You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# Somewhere around 2025-09-08, Fabric started validating the "Database=" connection argument and throwing 'Authentication failed' if the database doesnt exist
111
-
# In addition, set_current_catalog() is implemented using a threadlocal variable "target_catalog"
112
-
# So, when we drop a warehouse, and there are still threads with "target_catalog" set to reference it, any operations on those threads
113
-
# that use an either use an existing connection pointing to this warehouse or trigger a new connection
114
-
# will fail with an 'Authentication Failed' error unless we close all connections here, which also clears all the threadlocal data
135
+
# Close all connections if any thread may be using the dropped warehouse.
136
+
# We must check both the logical target and the physical connection catalog
137
+
# (falling back to the configured default when either is neutral) because
138
+
# Fabric validates the DATABASE= connection argument and raises
139
+
# 'Authentication Failed' when it points at a non-existent warehouse.
logger.debug("Already using requested Fabric catalog state, no action needed")
141
183
return
142
184
143
-
logger.info(f"Switching from catalog '{current_catalog}' to '{catalog_name}'")
144
-
145
-
# commit the transaction before closing the connection to help prevent errors like:
146
-
# > Snapshot isolation transaction failed in database because the object accessed by the statement has been modified by a
147
-
# > DDL statement in another concurrent transaction since the start of this transaction
148
-
# on subsequent queries in the new connection
149
-
self._connection_pool.commit()
150
-
151
-
# note: we call close() on the connection pool instead of self.close() because self.close() calls close_all()
152
-
# on the connection pool but we just want to close the connection for this thread
153
-
self._connection_pool.close()
154
-
self._target_catalog=catalog_name# new connections will use this catalog
155
-
156
-
catalog_after_switch=self.get_current_catalog()
185
+
# Decide whether the open connection needs to be replaced.
186
+
#
187
+
# The set_catalog decorator restores the previous catalog (often None)
188
+
# after every catalog-scoped call. For Fabric, a connection close +
189
+
# reopen is expensive because each new connection goes through ODBC and
190
+
# the Fabric gateway. We therefore apply lazy connection management:
191
+
#
192
+
# * When restoring to neutral (target=None): just update _target_catalog.
193
+
# The existing connection stays alive and will be reused or replaced
194
+
# on the next real switch, avoiding a pointless bounce through the
195
+
# default catalog.
196
+
#
197
+
# * When switching to a non-neutral catalog: only close/reopen if the
198
+
# open connection is already on a different catalog. If a previous
199
+
# restore-to-neutral left the connection on the right catalog, we
200
+
# skip the close entirely.
201
+
needs_reconnect= (target_catalogisnotNoneorexplicit_default_catalog) and (
202
+
connected_catalog!=target_catalog
203
+
)
157
204
158
-
ifcatalog_after_switch!=catalog_name:
159
-
# We need to raise an error if the catalog switch failed to prevent the operation that needed the catalog switch from being run against the wrong catalog
160
-
raiseSQLMeshError(
161
-
f"Unable to switch catalog to {catalog_name}, catalog ended up as {catalog_after_switch}"
205
+
ifneeds_reconnect:
206
+
logger.info(
207
+
"Switching connection from catalog '%s' to '%s'",
208
+
self._catalog_state_label(connected_catalog),
209
+
self._catalog_state_label(target_catalog),
162
210
)
211
+
# Commit before closing to avoid snapshot-isolation errors on
212
+
# subsequent queries in the new connection.
213
+
self._connection_pool.commit()
214
+
# note: close() on the pool (not self.close()) to only affect this
215
+
# thread's connection rather than all threads.
216
+
self._connection_pool.close()
217
+
self._connected_catalog=target_catalog
218
+
else:
219
+
logger.debug(
220
+
"Updating catalog target to '%s' (connection remains on '%s')",
0 commit comments