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

Aperta
#792 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
55/100
Tipo di issue
Bug
Chiarezza
Abbastanza chiara
Stato di attività
Tranquilla
Stack tecnologico
python

Direzione di ricerca

Inizia da src/databricks/sql/result_set.py, quindi segui i metodi di fetch di ThriftResultSet, SeaResultSet e KernelResultSet. Riproduci prima l’esempio del cursore chiuso e verifica come close() imposta lo stato esistente e i flag di esaurimento. Il lavoro è completo quando ogni metodo di fetch elencato solleva InterfaceError dopo close() per tutti e tre i backend, il comportamento PEP 249 è verificato e la nota sulla compatibilità è stata presa in considerazione.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

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.

Lingua principale
Python
Stelle
233
Fork
152
Merge medio
21h 5m
PR unite (30g)
10

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di databricks/databricks-sql-python

Tutte le issue di databricks/databricks-sql-python

Issue simili

Altre issue su Python

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.