do_rollback() swallows the connector's NotSupportedError, so a rollback reports success over a write that stands

オープン 初心者向け
#77 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

@dwaddle がすでに取り組んでいます。

2026年10月23日 から。

  • #86 @dwaddle による — オープン

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
68/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
静か
技術スタック
python, sqlalchemy
領域
databases

調査の方向性

DatabendDialect.do_rollback を見つけ、issue で説明されている connector Connection.rollback の動作を確認してください。サポートされていない操作に対して rollback が成功を報告しなくなっていることを検証し、リポジトリに対応するテストがある場合は、明示的な rollback および SQLAlchemy のエラーパスのカバレッジを追加または更新してください。

索引モデルが issue の本文から書いたものです。

説明

Versions

  • databend-sqlalchemy 0.5.5
  • databend-driver 0.34.2
  • SQLAlchemy 2.0.51
  • Python 3.12.9, macOS
  • Server: datafuselabs/databend:v1.2.925-patch-4 in Docker

What happens

connector.Connection.rollback() is honest — it raises:

class Connection:
    def commit(self): pass
    def rollback(self):
        raise NotSupportedError("Transactions are not supported")

but the dialect overrides do_rollback and swallows it:

class DatabendDialect:
    def do_rollback(self, dbapi_connection):
        # No transactions
        pass

So sqlalchemy.Connection.rollback() returns normally over a write that is still there afterwards. Nothing raises, nothing warns.

Three sequences, one variable changed each time, row count read back on a fresh connection:

sequence rows afterwards
INSERT, connection closed without committing 1
INSERT, then an explicit Connection.rollback() 1
BEGIN, INSERT, ROLLBACK sent as plain statements 1

Expected: either the rollback raises (the connector underneath already does), or it rolls something back.

Why this is worse than simply not having transactions

Wrapping writes in a transaction and rolling back on error is ordinary code, and this turns it from loudly unsupported into silently wrong. with engine.begin(): around a block that fails reports a clean rollback and leaves the partial write in place. SQLAlchemy's own error path issues a rollback when a statement fails inside a transaction, so that gets the same false report without the caller writing a rollback at all.

I ran into it building a compatibility layer that treats "can this engine undo a write" as a capability it has to answer per backend. Databend is the second engine I've seen answer that question wrongly, and the only one where the wrong answer comes from a deliberate override rather than an accident further down.

One thing worth stating precisely

"Databend has no transactions" isn't accurate, and the distinction matters for how you'd fix this. BEGIN/COMMIT are real statements, and every HTTP response carries a txn_state field (AutoCommit, in this configuration). Reaching them needs the client to carry the session back between requests — session_id and need_sticky in the response are how — and the blocking cursor path in databend-driver doesn't. So transactions are unreachable through this adapter rather than absent from the database. That's clearly a bigger piece of work; this issue is only about the false success.

Related: get_isolation_level raises NotImplementedError, so a caller can't ask the engine what it's going to do instead.

Suggested fix

Drop the do_rollback override and let the connector's NotSupportedError propagate. If that breaks too much for existing users, a warning would at least make it discoverable. The current shape is the one that can't be detected from outside.

主要言語
Python
スター
15
フォーク
5
平均マージ
1日 15時間
マージ済み PR(30日)
1

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

databendlabs/databend-sqlalchemy のほかの issue

databendlabs/databend-sqlalchemy の issue をすべて見る

似ている issue

Python の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。