Skip to content

Commit 275f99c

Browse files
committed
fix(db2): _truncate_table — IMMEDIATE outside transactions, DELETE inside
Two separate Db2 constraints require this dual approach: SQL0104N — TRUNCATE TABLE without IMMEDIATE fails; the keyword is mandatory in Db2 syntax and the base class does not add it. SQL0428N — TRUNCATE TABLE ... IMMEDIATE commits instantly and must be the first statement in a unit of work; it cannot run inside an open transaction and cannot be rolled back. When a transaction is already active, fall back to DELETE which participates in the transaction normally and can be rolled back. When no transaction is active, TRUNCATE TABLE ... IMMEDIATE runs as the first statement in a fresh unit of work and succeeds. This mirrors the intent of NonTransactionalTruncateMixin (used by MySQL and Redshift) but that mixin delegates to base._truncate_table() which omits IMMEDIATE — making it unsuitable for Db2 without an additional override.
1 parent cd67d73 commit 275f99c

1 file changed

Lines changed: 13 additions & 5 deletions

File tree

  • sqlmesh/core/engine_adapter

sqlmesh/core/engine_adapter/db2.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -733,11 +733,19 @@ def _create_table_like(
733733
)
734734

735735
def _truncate_table(self, table_name: TableName) -> None:
736-
# Db2 requires the IMMEDIATE keyword after the table name; without it
737-
# the statement fails with SQL0104N (unexpected token END-OF-STATEMENT,
738-
# expected IMMEDIATE).
739-
table = exp.to_table(table_name)
740-
self.execute(f"TRUNCATE TABLE {table.sql(dialect=self.dialect, identify=True)} IMMEDIATE")
736+
# Db2's TRUNCATE TABLE ... IMMEDIATE commits instantly and cannot be
737+
# rolled back (SQL0428N if inside an open transaction). When a
738+
# transaction is already active, use DELETE which participates in the
739+
# transaction normally and can be rolled back. When no transaction is
740+
# active, use TRUNCATE TABLE ... IMMEDIATE — the IMMEDIATE keyword is
741+
# mandatory in Db2 syntax (SQL0104N without it).
742+
if self._connection_pool.is_transaction_active:
743+
self.execute(exp.Delete(this=exp.to_table(table_name)))
744+
else:
745+
table = exp.to_table(table_name)
746+
self.execute(
747+
f"TRUNCATE TABLE {table.sql(dialect=self.dialect, identify=True)} IMMEDIATE"
748+
)
741749

742750
def _convert_df_datetime(self, df: DF, columns_to_types: t.Dict[str, exp.DataType]) -> None:
743751
"""

0 commit comments

Comments
 (0)