]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/log
thirdparty/sqlalchemy/sqlalchemy.git
9 hours agoMerge "escape single quotes in postgresql nextval() identifier rendering" into main main
Federico Caselli [Wed, 22 Jul 2026 21:29:29 +0000 (21:29 +0000)] 
Merge "escape single quotes in postgresql nextval() identifier rendering" into main

9 hours agoFix typo that impeded correct rendering of subsequent sourcecode block (#13450)
Lele Gaifax [Wed, 22 Jul 2026 21:25:34 +0000 (23:25 +0200)] 
Fix typo that impeded correct rendering of subsequent sourcecode block (#13450)

10 hours agoescape single quotes in postgresql nextval() identifier rendering
Javid Khan [Tue, 21 Jul 2026 05:53:51 +0000 (01:53 -0400)] 
escape single quotes in postgresql nextval() identifier rendering

Fixed bug in the PostgreSQL dialect where a single quote in a sequence,
table, or schema name, such as one supplied via a ``schema_translate_map``
or an explicit :class:`.Sequence`, could result in a malformed
``nextval()`` statement. The quote is now properly escaped. Pull request
courtesy dxbjavid.

Fixes: #13429
Closes: #13430
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13430
Pull-request-sha: 0c19bcbd85c69b492542c43a693600595cbd0916

Change-Id: I6198d491a8ead7429fb5ac70e0502a6644f06810

40 hours agoMerge "Revert "Use identifier preparer for string type collations"" into main
Michael Bayer [Tue, 21 Jul 2026 14:05:43 +0000 (14:05 +0000)] 
Merge "Revert "Use identifier preparer for string type collations"" into main

41 hours agoRevert "Use identifier preparer for string type collations"
Michael Bayer [Tue, 21 Jul 2026 13:19:39 +0000 (13:19 +0000)] 
Revert "Use identifier preparer for string type collations"

This reverts commit 06fd857c553a9e9cc7b4f30d179ee7582655e7e7.

Reason for revert: this first looked like a small place we needed a workaround, but nothing is ever like that.    unfortunately changing it in this way implies that we aren't using `collation_schema` in other places as well, using the awkward quoted_name workaround, which then leads into more awkwardness as we want collation schemas to be reflected, too.  would we be creating hand-quoted quoted_names for reflection also?  obviously not.   I assume I didnt consider these aspects when i tried to do a "less intrusive" change.

I would like to do just one gerrit that adds collation_schema in all places we need it, plus full reflection, at once, rather than the drip-drip that was not making the scope of the problem clear.

Change-Id: I9b21d87f575625188e6c332889c38a4aa7fa787f

2 days agoMerge "Enable mypy ignore-without-code rule" into main
Michael Bayer [Mon, 20 Jul 2026 19:57:15 +0000 (19:57 +0000)] 
Merge "Enable mypy ignore-without-code rule" into main

2 days agoEnable mypy ignore-without-code rule
Mike Bayer [Mon, 20 Jul 2026 16:52:20 +0000 (12:52 -0400)] 
Enable mypy ignore-without-code rule

Enable the mypy ``ignore-without-code`` error code in ``pyproject.toml``
so that bare ``# type: ignore`` comments are rejected, and add the
specific error code reported by mypy to each of the 330 remaining bare
ignore comments across 73 modules in ``lib/sqlalchemy``.

Codes were derived by running mypy against current main and applying the
code it reported for each location (e.g. ``[assignment]``,
``[no-any-return]``, ``[union-attr]``), rather than carrying over codes
from an earlier branch, since the underlying types and the set of ignores
already present on main have diverged substantially.  71 lines that
became longer than 79 characters after adding the code were annotated with
``# noqa: E501``, matching the existing convention used elsewhere in the
codebase.

Change-Id: I5b32b5edc3de382b426b7b297adbf522a7998538

2 days agoMerge branch 'dependabot/github_actions/actions/setup-python-7'
Mike Bayer [Mon, 20 Jul 2026 17:02:22 +0000 (13:02 -0400)] 
Merge branch 'dependabot/github_actions/actions/setup-python-7'

Change-Id: Ic8fdd99266a036ee79f804b64101c469e8153c88

2 days agoMerge "Improve ORM loader strategy error messages to use user-friendly representation...
Michael Bayer [Mon, 20 Jul 2026 16:35:17 +0000 (16:35 +0000)] 
Merge "Improve ORM loader strategy error messages to use user-friendly representations" into main

2 days agoBump actions/setup-python from 6 to 7 13444/head
dependabot[bot] [Mon, 20 Jul 2026 15:12:42 +0000 (15:12 +0000)] 
Bump actions/setup-python from 6 to 7

Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6 to 7.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2 days agoImprove ORM loader strategy error messages to use user-friendly representations
Jan Vollmer [Wed, 15 Jul 2026 12:56:19 +0000 (08:56 -0400)] 
Improve ORM loader strategy error messages to use user-friendly representations

Improved error messages raised when ORM loader strategy options cannot be
applied to a query.  Messages now render the offending option in a
user-friendly form such as ``joinedload(User.orders)`` rather than exposing
internal class and path representations, and the "does not apply to root
entities" message now includes the option that triggered the error.  The
same user-friendly rendering is also applied to the "conflicting loader
strategy" message and to the ``of_type()`` representation in "does not
link" messages.  Originating pull request courtesy Jan Vollmer.

Co-authored-by: Mike Bayer <mike_mp@zzzcomputing.com>
Fixes: #12398
Closes: #12401
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/12401
Pull-request-sha: 4de2e161924d2d61ee7ad8402315da754e7995f4

Change-Id: I41c4f7fd077bd7fdb6e6ac9675370a37f7e7d7b4

3 days agoMerge "Fix ORM UPDATE..RETURNING cache adaptation with synchronize_session=fetch...
Michael Bayer [Sun, 19 Jul 2026 15:07:09 +0000 (15:07 +0000)] 
Merge "Fix ORM UPDATE..RETURNING cache adaptation with synchronize_session=fetch" into main

4 days agoFix ORM UPDATE..RETURNING cache adaptation with synchronize_session=fetch
Mike Bayer [Sat, 18 Jul 2026 15:59:14 +0000 (11:59 -0400)] 
Fix ORM UPDATE..RETURNING cache adaptation with synchronize_session=fetch

Fixed result-metadata corruption affecting ORM-enabled UPDATE statements
that use .returning() together with synchronize_session="fetch".  In this
configuration the RETURNING clause is rendered in mapper/table column order
rather than the user-requested .returning() order; on a compiled-cache hit,
the cursor result metadata was positionally adapted against the cached
statement's user-requested column order, causing column values to be
returned under the wrong keys (e.g. row[T.a] returning T.b's value).

The mis-adaptation was frequently masked by cached row-getter functions
produced by a prior, correctly-adapted execution, so the wrong values
surfaced most reliably under concurrent execution racing on the shared
compiled cache.  The fix disables result-set adapt_to_context for this
path, mirroring the ORM INSERT and ORM SELECT load paths, since the cached
keymap already carries the correct Column objects.

ORM DELETE statements are not affected: DELETE does not pass through
crud._get_crud_params() and therefore retains the user-requested RETURNING
order; a non-regression DELETE case is included in the test.

Fixes: #13439
Change-Id: If58e93a0bb3220dc5637bc7bcf346d2177529d6d

4 days agotest suite adjustments
Mike Bayer [Sat, 18 Jul 2026 18:50:16 +0000 (14:50 -0400)] 
test suite adjustments

* add skip for psycopg that's similar to asyncpg
* extend thread timeout on lambda concurrency test

Change-Id: Ie2ad3970c84339440dab3cae29029523fbef0c33

7 days agoUse coercion rules for aliased() against select/union constructs
Rens Groothuijsen [Thu, 16 Jul 2026 00:03:25 +0000 (20:03 -0400)] 
Use coercion rules for aliased() against select/union constructs

Calling :func:`_orm.aliased` against a :func:`_sql.select` or
:func:`_sql.union` / :class:`_sql.CompoundSelect` construct, which
previously failed with an obscure ``AttributeError`` regarding a missing
``.mapper`` attribute, now raises when using SQLAlchemy 2.1, and emits a
deprecation warning under SQLAlchemy 2.0 as it coerces the construct into a
subquery instead.  This matches the behavior of other similar implicit
SELECT-to-FROM coercions.  Pull request courtesy Rens Groothuijsen.

Fixes: #6274
Closes: #12433
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/12433
Pull-request-sha: 416dde8509ac05b209400603d9e00bc82aa47c79

Change-Id: I63bdec71074b81fb85bf29e6ca0dd81cbe3f8cb3

7 days agoMerge "PostgreSQL WITH options: proper bool/None rendering; support CreateView" into...
Michael Bayer [Wed, 15 Jul 2026 15:47:42 +0000 (15:47 +0000)] 
Merge "PostgreSQL WITH options: proper bool/None rendering; support CreateView" into main

7 days agoPostgreSQL WITH options: proper bool/None rendering; support CreateView
Mike Bayer [Mon, 13 Jul 2026 21:29:50 +0000 (17:29 -0400)] 
PostgreSQL WITH options: proper bool/None rendering; support CreateView

Added ``postgresql_with`` support to :class:`.CreateView` for specifying
PostgreSQL view options such as ``security_invoker``, ``security_barrier``,
and ``check_option``, rendered as a ``WITH (...)`` clause between the view
name and the ``AS`` keyword.

Additionally, the ``postgresql_with`` parameter accepted by
:class:`.Table` and :class:`.Index` now correctly renders Python boolean
values as ``true``/``false`` (lowercase), and ``None`` values as the
parameter name alone without an ``= value`` portion.

A shared ``_prepare_withclause_opts`` helper in ``PGDDLCompiler``
is used by all three constructs for consistent formatting.

Fixes: #11122
Fixes: #13432
Closes: #11296
pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/11296
pull-request-sha: e1f79a2f7bcf4a07da65040c8cfba0561d515ffc
Change-Id: I9c9b29e01b087215ca6caf1b8e0db5a5b0753b31

9 days agoUse identifier preparer for string type collations
cjc0013 [Sat, 11 Jul 2026 19:09:37 +0000 (15:09 -0400)] 
Use identifier preparer for string type collations

Adjusted string type collation rendering to use the dialect identifier
preparer rather than unconditional quoting.  This allows PostgreSQL
schema-qualified collation names to be passed using quoted_name with
quote=False.  Added a PostgreSQL dialect documentation section with
examples for schema-qualified collation usage.

Fixes: #9693
pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13418
pull-request-sha: 8d806f8dd185df42a04e363a1c2617fdfca030ad
Change-Id: Icc5b2c17cc46c7134c5e0a32f700a977b6d2dd8a

10 days agofix rst doc formatting
Mike Bayer [Sun, 12 Jul 2026 22:57:16 +0000 (18:57 -0400)] 
fix rst doc formatting

Change-Id: If839f4a15bb8b7e0bdd50281ac5559c88a728226

10 days agorewrite SQLite in-memory database docs for concurrency
Mike Bayer [Sun, 12 Jul 2026 22:11:21 +0000 (18:11 -0400)] 
rewrite SQLite in-memory database docs for concurrency

Rewrote the "Using a Memory Database in Multiple Threads" section
in the pysqlite dialect docs to lead with the fundamental constraint
that a :memory: database is scoped to a single connection, and is
not suitable for concurrent use without shared cache or full
serialization.

Added a new "Using a Shared-Cache Memory Database" subsection
recommending the file::memory:?cache=shared&uri=true URI approach,
which gives each checkout its own DBAPI connection with independent
transaction state while sharing one in-memory database.  Documented
process-global scoping and named databases for isolation.

Demoted the StaticPool approach to a secondary subsection with a
prominent warning about its single-connection limitation and silent
data loss under concurrent sessions.

Added a corresponding "Using a Memory Database with Multiple
Coroutines" section to the aiosqlite dialect docs, cross-referencing
the pysqlite shared-cache documentation.

References: #13428, #6987
Change-Id: Ic07c5a2a564e8eca19e596267f61051a2aaa0258

11 days agoMerge "fix catastrophic backtracking in sqlite inline unique reflection regex" into...
Michael Bayer [Sat, 11 Jul 2026 21:42:38 +0000 (21:42 +0000)] 
Merge "fix catastrophic backtracking in sqlite inline unique reflection regex" into main

11 days agoMerge "migration note on subqueries" into main
Michael Bayer [Sat, 11 Jul 2026 21:41:47 +0000 (21:41 +0000)] 
Merge "migration note on subqueries" into main

11 days agomigration note on subqueries
jonathan vanasco [Sat, 11 Jul 2026 17:16:58 +0000 (13:16 -0400)] 
migration note on subqueries

Under 2.0, calls to `in_` and `not_in` no longer accept an explicit `.subquery()`.

Passing a `.subquery()` will cause typing issues from MyPy AND will raise runtime warnings.

There was no note of this in the migration guide.  This may be an effect of another change that is disclosed in the migration guide.  If so, I suggest nesting this text (or improved text describing this) under that section for ease in discovery and migration.

Added a note to the 2.0 migration guide.

<!-- go over following points. check them with an `x` if they do apply, (they turn into clickable checkboxes once the PR is submitted, so no need to do everything at once)

-->

This pull request is:

- [x] A documentation / typographical / small typing error fix
- Good to go, no issue or tests are needed
- [ ] A short code fix
- please include the issue number, and create an issue if none exists, which
  must include a complete example of the issue.  one line code fixes without an
  issue and demonstration will not be accepted.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.   one line code fixes without tests will not be accepted.
- [ ] A new feature implementation
- please include the issue number, and create an issue if none exists, which must
  include a complete example of how the feature would look.
- Please include: `Fixes: #<issue number>` in the commit message
- please include tests.

**Have a nice day!**

Closes: #11107
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/11107
Pull-request-sha: f8669da225bc7687208d2389c6ae3bf3c63f6aaf

Change-Id: Id33779cb126a700d9adebe5f08f9d6c085589db4

11 days agoAllow overriding @validates for inheritance
Mike Bayer [Thu, 9 Jul 2026 20:44:16 +0000 (16:44 -0400)] 
Allow overriding @validates for inheritance

When a subclass overrides a :func:`_orm.validates` method using the
same method name as the parent class, only the subclass validator is
now invoked for instances of the subclass.  The subclass validator
may call ``super()`` to also invoke the parent class validator.
Previously, the parent validator was always used regardless of
whether the subclass provided an override.  Pull request courtesy
Indivar Mishra.

as an aside, also sets -j auto for the sphinx autobuild
utility in the makefile, seems to work.  I would assume this was
not working when I originally added this option.

Fixes: #2943
Closes: #10574
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/10574
Pull-request-sha: d310bef35b0ac3e5b840842b62807fc4008fd086

Change-Id: If0dab1ce5d93dbba4686d9cab36b81f6a79bfc1e

13 days agoUse _effective_decimal_return_scale in Numeric.result_processor
Kadir Can Ozden [Thu, 9 Jul 2026 15:43:58 +0000 (11:43 -0400)] 
Use _effective_decimal_return_scale in Numeric.result_processor

Fixed an issue in :class:`.Numeric` where the
:paramref:`.Numeric.decimal_return_scale` parameter was ignored when the
DBAPI does not support native decimal objects (i.e.
``dialect.supports_native_decimal`` is ``False``).  In this path the result
processor was computing the conversion scale from
:paramref:`.Numeric.scale` directly, bypassing
:paramref:`.Numeric.decimal_return_scale` entirely.  The behavior now
matches :class:`.Float`, which already used the correct
``_effective_decimal_return_scale`` property. Pull request courtesy Kadir
Can Ozden.

Fixes: #13424
Closes: #13137
Co-authored-by: Mike Bayer <mike_mp@zzzcomputing.com>
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13137
Pull-request-sha: 9d5dbc80a4d053b46454c87d56d36b51c672a2dc

Change-Id: Ib671aa9db19c64fe69d95a47a4b8420b96e918b9

2 weeks agoAllow inspection registrations from module reloads
w-Jessamine [Mon, 29 Jun 2026 10:30:16 +0000 (06:30 -0400)] 
Allow inspection registrations from module reloads

Allowed the inspection registry to replace an existing registration with a
reloaded callable from the same module and name. This avoids an assertion
failure for tooling that unloads and reloads SQLAlchemy modules while still
rejecting conflicting registrations. Pull request courtersy w-Jessamine.

Fixes: #10748
Closes: #13402
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13402
Pull-request-sha: e54815ef0092da05277efab79b90b77e44734cb9

Change-Id: If2565206d6b861993df8c361511551e204120b5e

2 weeks agoMerge "update oracledb async dialect for oracledb __aenter__()" into main
Michael Bayer [Thu, 9 Jul 2026 03:34:47 +0000 (03:34 +0000)] 
Merge "update oracledb async dialect for oracledb __aenter__()" into main

2 weeks agoupdate oracledb async dialect for oracledb __aenter__()
AVRC26 [Tue, 7 Jul 2026 19:01:23 +0000 (15:01 -0400)] 
update oracledb async dialect for oracledb __aenter__()

Updated the oracledb async dialect where the async cursor adapter invoked
``__enter__()`` rather than ``__aenter__()`` on the underlying cursor.
While these are equivalent in oracledb itself, the correct async form is
now used for correctness. As ``AsyncCursor.__aenter__()`` was added in
oracledb 2.0.1, the minimum supported oracledb version is now 2.0.1,
declared via the ``oracle-oracledb`` extra.  Pull request courtesy AVRC26.

Fixes: #13420
Closes: #13421
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13421
Pull-request-sha: 20582e2eaf1cdf9cd8af94ecf216f5d5d9fb3d62

Change-Id: I04f0e6cf3f753a1bfc664c4f10c290093526b4cb

2 weeks agofix catastrophic backtracking in sqlite inline unique reflection regex
Javid Khan [Wed, 8 Jul 2026 14:20:43 +0000 (10:20 -0400)] 
fix catastrophic backtracking in sqlite inline unique reflection regex

Fixes: #13419
### Description

While reflecting a SQLite table, `get_unique_constraints` scans the stored
`CREATE TABLE` text (taken verbatim from `sqlite_master.sql`) with an
`INLINE_UNIQUE_PATTERN` to spot inline `UNIQUE` columns. The tail of that
pattern is `[\t ]+[a-z0-9_ ]+?[\t ]+UNIQUE`, where the lazy middle class
itself contains a space, so all three quantifiers can lay claim to the same
space character. When a column definition contains a run of whitespace that
isn't followed by `UNIQUE`, the engine tries every way of splitting that run
across the three quantifiers, which is cubic in the length of the run.

SQLite keeps the original whitespace of a `CREATE TABLE` statement in
`sqlite_master`, so any account that can create a table can leave a long gap
in a column definition and make later reflection of that schema hang.
A small reproduction:

```python
from sqlalchemy import create_engine, inspect

e = create_engine("sqlite://")
with e.begin() as c:
    c.exec_driver_sql(
        "CREATE TABLE t (x INTEGER" + " " * 1000 + "NOT NULL, "
        "y INTEGER NOT NULL UNIQUE)"
    )
inspect(e).get_unique_constraints("t")   # ~11s before, instant after
```

The fix tokenises the inter-keyword whitespace with disjoint classes,
`[\t ]+[a-z0-9_]+(?:[\t ]+[a-z0-9_]+)*?[\t ]+UNIQUE`, so a space only ever
belongs to a separator and never to a token. Valid inline `UNIQUE` columns
reflect exactly as before; I have added a regression test that reflects a
table carrying a long whitespace run and runs in linear time on the new
pattern.

### Checklist

This pull request is:

- [x] A short code fix

Closes: #13398
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13398
Pull-request-sha: e398806f1243897f25c6ef0697200a49df464243

Change-Id: I7e394357162c9d3aad6c7a72d9276321d404ca64

2 weeks agoinclude rollback exception in closed transaction context manager error message
Ilan Keshet [Wed, 8 Jul 2026 21:49:35 +0000 (17:49 -0400)] 
include rollback exception in closed transaction context manager error message

Improved the error message raised when a Session is used inside a context
manager after the transaction has been rolled back due to an exception.
The InvalidRequestError now includes the original exception that triggered
the rollback, making it clearer why the transaction is no longer active.
Pull request courtesy Ilan Keshet.

Closes: #11297
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/11297
Pull-request-sha: 9feb9658078e1acfbeed29a119c9765cf684f677

Change-Id: If4ee3e9f673adfec533726b9b4d5c125dfcf2b9c

2 weeks agoupdate for mypy 2.2.0
Mike Bayer [Wed, 8 Jul 2026 22:57:13 +0000 (18:57 -0400)] 
update for mypy 2.2.0

Change-Id: I5478706dd47825bba38a87f81cd4e05e3e596a67

2 weeks agoMerge "few more perf improvements to selectinload" into main
Michael Bayer [Tue, 7 Jul 2026 19:56:49 +0000 (19:56 +0000)] 
Merge "few more perf improvements to selectinload" into main

2 weeks agoSQL codestyle: trim spacing around 'INHERITS' table list
James Addison [Sat, 4 Jul 2026 08:02:35 +0000 (04:02 -0400)] 
SQL codestyle: trim spacing around 'INHERITS' table list

### Description
This is _pedantic_ consistency with other comma-separated SQL lists - e.g. `VALUES`, `IN`, `DISTINCT ON` - and subqueries, where generally parantheses are not inner-padded by space characters.

The test cases updated illustrate the difference:

```diff
-            "CREATE TABLE atable (id INTEGER) INHERITS ( i1 )",
+            "CREATE TABLE atable (id INTEGER) INHERITS (i1)",
```

```diff
-            "CREATE TABLE atable (id INTEGER) INHERITS ( i1, i2 )",
+            "CREATE TABLE atable (id INTEGER) INHERITS (i1, i2)",

```

I noticed during source code diff review between [v2.0.50 and v2.0.51](https://github.com/sqlalchemy/sqlalchemy/compare/rel_2_0_50...rel_2_0_51) that spaces are added on each side within the parentheses containing the inherited table list.

If it's intentional to draw attention to the fact that these are tables and not column names -- then my apologies, that would seem sorta reasonable.

The parsing/interpretation of these spaces seems unlikely to be the change that microscopically moves the performance needle enough to offset the climate crisis -- indeed the overhead of reading this and responding may be larger -- this is purely me being pedantic.

### Checklist

This pull request is:

- [x] A documentation / typographical / small typing error fix
- Good to go, no issue or tests are needed

**Have a nice day!**
(you too; plus weekend)

Closes: #13397
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13397
Pull-request-sha: 1324c758b81eb80fff70e706a8171d24b885d1a2

Change-Id: I23640361f6539daaee1260840b9fbe6d0a4ca05a

3 weeks agofew more perf improvements to selectinload
Federico Caselli [Tue, 30 Jun 2026 19:56:23 +0000 (21:56 +0200)] 
few more perf improvements to selectinload

avout named tuple attribute access in a loop, remove unneded sort
follow up of I2e772c7ee9fa9e1b50026cab8c7997b861f1acda

Change-Id: I58b691e25e7e34452d7754a8325e13373a87632b

3 weeks agoset PYTHONUTF8=1 for attestation step to fix encoding on Windows
Mike Bayer [Sat, 27 Jun 2026 20:20:17 +0000 (16:20 -0400)] 
set PYTHONUTF8=1 for attestation step to fix encoding on Windows

pypi_attestations sign writes attestation JSON files using the Windows
default encoding (CP1252) rather than UTF-8, causing twine to fail with
a UnicodeDecodeError when reading them back. PYTHONUTF8=1 forces UTF-8
for all file I/O on Windows.

Change-Id: I0eb7c4fae80eee52a81ed7106c1af699ebf79e21

3 weeks agocontinue-on-error for upload-release-assets to handle already_exists on re-runs
Mike Bayer [Sat, 27 Jun 2026 19:59:35 +0000 (15:59 -0400)] 
continue-on-error for upload-release-assets to handle already_exists on re-runs

When re-running the wheel build, wheels already uploaded to the GitHub release
cause upload-release-assets to fail with already_exists. With continue-on-error,
the attestation and PyPI upload steps still proceed since the wheel files remain
in ./wheelhouse/ regardless.

Change-Id: Id2ba96e95dd93b3ba14e9bf117a5d1a057178f37

3 weeks agouse python -m pip/twine/pypi_attestations to avoid PATH issues on macOS
Mike Bayer [Sat, 27 Jun 2026 19:50:49 +0000 (15:50 -0400)] 
use python -m pip/twine/pypi_attestations to avoid PATH issues on macOS

On macOS after cibuildwheel runs, bare pip/twine may not be on PATH.
Using python -m ensures the correct interpreter's tools are used.

Change-Id: I658267a4f51343d69cdd930744a4086685b735bf

3 weeks agoadd shell: bash to attestations step to fix glob expansion on Windows
Mike Bayer [Sat, 27 Jun 2026 19:50:02 +0000 (15:50 -0400)] 
add shell: bash to attestations step to fix glob expansion on Windows

PowerShell does not expand ./wheelhouse/* globs, causing pypi_attestations
sign to receive a literal asterisk and fail. Explicit bash shell ensures
glob expansion works on all platforms.

Change-Id: I98a2785e5e5ac3cd54db361f990fba32fa819ca5

3 weeks agofall back to twine upload without attestations if attestation signing fails
Mike Bayer [Sat, 27 Jun 2026 19:46:41 +0000 (15:46 -0400)] 
fall back to twine upload without attestations if attestation signing fails

On some platforms (e.g. windows-11-arm) pypi-attestations cannot install
due to missing cryptography binary wheels. Use continue-on-error on the
attestation step and conditionally pass --attestations to twine only when
signing succeeded.

Change-Id: Ibc9b5091c0db361f24376a887d6db04b0e32503c

3 weeks agofix create-wheels.yaml for cibuildwheel 4.x and release asset upload
Mike Bayer [Sat, 27 Jun 2026 19:17:29 +0000 (15:17 -0400)] 
fix create-wheels.yaml for cibuildwheel 4.x and release asset upload

Remove CIBW_ENABLE cpython-freethreading which is no longer a valid enable
group in cibuildwheel 4.x; free-threaded builds are now included by default
when specifying cp314t-* in CIBW_BUILD.

Change contents permission from read to write so that the upload-release-assets
step can attach wheels to the GitHub release.

Change-Id: I96c6755db1aba38e4eaeebdd2b7b3738a305226c

3 weeks agoVersion 2.1.0b4 placeholder
Mike Bayer [Sat, 27 Jun 2026 18:52:49 +0000 (14:52 -0400)] 
Version 2.1.0b4 placeholder

3 weeks ago- 2.1.0b3 rel_2_1_0b3
Mike Bayer [Sat, 27 Jun 2026 17:46:45 +0000 (13:46 -0400)] 
- 2.1.0b3

3 weeks agofix
Mike Bayer [Sat, 27 Jun 2026 17:03:21 +0000 (13:03 -0400)] 
fix

Change-Id: If46d73e1296c322e94f20083346bce32c0aad636

3 weeks agofixes for m2momitjointest
Mike Bayer [Sat, 27 Jun 2026 16:15:59 +0000 (12:15 -0400)] 
fixes for m2momitjointest

in 808fd28297f36bf932443bae77ca5bb16bcbd4dd , the new test suite
created per-column `ForeignKey` constructs instead of composite
ForeignKeyConstraint objects, leading to failures on all backends
other than SQLite.  The test now runs with backend, and also does not
need AssertsCompiledSQL directives.

Change-Id: Ia52172e22a3f8c37e63f60ce0d2d6b4708a2459b

3 weeks agomore changelog updates
Mike Bayer [Sat, 27 Jun 2026 16:06:18 +0000 (12:06 -0400)] 
more changelog updates

Change-Id: I182aba53fd92baaa132665b6ea49d882acd3b190

3 weeks agorework migration docs a bit, fix issues
Mike Bayer [Sat, 27 Jun 2026 15:11:49 +0000 (11:11 -0400)] 
rework migration docs a bit, fix issues

Change-Id: I0ef6e304e32ee8add3ebc2e325cc7d13e39e38aa

3 weeks agowrap before/after_cursor_execute event hooks in error handling
Mike Bayer [Fri, 26 Jun 2026 14:09:38 +0000 (10:09 -0400)] 
wrap before/after_cursor_execute event hooks in error handling

Expanded try/except error handling in _exec_single_context(),
_exec_insertmany_context(), and _cursor_execute() to encompass the
before_cursor_execute and after_cursor_execute event hooks. This
ensures that exceptions raised within these hooks, including
BaseException subclasses such as asyncio.CancelledError, are
properly handled via _handle_dbapi_exception(), providing correct
connection invalidation and pool notification.

Also added a guard in _handle_dbapi_exception to avoid
double-wrapping exceptions that are already StatementError
instances, which could occur when _cursor_execute's error handling
propagates up through _execute_context.

As part of this change, DBAPI errors raised from within these event
hooks will now be wrapped as SQLAlchemy exceptions.

Fixes: #13381
Change-Id: I6df29406f1eed9c318d02b00b999408c1e83535d

4 weeks agooverride get_select_precolumns() in StrSQLCompiler
Mike Bayer [Wed, 24 Jun 2026 12:49:30 +0000 (08:49 -0400)] 
override get_select_precolumns() in StrSQLCompiler

Fixed issue where :meth:`_sql.Select.get_final_froms` would emit a
deprecation warning when the statement made use of the PostgreSQL-specific
expression argument to :meth:`_sql.Select.distinct`; the same spurious
warning would be emitted when stringifying such a statement without
explicitly using a PostgreSQL dialect.  The fix ensures that this 1.4-era
warning is suppressed under both 2.0 and 2.1.

Note that under SQLAlchemy 2.1, passing an expression to
:meth:`_sql.Select.distinct` is deprecated overall, and is replaced by a
new PostgreSQL-specific construct (see :ticket:`12342`).

Fixes: #13396
Change-Id: I587e24aa7016c56b1d5bfe1048c4b6eb809dfb30

4 weeks agoMerge "fix catastrophic backtracking in mysql index comment reflection regex" into...
Michael Bayer [Tue, 23 Jun 2026 21:21:29 +0000 (21:21 +0000)] 
Merge "fix catastrophic backtracking in mysql index comment reflection regex" into main

4 weeks agoMerge "fixes for logging tests" into main
Michael Bayer [Tue, 23 Jun 2026 20:06:02 +0000 (20:06 +0000)] 
Merge "fixes for logging tests" into main

4 weeks agofix catastrophic backtracking in mysql index comment reflection regex
dxbjavid [Mon, 22 Jun 2026 15:30:40 +0000 (11:30 -0400)] 
fix catastrophic backtracking in mysql index comment reflection regex

Improved the regular expression used to parse index COMMENT clauses
in MySQL SHOW CREATE TABLE reflection to use an unambiguous
single-quoted-string pattern; the previous pattern was theoretically
subject to backtracking on malformed input, though such input is not
producible by MySQL itself.  Fix courtesy of Javid Khan.

Fixes: #13393
Closes: #13394
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13394
Pull-request-sha: 52239d122e937fd6b266ac49fb024063c82c9372

Change-Id: I9174705dd8e1539d8ed7c384b13280bf543d7341

4 weeks agoMerge "quote driver name and pass-through keys in pyodbc connect string" into main
Michael Bayer [Tue, 23 Jun 2026 18:11:13 +0000 (18:11 +0000)] 
Merge "quote driver name and pass-through keys in pyodbc connect string" into main

4 weeks agoMerge "Add explicit USING support to DELETE" into main
Michael Bayer [Tue, 23 Jun 2026 18:11:01 +0000 (18:11 +0000)] 
Merge "Add explicit USING support to DELETE" into main

4 weeks agofixes for logging tests
Mike Bayer [Tue, 23 Jun 2026 17:53:21 +0000 (13:53 -0400)] 
fixes for logging tests

Repair some things that went wrong in 0dcfa5e9ea49e481a7a35130f654cbdd3a8c1405
re #13363

* add "logging.handlers" import
* ensure DB connects before capturing log messages so we skip
  initial connect overhead

Change-Id: I10f3ac06b982633d617ec2d9c2a57371038b5a54

4 weeks agoAdd explicit USING support to DELETE
cjc0013 [Thu, 11 Jun 2026 21:23:04 +0000 (17:23 -0400)] 
Add explicit USING support to DELETE

Added :meth:`_sql.Delete.using`, allowing explicit FROM expressions such as
joins to be rendered in backend-specific multiple-table DELETE forms
including MySQL/MariaDB ``DELETE .. USING``.  Pull request courtesy
cjc0013.

Fixes: #8130
Closes: #13334
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13334
Pull-request-sha: df5644e96158a2424c85773d335bab6cc0c8c038

Change-Id: I9cadfc7ebb1c8b4f6a7433de3fbddbad205f545d

4 weeks agouse @classmethod per pytest guidance
Mike Bayer [Mon, 22 Jun 2026 15:36:02 +0000 (11:36 -0400)] 
use @classmethod per pytest guidance

Fixed class-scoped pytest fixtures that were defined as instance methods
using ``self``, which is deprecated as of pytest 9.1 and will be removed in
pytest 10. Fixtures are now decorated with a compatibility ``@classmethod``
decorator and use ``cls`` as the first parameter.

Fixes: #13392
Change-Id: I866de54e22569c9d55eb97dce165670994ec4a57

4 weeks agoquote driver name and pass-through keys in pyodbc connect string
dxbjavid [Wed, 17 Jun 2026 12:49:06 +0000 (08:49 -0400)] 
quote driver name and pass-through keys in pyodbc connect string

Tightened the construction of the ODBC connection string in the pyodbc
connector (as well as the mssql-python connector in 2.1) so that the
driver name, the names of pass-through connection parameters, and values
containing ``}`` are brace-quoted.  Previously a ``}`` in the driver name
or in a pass-through value, or a ``;`` in the name of a pass-through
parameter, could close the surrounding token early and allow the
remainder of the string to be interpreted as additional connection
attributes.  Pull request courtesy dxbjavid.

Fixes: #13380
Closes: #13379
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13379
Pull-request-sha: 34433408bff86a9044be5d431b31688ab6d7578d

Change-Id: I5a0b522e62d306cf6dc59c7f61fe584df02a948d

4 weeks agoMerge branch 'dependabot/github_actions/actions/checkout-7'
Mike Bayer [Thu, 18 Jun 2026 18:12:36 +0000 (14:12 -0400)] 
Merge branch 'dependabot/github_actions/actions/checkout-7'

Change-Id: I46dff7c91fd6abef23ef8c76a5ee072176618b99

4 weeks agoMerge "Improve performance of selectinload result handling by up to ~30%" into main
Michael Bayer [Thu, 18 Jun 2026 17:25:40 +0000 (17:25 +0000)] 
Merge "Improve performance of selectinload result handling by up to ~30%" into main

4 weeks agoBump actions/checkout from 6 to 7 13387/head
dependabot[bot] [Thu, 18 Jun 2026 15:12:33 +0000 (15:12 +0000)] 
Bump actions/checkout from 6 to 7

Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
5 weeks agoFix is_pep695 misidentifying Annotated[TypeAliasType] as PEP 695
Mike Bayer [Wed, 17 Jun 2026 22:06:56 +0000 (18:06 -0400)] 
Fix is_pep695 misidentifying Annotated[TypeAliasType] as PEP 695

The is_pep695() function incorrectly identified
Annotated[TypeAliasType, ...] as a PEP 695 type alias because
Annotated's __origin__ attribute returns the first type argument
(the TypeAliasType) rather than Annotated itself.  This caused
_init_column_for_annotation to crash with AttributeError when
attempting to access __value__ on the Annotated wrapper.

Added a check for is_pep593() before recursing through __origin__
in is_pep695(), so Annotated types are correctly excluded.

Fixes: #13386
Change-Id: I36ef83ebbab5abc08bed0131efb552c3fc001911

5 weeks agoImprove performance of selectinload result handling by up to ~30%
Oliver Parker [Wed, 17 Jun 2026 15:15:18 +0000 (11:15 -0400)] 
Improve performance of selectinload result handling by up to ~30%

* in selectinloader, dont use Bundle() to represent the PK portion
* use more efficient mapper._state_ident_getter() method in selectinloader
  which pre-resolves keys and only calls upon _get_state_attr_by_column when
  an attribute is not locally present
* removed use of groupby() + lambda against Row objects in subqueryloader; converts
  to tuple and builds lists via append()

Adds tests pinning behavior of the rewritten result handling: the uselist=False multiple-rows warning, and many-to-one loads where the foreign key value matches no row or is NULL.

Benchmarked on an in-memory SQLite database (median of 30 runs, ms):

case | baseline | branch | Δ
-- | -- | -- | --
selectin_m2m | 9.747 | 6.958 | -28.6%
selectin_m2o | 13.761 | 12.538 | -8.9%
selectin_nested | 14.670 | 11.473 | -21.8%
selectin_o2m | 14.686 | 11.823 | -19.5%
selectin_o2m_few_big | 25.771 | 19.787 | -23.2%
subquery_o2m | 15.946 | 15.736 | -1.3%

Fixes: #13363
Closes: #13364
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13364
Pull-request-sha: 3b858fc54bb28f7c44101be5b7fdc6c02dda6c66

Change-Id: I2e772c7ee9fa9e1b50026cab8c7997b861f1acda

5 weeks agoMerge branch 'dependabot/github_actions/pypa/cibuildwheel-4.1.0'
Mike Bayer [Mon, 15 Jun 2026 20:29:26 +0000 (16:29 -0400)] 
Merge branch 'dependabot/github_actions/pypa/cibuildwheel-4.1.0'

Change-Id: I263869dff37838f9e34e4b6c6641c26aec714374

5 weeks agoMerge "Fixes: 13363 Process ORM result rows as plain tuples without Row construction...
Michael Bayer [Mon, 15 Jun 2026 20:28:20 +0000 (20:28 +0000)] 
Merge "Fixes: 13363 Process ORM result rows as plain tuples without Row construction" into main

5 weeks agoFixes: 13363 Process ORM result rows as plain tuples without Row construction
Oliver Parker [Mon, 15 Jun 2026 14:41:06 +0000 (10:41 -0400)] 
Fixes: 13363 Process ORM result rows as plain tuples without Row construction
ORM result row fetching now processes rows as plain tuples rather than
constructing :class:`.Row` objects, as ORM loaders use position-based
access and do not require the :class:`.Row` interface. :class:`.Row`
construction is still used when engine-level debug logging is enabled so
that individual rows can be logged. Benchmarks show a 3-16% improvement in
ORM entity load times depending on query shape.  Pull request courtesy
Oliver Parker.

Adds Result._all_interim_rows(), which returns the remaining rows as processed plain tuples, applying result processors and tuple filters but skipping Row object construction.  ORM loading uses this for its row fetch; its row getters are position-based itemgetters that accept any tuple-like row.  Results that require row logging or have scalar sources fall back to Row construction.

Adds tests covering the new behavior: rows are plain tuples with result processors applied, and Row construction still occurs when engine-level row logging is enabled, at both the Result and ORM loading level.

Benchmarked on an in-memory SQLite database with this change alone (median of 30 runs, ms); this path is used by all ORM entity loads:

    plain_small (500 rows x 5 cols)    2.43 ->  2.28    -6%
    plain_wide (2000 rows x 25 cols)   8.17 ->  7.24   -11%
    joined_o2m (500 x 10)             18.56 -> 16.95    -9%
    selectin_o2m (500 x 10)           18.45 -> 17.79    -4%
    selectin_nested (50 x 10 x 10)    18.67 -> 17.33    -7%
    selectin_m2m (500 x 10)           12.70 -> 11.53    -9%
    selectin_m2o (5000 -> 200)        15.83 -> 15.29    -3%
    selectin_o2m_few_big (20 x 500)   32.96 -> 31.29    -5%
    subquery_o2m (500 x 10)           21.51 -> 18.16   -16%

Fixes: #13363
Closes: #13365
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13365
Pull-request-sha: 46f4125ead7e37b780160ae70e03ec204ecb9617

Change-Id: Ia91a89c8cac78d4790391bc5b171b76d4aaca71b

5 weeks agocherry-pick changelog update for 2.0.52
Mike Bayer [Mon, 15 Jun 2026 15:41:38 +0000 (11:41 -0400)] 
cherry-pick changelog update for 2.0.52

5 weeks agocherry-pick changelog from 2.0.51
Mike Bayer [Mon, 15 Jun 2026 15:41:37 +0000 (11:41 -0400)] 
cherry-pick changelog from 2.0.51

5 weeks agoBump pypa/cibuildwheel from 4.0.0 to 4.1.0 13373/head
dependabot[bot] [Mon, 15 Jun 2026 15:21:14 +0000 (15:21 +0000)] 
Bump pypa/cibuildwheel from 4.0.0 to 4.1.0

Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 4.0.0 to 4.1.0.
- [Release notes](https://github.com/pypa/cibuildwheel/releases)
- [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md)
- [Commits](https://github.com/pypa/cibuildwheel/compare/v4.0.0...v4.1.0)

---
updated-dependencies:
- dependency-name: pypa/cibuildwheel
  dependency-version: 4.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
5 weeks agofix backtracking hang in hstore literal parser
dxbjavid [Fri, 12 Jun 2026 11:19:04 +0000 (07:19 -0400)] 
fix backtracking hang in hstore literal parser

Fixed regular expression in the pure Python hstore result processor,
used when ``use_native_hstore=False`` is set, which could hang on
malformed hstore text containing unterminated quoted segments with
backslashes.  Pull request courtesy dxbjavid.

Fixes: #13370
Closes: #13371
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13371
Pull-request-sha: f5eddae11c435c78f326b70a15357cbaf6d09337

Change-Id: I0d2d7565dc88f56a73b41e2ad20ca1c5a6f738bb

5 weeks agoadd row logging tests
Mike Bayer [Fri, 12 Jun 2026 17:33:05 +0000 (13:33 -0400)] 
add row logging tests

ensure all the main result methods as well as the ORM-used
_raw_all_rows() perform equivalent row logging.

Change-Id: Iee0dc3c75a9c71f6d1a73fa058c5edf0b16348ec

5 weeks agobump mssql-python to 1.9.0
Mike Bayer [Fri, 12 Jun 2026 18:13:50 +0000 (14:13 -0400)] 
bump mssql-python to 1.9.0

1.9.0 seems to fix the picklable statement exception fail,
so fix for that test and pin to lower version

Change-Id: Ic561b1a6b688f38b9f5189508d9203bca47fef79

5 weeks agoMerge "factor single-table reflection wrappers into common mixin" into main
Michael Bayer [Fri, 12 Jun 2026 16:12:57 +0000 (16:12 +0000)] 
Merge "factor single-table reflection wrappers into common mixin" into main

5 weeks agochore: improve sqlalchemy maintenance path (#13351)
lphuc2250gma [Thu, 11 Jun 2026 21:19:57 +0000 (17:19 -0400)] 
chore: improve sqlalchemy maintenance path (#13351)

Co-authored-by: Noa Levi <275430404+lphuc2250gma@users.noreply.github.com>
5 weeks agoDocument quoted_name use for PostgreSQL INHERITS (#13342)
CaoRongkai [Thu, 11 Jun 2026 21:19:16 +0000 (05:19 +0800)] 
Document quoted_name use for PostgreSQL INHERITS (#13342)

5 weeks agoBump pypa/cibuildwheel from 3.4.1 to 4.0.0 (#13358)
dependabot[bot] [Thu, 11 Jun 2026 20:57:54 +0000 (22:57 +0200)] 
Bump pypa/cibuildwheel from 3.4.1 to 4.0.0 (#13358)

Bumps [pypa/cibuildwheel](https://github.com/pypa/cibuildwheel) from 3.4.1 to 4.0.0.
- [Release notes](https://github.com/pypa/cibuildwheel/releases)
- [Changelog](https://github.com/pypa/cibuildwheel/blob/main/docs/changelog.md)
- [Commits](https://github.com/pypa/cibuildwheel/compare/v3.4.1...v4.0.0)

---
updated-dependencies:
- dependency-name: pypa/cibuildwheel
  dependency-version: 4.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
6 weeks agofactor single-table reflection wrappers into common mixin
Mike Bayer [Fri, 5 Jun 2026 20:02:02 +0000 (16:02 -0400)] 
factor single-table reflection wrappers into common mixin

Introduced _BackendsMultiReflection mixin in engine/default.py
that provides the get_columns(), get_pk_constraint(),
get_foreign_keys(), get_indexes(), get_unique_constraints(),
get_check_constraints(), get_table_comment(), and
get_table_options() single-table methods, each delegating to
the corresponding get_multi_* method with
filter_names=[table_name].

PostgreSQL, Oracle, and MSSQL dialects now inherit from this
mixin instead of duplicating the wrapper pattern.  Oracle
retains its _value_or_raise() override which applies
normalize_name() for case-folding.  MSSQL overrides
get_unique_constraints(), get_check_constraints(), and
get_table_options() with NotImplementedError since it has no
native get_multi_* for those yet.

Change-Id: If68bbf94b3956348fc7ae8179ff093d63dcdfbe2

6 weeks agoMerge "allow rollback within _prepare_impl on twophase prepare failure" into main
Michael Bayer [Wed, 10 Jun 2026 13:08:43 +0000 (13:08 +0000)] 
Merge "allow rollback within _prepare_impl on twophase prepare failure" into main

6 weeks agoMerge "repair xid in psycopg" into main
Michael Bayer [Wed, 10 Jun 2026 13:08:10 +0000 (13:08 +0000)] 
Merge "repair xid in psycopg" into main

6 weeks agoallow rollback within _prepare_impl on twophase prepare failure
Mike Bayer [Tue, 9 Jun 2026 18:47:46 +0000 (14:47 -0400)] 
allow rollback within _prepare_impl on twophase prepare failure

When tpc_prepare() raised during SessionTransaction._prepare_impl(),
the error handler's call to self.rollback() was blocked by the
@declare_states decorator, which had set _next_state to
CHANGE_IN_PROGRESS. This caused IllegalStateChangeError to be raised
instead of the original database exception, masking the real error
and preventing proper cleanup.

Used _expect_state(SessionTransactionState.CLOSED) to temporarily
allow the rollback state transition, matching the existing pattern
used in commit() for the close() call.

Fixes: #13356
Change-Id: Ie8212d5b6f8515340cf9d83c56dcbfa5a7415812

6 weeks agoMerge "send execution options to connection also" into main
Michael Bayer [Tue, 9 Jun 2026 18:34:29 +0000 (18:34 +0000)] 
Merge "send execution options to connection also" into main

6 weeks agoMerge "remove legacy include_columns in index reflection" into main
Michael Bayer [Tue, 9 Jun 2026 14:23:36 +0000 (14:23 +0000)] 
Merge "remove legacy include_columns in index reflection" into main

6 weeks agorepair xid in psycopg
Federico Caselli [Fri, 5 Jun 2026 19:51:13 +0000 (21:51 +0200)] 
repair xid in psycopg

Repaired bug introduced in :ticket:`13229` where a two-phase
transaction recovery would not return the correct transaction
identifier when generating the identifiers using the ``xid()``
method of the psycopg connection.

Fixes: #13355
Change-Id: Iffe68c1701afaa678fa7b598559dd396d3f8db41

6 weeks agouse trusted publishing for PyPI wheel uploads
Mike Bayer [Fri, 5 Jun 2026 16:35:35 +0000 (12:35 -0400)] 
use trusted publishing for PyPI wheel uploads

Replace token-based PyPI authentication with OIDC trusted publishing.
Add workflow-level id-token: write permission, generate PEP 740
attestations using pypi-attestations, and upload with
twine --attestations.  Removes the pypi_token secret dependency.

Closes: #13324
Change-Id: I75d8eab7ade7be61ed86d773ea2403cd484c81dd

6 weeks agoMerge "minor code improvement to the mssql multi reflection" into main
Michael Bayer [Fri, 5 Jun 2026 14:25:26 +0000 (14:25 +0000)] 
Merge "minor code improvement to the mssql multi reflection" into main

6 weeks agoMerge "Register func.any(), func.all(), func.some() as collection aggregates" into...
Michael Bayer [Fri, 5 Jun 2026 14:08:03 +0000 (14:08 +0000)] 
Merge "Register func.any(), func.all(), func.some() as collection aggregates" into main

6 weeks agominor code improvement to the mssql multi reflection
Federico Caselli [Thu, 4 Jun 2026 22:47:52 +0000 (00:47 +0200)] 
minor code improvement to the mssql multi reflection

improve caching and remove redundant flag

Change-Id: I46ee752c908227667a281bd4d436fac2b43b0d8e

6 weeks agoremove legacy include_columns in index reflection
Federico Caselli [Thu, 4 Jun 2026 21:23:46 +0000 (23:23 +0200)] 
remove legacy include_columns in index reflection

Removed the legacy ``include_columns`` key from the dictionary returned
by the index reflection methods of some dialects.
This information is now part of the ``dialect_options`` dictionary under the key
``{dialect_name}_include``, such as ``postgresql_include`` or ``mssql_include``.

Fixes: #13350
Change-Id: I9535690350d97e19477f7e9919dc4994b876af47

6 weeks agofix docs lint warning
Federico Caselli [Thu, 4 Jun 2026 21:26:13 +0000 (23:26 +0200)] 
fix docs lint warning

Change-Id: I6c8e38dc663bc0b53ab1259daab50617583ccdbb

6 weeks agoMerge "Implement native multi-table reflection API for the mssql dialect" into main
Federico Caselli [Thu, 4 Jun 2026 21:25:40 +0000 (21:25 +0000)] 
Merge "Implement native multi-table reflection API for the mssql dialect" into main

6 weeks agoImplement native multi-table reflection API for the mssql dialect
Gaurav Sharma [Wed, 3 Jun 2026 12:52:09 +0000 (08:52 -0400)] 
Implement native multi-table reflection API for the mssql dialect

### Description

Adds 5 native `get_multi_*` reflection methods (columns, pk, fk, indexes, table_comment) for the MSSQL dialect, replacing the per-table loop in `_default_multi_reflect`. Single-table methods now delegate to the multi versions (PG/Oracle pattern); legacy per-table SQL is retained as `_internal_get_*` helpers, used only for tempdb reflection.

Not implemented here: `get_multi_unique_constraints`, `get_multi_check_constraints`, `get_multi_table_options` -MSSQL has no single-table counterparts to delegate from. Happy to add as a follow-up.

### Performance

Measured with `test/perf/many_table_reflection.py` against SQL Server 2022 (Docker, localhost, pyodbc + ODBC Driver 18) on a 250-table fixture, 15-50 cols, with PKs/FKs/indexes/comments:

| | single | multi | speedup |
|---|---|---|---|
| `get_columns` | 1.33s | 0.35s | 3.8x |
| `get_pk_constraint` | 1.41s | 0.08s | 18x |
| `get_foreign_keys` | 7.07s | 0.19s | 37x |
| `get_indexes` | 0.80s | 0.09s | 8.6x |
| `get_table_comment` | 0.71s | 0.05s | 14x |
| **MetaData.reflect** | **12.62s** | **1.15s** | **11x** |

### Checklist

This pull request is:

- [x] A new feature implementation
- Fixes: #8430
- Tests added in `test/dialect/mssql/test_reflection.py`
- Changelog entry: `doc/build/changelog/unreleased_21/8430.rst`

Closes: #13297
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13297
Pull-request-sha: 2c6c69f159225f85312e39d99222279ef8cbadd1

Change-Id: I525c60fc5ece94dd250f376b05b64b09e65ca0d7

6 weeks agoRemoved erroneous debug print (#13349)
Bradley Davis [Thu, 4 Jun 2026 19:51:32 +0000 (12:51 -0700)] 
Removed erroneous debug print (#13349)

6 weeks agoMerge "Perf/conditional unique selectinload" into main
Federico Caselli [Thu, 4 Jun 2026 19:50:15 +0000 (19:50 +0000)] 
Merge "Perf/conditional unique selectinload" into main

6 weeks agoimprove typed column migration docs
Federico Caselli [Thu, 4 Jun 2026 19:33:19 +0000 (21:33 +0200)] 
improve typed column migration docs

Change-Id: I402580004d1c0d8583ebc9e2852f38d687ba6ae8

6 weeks agosend execution options to connection also
Mike Bayer [Wed, 3 Jun 2026 13:46:19 +0000 (09:46 -0400)] 
send execution options to connection also

Session level :paramref:`_orm.Session.execution_options` now take
effect for Core level SQL emitted by unit of work operations, in
addition to their existing use within ORM statement executions.
This is to provide for Core options such as
:paramref:`_engine.Connection.execution_options.schema_translate_map`
to be applicable to a :class:`.Session` overall.

Fixes: #13346
Change-Id: Icb453b7925f1bc38f30538d7726d222842bc65bd

6 weeks agoRegister func.any(), func.all(), func.some() as collection aggregates
Mike Bayer [Thu, 4 Jun 2026 14:17:06 +0000 (10:17 -0400)] 
Register func.any(), func.all(), func.some() as collection aggregates

Added CollectionAggregateFunction base class that sets
_is_collection_aggregate = True, and registered any_, all_, some_
as subclasses so that func.any(), func.all(), and func.some() correctly
prevent operator flipping on negation. Previously ~(col == func.any(arr))
would incorrectly compile to col != any(arr) instead of
NOT (col = any(arr)), which has different semantics for collection
aggregate comparison modifiers.

Also extended the _construct_for_op guard to check both left and right
operands for _is_collection_aggregate, since func.any(arr) can appear
on either side of a comparison unlike the standalone any_() construct
which auto-reverses operands.

Fixes: #13343
Change-Id: Id4774938876dc7f1f38cf143dccfe3c8ddba464d

7 weeks agoPerf/conditional unique selectinload
Oliver Parker [Wed, 3 Jun 2026 06:51:13 +0000 (02:51 -0400)] 
Perf/conditional unique selectinload

Optimized :func:`_orm.selectinload` to skip the ``.unique()`` call on inner
result sets when no nested :func:`_orm.joinedload` on a collection is
present.  The uniquing pass is only required when a joined eager load
inflates rows due to a one-to-many or many-to-many JOIN; in the common case
of a leaf selectin load, rows are already unique by construction and the
per-row hashing overhead can be avoided. As a side effect, ``yield_per``
set in a ``do_orm_execute`` event for a :func:`_orm.selectinload`
relationship load no longer raises ``InvalidRequestError`` when no nested
collection joinedload is in effect, since ``.unique()`` is no longer called
in that path. Pull request courtesy Oliver Parker.

`_SelectInLoader._load_via_parent` and `_load_via_child` currently call
`.unique()` unconditionally on the inner `Result`. The uniqueness pass is only
required when a nested `joinedload` on a collection is in effect — in that case
the `JOIN` inflates rows (one row per `(child, grandchild)` instead of one per
child) and the outer `groupby` would produce duplicated entries without dedup.

`loading.instances()` already signals exactly this condition: it sets
`Result._unique_filter_state` to a `require_unique` guard when the inner
compile state has `multi_row_eager_loaders=True`. When that flag is unset (no
nested collection `joinedload`), `_unique_filter_state` stays `None`, meaning
the inner query produces unique rows by construction:

- `omit_join` 1:N — one row per child
- `omit_join` M2O — one row per parent
- `omit_join` M2M — one row per (parent, entity)
- `load_with_join` (non-omit) — one row per (parent, child)

This PR makes the `.unique()` call conditional, via a new `_has_unique_filter`
property on `Result` that exposes this state without reaching into the private
`_unique_filter_state` attribute directly:

```python
if result._has_unique_filter:
    result = result.unique()
```

Per-row hashing in `_iterator_getter` is avoided in the common leaf-load case.
On an in-memory SQLite bench (2000 parents × 5 children + M:N tags, Python
3.14, n=1000 iterations):

| Workload | before avg | after avg | delta | before sd | after sd |
|---|---|---|---|---|---|
| selectin children (1:N) | 56.0 ms | 41.4 ms | **−26%** | 5.2 ms | 1.9 ms |
| selectin tags M2M | 25.6 ms | 20.0 ms | **−22%** | 4.2 ms | 3.1 ms |
| joined children (1:N) | 42.9 ms | 37.6 ms | ~0% | — | — |
| plain parent load | 4.2 ms | 3.6 ms | ~0% | — | — |

**Behaviour change:** `yield_per` set in a `do_orm_execute` event for a
relationship load no longer raises
`InvalidRequestError("Can't use yield_per in conjunction with unique")` for
`selectinload` without a nested collection `joinedload` — because `.unique()`
is no longer called in that path. `immediateload` is unaffected (it still calls
`.unique()` unconditionally).

Fixes: #13339
Closes: #13341
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13341
Pull-request-sha: 980af0383b174271bb602a890f595c26f78ddcee

Change-Id: I12e993f104d354ae894f81f9b09fbcf9a95b0027

7 weeks agoHoist loop-invariant set intersection in _get_display_froms
sebastianbreguel [Sun, 31 May 2026 20:12:19 +0000 (16:12 -0400)] 
Hoist loop-invariant set intersection in _get_display_froms

Fixes #13336.

`SelectState._get_display_froms` recomputed a loop-invariant `_cloned_intersection(...)` once per FROM element in each of the three correlation comprehensions, making each branch O(N²) in the number of FROM elements. This hoists the call so it runs once, which is O(N).

`_cloned_intersection` / `_cloned_difference` are pure and return a set, and neither argument changes during the comprehension, so the result is identical. A function-level benchmark asserts `old == new` at every N (full numbers in #13336), and `test/sql/` plus the ORM compilation/query tests pass: 7442 passed, 359 skipped. Net -14 lines.

Per the issue discussion, no changelog entry is included.

### Checklist

This pull request is:

- [x] A short code fix
  - Issue with a runnable demonstration: #13336
  - Behavior-preserving (no logic change), so it is covered by the existing `test/sql/` and ORM compilation/query suites rather than adding new tests.

Closes: #13337
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13337
Pull-request-sha: beba43e77a773a4d9e9d55cc39c7c85ecda6293e

Change-Id: I95b02ffa66ef709c16bf5275924ec03244c19ecb

7 weeks agoAdd ambiguous column support to SimpleResultMetaData
me-saurabhkohli [Fri, 29 May 2026 20:03:40 +0000 (16:03 -0400)] 
Add ambiguous column support to SimpleResultMetaData

Fixed issue where :meth:`.Result.freeze` would lose track of ambiguous
column names present in the original :class:`.CursorResult`, causing
key-based access on the thawed result to silently return a value instead of
raising :class:`.InvalidRequestError`.  The
:class:`.SimpleResultMetaData` now accepts and propagates ambiguous key
information so that frozen, thawed, and pickled results raise consistently
for duplicate column names.  Pull request courtesy Saurabh Kohli.

Fixes: #9427
Closes: #13335
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/13335
Pull-request-sha: c03904ece298493ca69bf6e9cbdae23c7fb6a7b0

Change-Id: Ia184f77b442b069e6f9a4f94a967ead41a1704b6

7 weeks agoMerge "allow backref named 'metadata' to not break _metadata_for_cls" into main
Michael Bayer [Thu, 28 May 2026 16:37:00 +0000 (16:37 +0000)] 
Merge "allow backref named 'metadata' to not break _metadata_for_cls" into main

7 weeks agoallow backref named 'metadata' to not break _metadata_for_cls
Mike Bayer [Thu, 28 May 2026 14:25:39 +0000 (10:25 -0400)] 
allow backref named 'metadata' to not break _metadata_for_cls

Fixed regression caused by :ticket:`8068` where a ``backref``
named ``'metadata'`` on a mapped class would cause an
``AssertionError`` when the class also used string-based
relationship references (e.g. ``secondary="some_table"``).
The ``_metadata_for_cls()`` helper now checks
``isinstance(meta, MetaData)`` as a condition rather than
asserting, falling back to ``registry.metadata`` when the
class attribute has been overwritten by a backref.

A warning is now emitted when a Declarative attribute name is named
``metadata`` or ``registry``.  Previously, no warning was emitted for
``registry``, and using the name ``metadata`` would raise an
InvalidRequestError.   Since these names can be used for attributes
that are mapped as backrefs or using imperative mappings, usage
under Declarative has been relaxed for ``metadata`` but also warns
for both names as they may have unintended interactions with the
Declarative reserved names.

References: https://bugs.launchpad.net/nova/+bug/2154165
References: https://github.com/sqlalchemy/sqlalchemy/discussions/8619

Fixes: #13333
Change-Id: I0f3173bce9c8c8881bd6b8ea75102bb8ec92be8b