Releases: snowflakedb/snowflake-sqlalchemy
Releases · snowflakedb/snowflake-sqlalchemy
Release
- v1.10.0 (May 20, 2026)
- Fix
with_loader_criteriasilently dropping filters on non-Snowflake dialects (#676). 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, etc. Snowflake dialect behavior is unchanged; the BCR-1057 lateral-join workaround is now scoped to Snowflake connections only. - Map Snowflake
UUIDcolumn type tosqlalchemy.sql.sqltypes.UUIDfor reflection on SQLAlchemy 2.x (#681). Previously reflected asNullType. Values are returned as plain strings (as_uuid=False) rather thanuuid.UUIDinstances. No change on SQLAlchemy 1.4 where the genericUUIDtype does not exist. - Add GCS bucket support for
CopyIntoStorage(SNOW-721174, #368). - Scope
referred_schema=Nonenormalization in foreign key reflection to the default schema only (#610, SNOW-2313675):- When reflecting the default schema, same-schema FKs (default → default) keep the established SQLAlchemy convention of
referred_schema=None, preserving compatibility with the upstream reflection test suite and with applications that do not qualify default-schema FK targets. - When reflecting a non-default schema every FK keeps its actual
referred_schema, which prevents SQLAlchemy's_reflect_fkfrom autoloading a non-default-schema target from the wrong place (the bug behind #610) and avoids the Alembic autogenerate mismatch that previously occurred when user metadata explicitly qualified a cross-schema FK that happened to target the default schema.
- When reflecting the default schema, same-schema FKs (default → default) keep the established SQLAlchemy convention of
- Add
SnowflakeBase,snowflake_declarative_base(), andSnowflakeSessionto enable efficient bulk inserts for ORM models with nullable optional columns (SNOW-893080, #441). Whensession.bulk_save_objects()is used with models that have randomly populated nullable columns, SQLAlchemy normally groups objects by their set of non-None column keys, producing O(N) separate INSERT statements.SnowflakeBase/snowflake_declarative_base()pre-populate all plain-nullable columns at construction time, andSnowflakeSessionpassesrender_nulls=Trueso all objects share the same parameter-key set and are batched into a singleexecutemanyINSERT. - Fix case-sensitive identifier handling (SNOW-1232488). Always-active bug fixes with no behavioural change for default users:
_split_schema_by_dotnow correctly parses SQL-escaped double-quotes ("") inside quoted schema/database identifiers (e.g."my""schema"→my"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. The caller has already opted into case-sensitive semantics by constructing aquoted_name(..., True), so this is honoured independently of the dialect flag._has_object(used byhas_table/has_sequence) now appliesdenormalize_nameto both the schema and object name before building theDESCSQL, making it consistent with all other reflection methods.- Atomic
_NameUtilsswap increate_connect_args— when the URL'scase_sensitive_identifiersvalue differs from the current dialect state, thename_utilsinstance is replaced rather than mutated in place, so concurrent readers on other threads observe either the old or the new instance but never a torn update.
- Add
case_sensitive_identifiersopt-in engine flag (kwarg or?case_sensitive_identifiers=TrueURL param) governing three related behaviours. The default isFalse; existing applications are unaffected unless they explicitly opt in:- ALL-UPPERCASE reserved-word identifiers (e.g.
TABLE) are normalised toquoted_name("table", True)instead of returning unchanged, preventing key-lookup mismatches between creation and reflection. - Mixed-case reflected identifiers (e.g.
MyColfrom a quoted Snowflake column) are returned asquoted_name("MyCol", True)instead of a plainstr. Emitted SQL is identical in both modes (_requires_quotesforce-quotes any name containing uppercase chars); the difference is only observable viaisinstance(..., quoted_name)and.quote. - Schema strings with inner double-quotes — e.g.
'"myschema"'or'"mydb"."myschema"'— have their extracted parts markedquote=Trueby_split_schema_by_dot, preserving case-sensitivity in emitted SQL. Without the flag, the extracted parts keepquote=Noneand the preparer's_requires_quotesheuristic decides per-part (stripping inner quotes for all-lowercase parts, which matches pre-PR behaviour). Usequoted_name("myschema", True)orMetaData(schema=quoted_name(..., True))to opt into case-sensitivity on a per-value basis without enabling the flag.
- ALL-UPPERCASE reserved-word identifiers (e.g.
- Add
create_snowflake_engine(url, schema=..., case_sensitive_schema=True)helper that URL-encodes case-sensitive schema names using%22so the Snowflake connector receives the literal double-quoted form. Fix security vulnerability: schema names are now always URL-encoded regardless ofcase_sensitive_schema, preventing special characters (?,#,/) from being misinterpreted as URL delimiters by SQLAlchemy's URL parser. - Add
snowflake.sqlalchemy.alembic_util.render_item— a drop-in Alembicrender_itemhook forenv.pythat serialisesquoted_namecolumns withquote=Truecorrectly in generated migration files, preventing Alembic autogenerate from silently converting case-sensitive column names to uppercase. - Emit
SnowflakeWarningat DDL compile time whenIdentity()is used on a primary key column, alerting users that ORM flush operations will raise aFlushError. The warning is emitted once per unique(table, column)pair per Python process. UseSequence()instead. - Add support for cross-database schema reflection using
schema='database.schema'notation. This allows reflecting and joining tables from different databases in a single session without raw SQL. (#456) - 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 #545 introduced the override (#618). - Introduce composite key ordering, fixes #450
- Optimise reflection performance (SNOW-689531, #656):
- Add
get_multi_columns,get_multi_pk_constraint,get_multi_unique_constraints,get_multi_foreign_keysfor SQLAlchemy 2.x bulk reflection — each issues one schema-wide query per reflection pass instead of one query per table. - SQLAlchemy 2.x
get_columnsnow usesDESC TABLEdirectly (per-table, live) sinceget_multi_columnshandles all bulk reflection; temporary tables and dynamic tables are reflected correctly without schema-wide queries. - Fix
SHOW INDEXES IN TABLEreplacing the previousSHOW TABLES LIKEapproach for single-table index reflection, eliminating SQLLIKEwildcard false-positives and case-sensitivity bugs. - Add
_always_quote_joinhelper that always quotes denormalised identifiers — ensures correct SQL for case-sensitive table and schema names in per-table reflection paths. - Fix foreign key
referred_schemaresolution so reflected FKs always keep their actual schema unless the target lives in the connection's default schema. Previously FKs whose target shared the reflected non-default schema were reported withreferred_schema=None, which caused SQLAlchemy's_reflect_fkto autoload from the wrong schema and raiseNoReferencedColumnErrorduring Alembic autogenerate. - Add shared row-parsing helpers (
_parse_pk_rows,_parse_uk_rows,_parse_fk_rows) so correctness fixes propagate to both per-table and schema-wide reflection paths. cache_column_metadata=Trueopt-in enables per-tableSHOW … IN TABLEqueries forget_pk_constraint,get_unique_constraints,get_foreign_keys, andget_indexeson SQLAlchemy 1.4.- 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. Previously these methods always issuedSHOW … IN SCHEMAeven for single-table Inspector calls (e.g.pandas.read_sql_table()), causing ~20-second delays on schemas with thousands of tables (SNOW-689531).
- Add
- Fix
Release
- v1.9.0 (March 4, 2026)
- Add support for
DECFLOATandVECTORdata types - Add server_version_info support
- Add support for
ILIKEin queries - Fix
SYSDATE()rendering - Fix and improve schema reflection (SNOW-593204, SNOW-2331576, SNOW-2852779)
- Fix crash when reflecting without specifying a schema, caused by
Nonearguments in internal schema resolution (#623). - Fix crash when
SHOW TABLESreturns empty string table names, causingIndexErrorduring reflection (#296). - Fix incomplete identity column reflection metadata, now includes all fields required by SQLAlchemy 2.0+ (
always,cycle,order, etc.). - Introduce shared helper for fully-qualified schema name resolution, replacing inconsistent ad-hoc patterns across reflection methods.
- Refactor column reflection internals into dedicated helpers to reduce complexity without changing behavior.
- Add
pytest-xdistparallel test support via per-worker schema provisioning hooks.
- Fix crash when reflecting without specifying a schema, caused by
- Bump
pandaslower bound insa14test environment from<2.1to>=2.1.1,<2.2to ensure pre-built wheels are available for Python 3.12 - Fix SQLAlchemy version parsing (SNOW-3066571)
- Document support for session parameters (like QUERY_TAG), references: #644
- Support timezone in timestamp and datetime types (#199)
- Add support for
Release
-
v1.8.2 (December 9, 2025)
- Updated supported max python version to 3.13
- Version 1.8.1 yanked due to max python version supported by
snowflake-connector-python
-
v1.8.1 (December 9, 2025)
- Add python 3.14 to project metadata
Release
- v1.8.0(December 5, 2025)
- Add logging of SQLAlchemy version
- Bump
snowflake-connector-python<5.0.0 - Add python up to 3.14
- Add logging of SQLAlchemy version and pandas (if used)
Release
- v1.7.7(September 3, 2025)
- Fix exception for structured type columns dropped while collecting meetadata
Release
- v1.7.6(July 10, 2025)
- Fix get_multi_indexes issue, wrong assign of returned indexes when processing multiple indexes in a table
Release
- v1.7.5(June 20, 2025)
- Fix compilation of Merge and Copy Into was not working
Release
- v1.7.4(June 10, 2025)
- Fix dependency on DESCRIBE TABLE columns quantity (differences in columns caused by Snowflake parameters).
- Fix unnecessary condition was causing issues when parsing StructuredTypes columns.
- Update README.md to include instructions on how to verify package signatures using cosign.
Release
- v1.7.3(January 15, 2025)
- Fix support for SqlAlchemy ARRAY.
- Fix return value of snowflake get_table_names.
- Fix incorrect quoting of identifiers with
_as initial character. - Fix ARRAY type not supported in HYBRID tables.
- Add
force_div_is_floordivflag to overridediv_is_floordivnew default valueFalseinSnowflakeDialect.- With the flag in
False, the/division operator will be treated as a float division and//as a floor division. - This flag is added to maintain backward compatibility with the previous behavior of Snowflake Dialect division.
- This flag will be removed in the future and Snowflake Dialect will use
div_is_floor_divasFalse.
- With the flag in
Release
- v1.7.2(December 18, 2024)
- Fix quoting of
_as column name - Fix index columns was not being reflected
- Fix index reflection cache not working
- Add support for structured OBJECT datatype
- Add support for structured ARRAY datatype
- Fix quoting of