ResultSet fetch methods silently return empty after close instead of raising (PEP 249 §Cursor)

Đang mở
#792 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
55/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Ít trao đổi
Công nghệ
python
Lĩnh vực
backend-api-design

Hướng nghiên cứu

Bắt đầu trong src/databricks/sql/result_set.py, sau đó truy vết các phương thức fetch trên ThriftResultSet, SeaResultSet và KernelResultSet. Trước tiên, tái hiện ví dụ về cursor đã đóng và kiểm tra cách close() thiết lập trạng thái hiện có cùng các cờ hết dữ liệu. Hoàn thành có nghĩa là mọi phương thức fetch được liệt kê đều phát sinh InterfaceError sau close() trên cả ba backend, hành vi theo PEP 249 đã được xác minh và ghi chú về khả năng tương thích đã được xem xét.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

enhancement

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):

  1. Add self._closed: bool = False. Set to True inside close() after cleanup.
  2. Add a private _check_open() that raises InterfaceError("Result set is closed") if _closed.
  3. 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.

Ngôn ngữ chính
Python
Star
233
Fork
152
Merge trung bình
21 giờ 5 phút
Pull request đã merge (30 ngày)
10

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của databricks/databricks-sql-python

Tất cả issue của databricks/databricks-sql-python

Issue tương tự

Thêm issue về Python

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.