@@ -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+
506573if __name__ == "__main__" :
507574 unittest .main ()
0 commit comments