ResultSet fetch methods silently return empty after close instead of raising (PEP 249 §Cursor)
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 55/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 静か
- 技術スタック
- python
調査の方向性
src/databricks/sql/result_set.py から開始し、続いて ThriftResultSet、SeaResultSet、KernelResultSet の fetch メソッドを追跡します。まず閉じたカーソルの例を再現し、close() が既存の状態と枯渇フラグをどのように設定するかを確認します。3 つすべてのバックエンドで、一覧にあるすべての fetch メソッドが close() 後に InterfaceError を発生させ、PEP 249 の動作が検証され、互換性に関する注記が考慮されていれば完了です。
索引モデルが issue の本文から書いたものです。
説明
Summary
PEP 249 §Cursor says fetch operations on a closed cursor should raise an exception. Today, all three result-set implementations (ThriftResultSet, SeaResultSet, KernelResultSet) silently return empty after close() rather than raising InterfaceError.
Repro
import databricks.sql
with databricks.sql.connect(...) as conn:
cur = conn.cursor()
cur.execute("SELECT 1")
cur.close()
cur.fetchall() # PEP 249 says raise; today returns [].
Root cause
# src/databricks/sql/result_set.py — base ResultSet.close():
def close(self) -> None:
...
finally:
self.has_been_closed_server_side = True
self.status = CommandState.CLOSED
The flag is set, but the fetch methods don't read it. They walk self.results (an internal queue) which has been closed; next_n_rows returns empty rather than raising. KernelResultSet has the same shape with self._exhausted = True in close, which short-circuits its fetch loop to empty.
Scope
All three backends. This is a project-wide PEP 249 compliance gap, not specific to the kernel backend.
Concurrent fetch-vs-close (related)
There is no _closed flag readable by concurrent threads — if one thread is mid-fetch while another calls close(), behaviour is undefined (likely AttributeError from a nulled handle). Cursors are documented as not thread-safe, so this is "not a bug" by design, but a single _closed flag would make accidental misuse fail cleanly with InterfaceError instead of AttributeError.
Suggested fix
In base ResultSet (src/databricks/sql/result_set.py):
- Add
self._closed: bool = False. Set toTrueinsideclose()after cleanup. - Add a private
_check_open()that raisesInterfaceError("Result set is closed")if_closed. - Call
_check_open()at the top of every fetch method (fetchone,fetchmany,fetchall,fetchmany_arrow,fetchall_arrow).
Backwards-compat note: any user code that defensively does cur.close(); cur.fetchall() expecting [] will start raising. Likely warrants a release note.
Surfaced by
Review of PR #787 (kernel backend). Documented as P1 #8 + #9 in https://github.com/databricks/databricks-sql-python/pull/787#issuecomment-4475165482 — but the gap is pre-existing on Thrift and SEA too, not specific to the kernel backend.
- 主要言語
- Python
- スター
- 233
- フォーク
- 152
- 平均マージ
- 21時間 5分
- マージ済み PR(30日)
- 10
コントリビューションガイド
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
databricks/databricks-sql-python のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
databricks/databricks-sql-python の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 86/100
-
🐛 Bug 🔔 Pending processing
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
jumpserver/jumpserver#17584 ·