Skip to content

Commit 0d5ef29

Browse files
test: add regression tests
1 parent a2fb885 commit 0d5ef29

1 file changed

Lines changed: 67 additions & 0 deletions

File tree

Lib/test/test_sqlite3/test_regression.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,5 +503,72 @@ def test_recursive_cursor_iter(self):
503503
self.cur.fetchall)
504504

505505

506+
class CallbackClosesConnectionTests(unittest.TestCase):
507+
"""Regression tests for gh-XXXXXX: callbacks that close the connection
508+
during query execution must raise ProgrammingError, not crash."""
509+
510+
def _make_con(self) -> sqlite.Connection:
511+
con = sqlite.connect(":memory:")
512+
con.execute("CREATE TABLE t (v INTEGER)")
513+
con.execute("INSERT INTO t VALUES (1)")
514+
con.commit()
515+
return con
516+
517+
def test_udf_closes_connection(self) -> None:
518+
con = self._make_con()
519+
520+
def evil(x: int) -> int:
521+
con.close()
522+
return x
523+
524+
con.create_function("evil", 1, evil)
525+
with self.assertRaises((sqlite.ProgrammingError, sqlite.OperationalError)):
526+
con.execute("SELECT evil(v) FROM t").fetchall()
527+
528+
def test_progress_handler_closes_connection(self) -> None:
529+
con = self._make_con()
530+
fired = False
531+
532+
def handler() -> int:
533+
nonlocal fired
534+
if not fired:
535+
fired = True
536+
con.close()
537+
return 0
538+
539+
con.set_progress_handler(handler, 1)
540+
with self.assertRaises((sqlite.ProgrammingError, sqlite.OperationalError)):
541+
con.execute("SELECT v FROM t").fetchall()
542+
543+
def test_trace_callback_closes_connection(self) -> None:
544+
con = self._make_con()
545+
fired = False
546+
547+
def tracer(statement: str) -> None:
548+
nonlocal fired
549+
if not fired:
550+
fired = True
551+
con.close()
552+
553+
con.set_trace_callback(tracer)
554+
with self.assertRaises((sqlite.ProgrammingError, sqlite.OperationalError)):
555+
con.execute("SELECT v FROM t").fetchall()
556+
557+
def test_authorizer_closes_connection(self) -> None:
558+
con = self._make_con()
559+
fired = False
560+
561+
def auth(action: int, arg1: str, arg2: str, db: str, trigger: str) -> int:
562+
nonlocal fired
563+
if not fired:
564+
fired = True
565+
con.close()
566+
return sqlite.SQLITE_OK
567+
568+
con.set_authorizer(auth)
569+
with self.assertRaises((sqlite.ProgrammingError, sqlite.OperationalError)):
570+
con.execute("SELECT v FROM t").fetchall()
571+
572+
506573
if __name__ == "__main__":
507574
unittest.main()

0 commit comments

Comments
 (0)