SQLAlchemy release notes for 2026¶
This article contains the release notes for the SQLAlchemy, including the following when applicable:
- Behavior changes
- New features
- Customer-facing bug fixes
Snowflake uses semantic versioning for SQLAlchemy updates.
See Using the Snowflake SQLAlchemy toolkit with the Python Connector for documentation.
Version 1.10.0 (May 20, 2026)¶
New features and updates¶
- Added Google Cloud Storage (GCS) bucket support for the
CopyIntoStorageexpression. - Added
SnowflakeBase,snowflake_declarative_base(), andSnowflakeSessionto enable efficient bulk inserts for ORM models with nullable optional columns. UsingSnowflakeBase(orsnowflake_declarative_base()) along withSnowflakeSessionbatches all objects into a singleexecutemanyINSERT, instead of producing one INSERT statement per distinct set of non-Nonecolumn keys. - Added the
case_sensitive_identifiersopt-in engine flag (constructor keyword argument or?case_sensitive_identifiers=TrueURL parameter) that governs case-sensitive identifier handling. The default value isFalse, so existing applications aren’t affected unless they explicitly opt in. When you opt in:- All-uppercase reserved-word identifiers (for example,
TABLE) are normalized toquoted_name("table", True)to prevent key-lookup mismatches between creation and reflection. - Mixed-case reflected identifiers (for example,
MyColfrom a quoted Snowflake column) are returned asquoted_name("MyCol", True)instead of a plainstr. - Schema strings with inner double quotes (for example,
'"myschema"'or'"mydb"."myschema"') have their extracted parts markedquote=True, preserving case sensitivity in emitted SQL.
- All-uppercase reserved-word identifiers (for example,
- Added the
create_snowflake_engine(url, schema=..., case_sensitive_schema=True)helper. The helper URL-encodes case-sensitive schema names using%22so the Snowflake connector receives the literal double-quoted form. Schema names are now always URL-encoded regardless ofcase_sensitive_schema, preventing special characters (?,#,/) from being misinterpreted as URL delimiters. - Added
snowflake.sqlalchemy.alembic_util.render_item, a drop-in Alembicrender_itemhook forenv.pythat serializesquoted_namecolumns withquote=Truecorrectly in generated migration files, preventing Alembic autogenerate from silently converting case-sensitive column names to uppercase. - Added support for cross-database schema reflection using
schema='database.schema'notation, so you can reflect and join tables from different databases in a single session without using raw SQL. - Added composite key ordering.
- Added a
SnowflakeWarningthat’s emitted at DDL compile time whenIdentity()is used on a primary key column. The warning alerts you that ORM flush operations will raise aFlushError. UseSequence()instead. The warning is emitted once per unique(table, column)pair per Python process. - Mapped the Snowflake
UUIDcolumn type tosqlalchemy.sql.sqltypes.UUIDfor reflection on SQLAlchemy 2.x. The column was previously reflected asNullType. Values are returned as plain strings (as_uuid=False) rather thanuuid.UUIDinstances. There’s no change on SQLAlchemy 1.4, where the genericUUIDtype doesn’t exist. - Optimized reflection performance:
- Added
get_multi_columns,get_multi_pk_constraint,get_multi_unique_constraints, andget_multi_foreign_keysfor SQLAlchemy 2.x bulk reflection. Each method issues one schema-wide query per reflection pass instead of one query per table. - On SQLAlchemy 2.x,
get_pk_constraint,get_unique_constraints,get_foreign_keys, andget_indexesnow automatically use per-tableSHOW … IN TABLEqueries without any opt-in flag. These methods previously always issuedSHOW … IN SCHEMA, even for single-table Inspector calls, which caused approximately 20-second delays on schemas with thousands of tables. - The
cache_column_metadata=Trueopt-in now enables per-tableSHOW … IN TABLEqueries forget_pk_constraint,get_unique_constraints,get_foreign_keys, andget_indexeson SQLAlchemy 1.4. - SQLAlchemy 2.x
get_columnsnow usesDESC TABLEdirectly so that temporary tables and dynamic tables are reflected correctly.
- Added
Bug fixes¶
- Fixed
with_loader_criteriasilently dropping filters on non-Snowflake dialects. Importingsnowflake-sqlalchemypreviously altered SQLAlchemy’s ORM compilation for every dialect in the process, causing loader-criteria filters to be omitted inside sealed subqueries when using PostgreSQL, MySQL, SQLite, and others. Snowflake dialect behavior is unchanged; the BCR-1057 lateral-join workaround is now scoped to Snowflake connections only. - Scoped
referred_schema=Nonenormalization in foreign key reflection to the default schema only. When reflecting the default schema, same-schema foreign keys (default to default) keep the established SQLAlchemy convention ofreferred_schema=None. When reflecting a non-default schema, every foreign key keeps its actualreferred_schema. This change prevents Alembic autogenerate mismatches that previously occurred for cross-schema foreign keys that targeted the default schema. - Fixed case-sensitive identifier handling:
_split_schema_by_dotnow correctly parses SQL-escaped double quotes ("") inside quoted schema and database identifiers (for example,"my""schema"becomesmy"schema), preventing silent truncation of identifiers containing literal quote characters.denormalize_column_namenow correctly double-quotesquoted_name("mycol", True)columns inCLUSTER BYclauses, instead of silently dropping the case-sensitivity signal._has_object(used byhas_tableandhas_sequence) now appliesdenormalize_nameto both the schema and object name before building theDESCSQL, making it consistent with all other reflection methods.create_connect_argsnow atomically replaces thename_utilsinstance when the URL’scase_sensitive_identifiersvalue differs from the current dialect state, so concurrent readers on other threads never observe a torn update.
- Restored backward-compatible SQL generation for true division (
/) whendiv_is_floordiv=True. The Snowflake compiler now correctly delegates to the SQLAlchemy base implementation, emittingCAST(col AS NUMERIC)for integer operands as it did before. - Fixed foreign key
referred_schemaresolution so reflected foreign keys keep their actual schema unless the target is in the connection’s default schema. Foreign keys whose target shared the reflected non-default schema were previously reported withreferred_schema=None, which caused SQLAlchemy’s_reflect_fkto autoload from the wrong schema and raiseNoReferencedColumnErrorduring Alembic autogenerate. - Replaced
SHOW TABLES LIKEwithSHOW INDEXES IN TABLEfor single-table index reflection, eliminating SQLLIKEwildcard false positives and case-sensitivity bugs.
Version 1.9.0 (March 04, 2026)¶
New features and updates¶
- Added support for
DECFLOATandVECTORdata types. - Added support for
server_version_infosupport. - Added support for
ILIKEin queries. - Introduced a shared helper for fully-qualified schema name resolution, replacing inconsistent ad-hoc patterns across reflection methods.
- Refactored column reflection internals into dedicated helpers to reduce complexity without changing behavior.
- Added
pytest-xdistparallel test support via per-worker schema provisioning hooks. - Bumped pandas lower bound in the sa14 test environment from <2.1 to >=2.1.1,<2.2 to ensure pre-built wheels are available for Python 3.12.
- Added support for timezone in timestamp and datetime types.
Bug fixes¶
- Fixed
SYSDATE()rendering. - Fixed and improved schema reflection.
- Fixed a crash issue when reflecting without specifying a schema, caused by
Nonearguments in internal schema resolution. - Fixed a crash issue when SHOW TABLES returns empty string table names, causing
IndexErrorduring reflection. - Fixed incomplete identity column reflection metadata. This column now includes all fields required by SQLAlchemy 2.0+ (
always,cycle,order, and so on). - Fixed SQLAlchemy version parsing.