@@ -886,6 +886,36 @@ def __getitem__(slf, x):
886886 with self .assertRaises (ZeroDivisionError ):
887887 self .cu .execute ("select name from test where name=?" , L ())
888888
889+ def test_execute_use_after_close_with_bind_parameters (self ):
890+ # Prevent SIGSEGV when closing the connection while binding parameters.
891+ #
892+ # Internally, the connection's state is checked after bind_parameters().
893+ # Without this check, we would only be aware of the closed connection
894+ # by calling an sqlite3 function afterwards. However, it is important
895+ # that we report the error before leaving executemany() call.
896+ #
897+ # Regression test for https://github.com/python/cpython/issues/143198.
898+
899+ class PT (CxWrapper ):
900+ def __init__ (self , cx , value ):
901+ super ().__init__ (cx )
902+ self .value = value
903+
904+ def __getitem__ (self , i ):
905+ self .side_effect ()
906+ return self .value
907+
908+ def __len__ (self ):
909+ return 1
910+
911+ cx = sqlite .connect (":memory:" )
912+ cx .execute ("create table tmp(a number)" )
913+ self .addCleanup (cx .close )
914+ cu = cx .cursor ()
915+ msg = r"Cannot operate on a closed database\."
916+ with self .assertRaisesRegex (sqlite .ProgrammingError , msg ):
917+ cu .execute ("insert into tmp(a) values (?)" , PT (cx , 1 ))
918+
889919 def test_execute_named_param_and_sequence (self ):
890920 dataset = (
891921 ("select :a" , (1 ,)),
@@ -1069,8 +1099,14 @@ def test_executemany_use_after_close(self, params_class):
10691099 with self .assertRaisesRegex (sqlite .ProgrammingError , msg ):
10701100 cu .executemany ("insert into tmp(a) values (?)" , params_class (cx ))
10711101
1072- def test_executemany_use_after_close_with___len__ (self ):
1073- # Prevent SIGSEGV with a len(parameters) closing the connection.
1102+ def test_executemany_use_after_close_with_bind_parameters (self ):
1103+ # Prevent SIGSEGV when closing the connection while binding parameters.
1104+ #
1105+ # Internally, the connection's state is checked after bind_parameters().
1106+ # Without this check, we would only be aware of the closed connection
1107+ # by calling an sqlite3 function afterwards. However, it is important
1108+ # that we report the error before leaving executemany() call.
1109+ #
10741110 # Regression test for https://github.com/python/cpython/issues/143198.
10751111
10761112 class PT (CxWrapper ):
@@ -1079,24 +1115,22 @@ def __init__(self, cx, value):
10791115 self .value = value
10801116
10811117 def __getitem__ (self , i ):
1082- if self .value == 3 :
1118+ if self .value == len ( ITEMS ) :
10831119 self .side_effect ()
10841120 return self .value
10851121
10861122 def __len__ (self ):
10871123 return 1
10881124
1089- class Ps (CxWrapper ):
1090- def __iter__ (self ):
1091- return iter ([PT (cx , 1 ), PT (cx , 2 ), PT (cx , 3 )])
1092-
10931125 cx = sqlite .connect (":memory:" )
10941126 cx .execute ("create table tmp(a number)" )
10951127 self .addCleanup (cx .close )
1128+
1129+ ITEMS = [PT (cx , 1 ), PT (cx , 2 ), PT (cx , 3 )]
10961130 cu = cx .cursor ()
10971131 msg = r"Cannot operate on a closed database\."
10981132 with self .assertRaisesRegex (sqlite .ProgrammingError , msg ):
1099- cu .executemany ("insert into tmp(a) values (?)" , Ps ( cx ))
1133+ cu .executemany ("insert into tmp(a) values (?)" , iter ( ITEMS ))
11001134
11011135 def test_fetch_iter (self ):
11021136 # Optional DB-API extension.
0 commit comments