@@ -728,21 +728,6 @@ def test_database_keyword(self):
728728 self .assertEqual (type (cx ), sqlite .Connection )
729729
730730
731- class ParamsCxCloseInIterMany :
732- def __init__ (self , cx ):
733- self .cx = cx
734-
735- def __iter__ (self ):
736- self .cx .close ()
737- return iter ([(1 ,), (2 ,), (3 ,)])
738-
739-
740- def ParamsCxCloseInNext (cx ):
741- for i in range (10 ):
742- cx .close ()
743- yield (i ,)
744-
745-
746731class CursorTests (unittest .TestCase ):
747732 def setUp (self ):
748733 self .cx = sqlite .connect (":memory:" )
@@ -874,31 +859,6 @@ def __getitem__(slf, x):
874859 with self .assertRaises (ZeroDivisionError ):
875860 self .cu .execute ("select name from test where name=?" , L ())
876861
877- def test_execute_and_concurrent_close_in___getitem__ (self ):
878- # Prevent SIGSEGV when closing the connection while binding parameters.
879- #
880- # Internally, the connection's state is checked after bind_parameters().
881- # Without this check, we would only be aware of the closed connection
882- # by calling an sqlite3 function afterwards. However, it is important
883- # that we report the error before leaving the execute() call.
884- #
885- # Regression test for https://github.com/python/cpython/issues/143198.
886-
887- class PT :
888- def __getitem__ (self , i ):
889- cx .close ()
890- return 1
891- def __len__ (self ):
892- return 1
893-
894- cx = sqlite .connect (":memory:" )
895- cx .execute ("create table tmp(a number)" )
896- self .addCleanup (cx .close )
897- cu = cx .cursor ()
898- msg = r"Cannot operate on a closed database\."
899- with self .assertRaisesRegex (sqlite .ProgrammingError , msg ):
900- cu .execute ("insert into tmp(a) values (?)" , PT ())
901-
902862 def test_execute_named_param_and_sequence (self ):
903863 dataset = (
904864 ("select :a" , (1 ,)),
@@ -1070,56 +1030,6 @@ def test_execute_many_not_iterable(self):
10701030 with self .assertRaises (TypeError ):
10711031 self .cu .executemany ("insert into test(income) values (?)" , 42 )
10721032
1073- @subTests ("params_factory" , (ParamsCxCloseInIterMany , ParamsCxCloseInNext ))
1074- def test_executemany_and_concurrent_close_in___iter__ (self , params_factory ):
1075- # Prevent SIGSEGV with iterable of parameters closing the connection.
1076- # Regression test for https://github.com/python/cpython/issues/143198.
1077- cx = sqlite .connect (":memory:" )
1078- cx .execute ("create table tmp(a number)" )
1079- self .addCleanup (cx .close )
1080- cu = cx .cursor ()
1081- msg = r"Cannot operate on a closed database\."
1082- with self .assertRaisesRegex (sqlite .ProgrammingError , msg ):
1083- cu .executemany ("insert into tmp(a) values (?)" , params_factory (cx ))
1084-
1085- # The test constructs an iterable of parameters of length 'n'
1086- # and the connection is closed when we access the j-th one.
1087- # The iterable is of type 'map' but the test wraps that map
1088- # with 'iterable_wrapper' to exercise internals.
1089- @subTests (("j" , "n" ), ([0 , 1 ], [0 , 3 ], [1 , 3 ], [2 , 3 ]))
1090- @subTests ("iterable_wrapper" , (list , lambda x : x , lambda x : iter (x )))
1091- def test_executemany_and_concurrent_close_in___getitem__ (
1092- self , j , n , iterable_wrapper
1093- ):
1094- # Prevent SIGSEGV when closing the connection while binding parameters.
1095- #
1096- # Internally, the connection's state is checked after bind_parameters().
1097- # Without this check, we would only be aware of the closed connection
1098- # by calling an sqlite3 function afterwards. However, it is important
1099- # that we report the error before leaving executemany() call.
1100- #
1101- # Regression test for https://github.com/python/cpython/issues/143198.
1102-
1103- cx = sqlite .connect (":memory:" )
1104- cx .execute ("create table tmp(a number)" )
1105- self .addCleanup (cx .close )
1106-
1107- class PT :
1108- def __init__ (self , value ):
1109- self .value = value
1110- def __getitem__ (self , i ):
1111- if self .value == j :
1112- cx .close ()
1113- return self .value
1114- def __len__ (self ):
1115- return 1
1116-
1117- cu = cx .cursor ()
1118- msg = r"Cannot operate on a closed database\."
1119- items = iterable_wrapper (map (PT , range (n )))
1120- with self .assertRaisesRegex (sqlite .ProgrammingError , msg ):
1121- cu .executemany ("insert into tmp(a) values (?)" , items )
1122-
11231033 def test_fetch_iter (self ):
11241034 # Optional DB-API extension.
11251035 self .cu .execute ("delete from test" )
@@ -1801,12 +1711,62 @@ def test_connection_execute(self):
18011711 result = self .con .execute ("select 5" ).fetchone ()[0 ]
18021712 self .assertEqual (result , 5 , "Basic test of Connection.execute" )
18031713
1804- def test_connection_execute_close_in___getitem__ (self ):
1805- # See CursorTests.test_execute_and_concurrent_close_in___getitem__().
1714+ def test_connection_executemany (self ):
1715+ con = self .con
1716+ con .execute ("create table test(foo)" )
1717+ con .executemany ("insert into test(foo) values (?)" , [(3 ,), (4 ,)])
1718+ result = con .execute ("select foo from test order by foo" ).fetchall ()
1719+ self .assertEqual (result [0 ][0 ], 3 , "Basic test of Connection.executemany" )
1720+ self .assertEqual (result [1 ][0 ], 4 , "Basic test of Connection.executemany" )
1721+
1722+ def test_connection_executescript (self ):
1723+ con = self .con
1724+ con .executescript ("""
1725+ CREATE TABLE test(foo);
1726+ INSERT INTO test(foo) VALUES (5);
1727+ """ )
1728+ result = con .execute ("select foo from test" ).fetchone ()[0 ]
1729+ self .assertEqual (result , 5 , "Basic test of Connection.executescript" )
1730+
1731+
1732+ class ParamsCxCloseInIterMany :
1733+ def __init__ (self , cx ):
1734+ self .cx = cx
1735+
1736+ def __iter__ (self ):
1737+ self .cx .close ()
1738+ return iter ([(1 ,), (2 ,), (3 ,)])
1739+
18061740
1741+ def ParamsCxCloseInNext (cx ):
1742+ for i in range (10 ):
1743+ cx .close ()
1744+ yield (i ,)
1745+
1746+
1747+ class ExecutionConcurrentlyCloseConnectionBaseTests :
1748+ """Tests when execute() and executemany() concurrently close the connection."""
1749+
1750+ def inittest (self ):
1751+ """Return a pair (connection, connection or cursor) to use in tests."""
18071752 cx = sqlite .connect (":memory:" )
18081753 cx .execute ("create table tmp(a number)" )
18091754 self .addCleanup (cx .close )
1755+ return cx , self .interface (cx )
1756+
1757+ def interface (self , connection ):
1758+ """Return a cursor-like interface from a given SQLite3 connection."""
1759+ raise NotImplementedError
1760+
1761+ def test_execute_use___getitem__ (self ):
1762+ # Prevent SIGSEGV when closing the connection while binding parameters.
1763+ #
1764+ # Internally, the connection's state is checked after bind_parameters().
1765+ # Without this check, we would only be aware of the closed connection
1766+ # by calling an sqlite3 function afterwards. However, it is important
1767+ # that we report the error before leaving the execute() call.
1768+ #
1769+ # Regression test for https://github.com/python/cpython/issues/143198.
18101770
18111771 class PT :
18121772 def __getitem__ (self , i ):
@@ -1815,39 +1775,37 @@ def __getitem__(self, i):
18151775 def __len__ (self ):
18161776 return 1
18171777
1778+ cx , cu = self .inittest ()
18181779 msg = r"Cannot operate on a closed database\."
18191780 with self .assertRaisesRegex (sqlite .ProgrammingError , msg ):
1820- cx .execute ("insert into tmp(a) values (?)" , PT ())
1821-
1822- def test_connection_executemany (self ):
1823- con = self .con
1824- con .execute ("create table test(foo)" )
1825- con .executemany ("insert into test(foo) values (?)" , [(3 ,), (4 ,)])
1826- result = con .execute ("select foo from test order by foo" ).fetchall ()
1827- self .assertEqual (result [0 ][0 ], 3 , "Basic test of Connection.executemany" )
1828- self .assertEqual (result [1 ][0 ], 4 , "Basic test of Connection.executemany" )
1781+ cu .execute ("insert into tmp(a) values (?)" , PT ())
18291782
18301783 @subTests ("params_factory" , (ParamsCxCloseInIterMany , ParamsCxCloseInNext ))
1831- def test_connection_executemany_close_in___iter__ (self , params_factory ):
1784+ def test_executemany_use___iter__ (self , params_factory ):
18321785 # Prevent SIGSEGV with iterable of parameters closing the connection.
18331786 # Regression test for https://github.com/python/cpython/issues/143198.
1834- cx = sqlite .connect (":memory:" )
1835- cx .execute ("create table tmp(a number)" )
1836- self .addCleanup (cx .close )
1787+ cx , cu = self .inittest ()
18371788 msg = r"Cannot operate on a closed database\."
18381789 with self .assertRaisesRegex (sqlite .ProgrammingError , msg ):
1839- cx .executemany ("insert into tmp(a) values (?)" , params_factory (cx ))
1790+ cu .executemany ("insert into tmp(a) values (?)" , params_factory (cx ))
18401791
1792+ # The test constructs an iterable of parameters of length 'n'
1793+ # and the connection is closed when we access the j-th one.
1794+ # The iterable is of type 'map' but the test wraps that map
1795+ # with 'iterable_wrapper' to exercise internals.
18411796 @subTests (("j" , "n" ), ([0 , 1 ], [0 , 3 ], [1 , 3 ], [2 , 3 ]))
1842- @subTests ("iterable_wrapper" , (list , lambda x : x ))
1843- def test_connection_executemany_close_in___getitem__ (
1844- self , j , n , iterable_wrapper ,
1845- ):
1846- # See CursorTests.test_executemany_and_concurrent_close_in___getitem__().
1797+ @subTests ("iterable_wrapper" , (list , lambda x : x , lambda x : iter (x )))
1798+ def test_executemany_use___getitem__ (self , j , n , iterable_wrapper ):
1799+ # Prevent SIGSEGV when closing the connection while binding parameters.
1800+ #
1801+ # Internally, the connection's state is checked after bind_parameters().
1802+ # Without this check, we would only be aware of the closed connection
1803+ # by calling an sqlite3 function afterwards. However, it is important
1804+ # that we report the error before leaving executemany() call.
1805+ #
1806+ # Regression test for https://github.com/python/cpython/issues/143198.
18471807
1848- cx = sqlite .connect (":memory:" )
1849- cx .execute ("create table tmp(a number)" )
1850- self .addCleanup (cx .close )
1808+ cx , cu = self .inittest ()
18511809
18521810 class PT :
18531811 def __init__ (self , value ):
@@ -1859,19 +1817,29 @@ def __getitem__(self, i):
18591817 def __len__ (self ):
18601818 return 1
18611819
1862- items = iterable_wrapper (map (PT , range (n )))
18631820 msg = r"Cannot operate on a closed database\."
1821+ items = iterable_wrapper (map (PT , range (n )))
18641822 with self .assertRaisesRegex (sqlite .ProgrammingError , msg ):
1865- cx .executemany ("insert into tmp(a) values (?)" , items )
1823+ cu .executemany ("insert into tmp(a) values (?)" , items )
1824+
1825+
1826+ class ConnectionExecutionConcurrentlyCloseConnectionTests (
1827+ ExecutionConcurrentlyCloseConnectionBaseTests ,
1828+ unittest .TestCase ,
1829+ ):
1830+ """Regression tests for conn.execute() and conn.executemany()."""
1831+ def interface (self , connection ):
1832+ return connection
1833+
1834+
1835+ class CursorExecutionConcurrentlyCloseConnectionTests (
1836+ ExecutionConcurrentlyCloseConnectionBaseTests ,
1837+ unittest .TestCase ,
1838+ ):
1839+ """Regression tests for cursor.execute() and cursor.executemany()."""
1840+ def interface (self , connection ):
1841+ return connection .cursor ()
18661842
1867- def test_connection_executescript (self ):
1868- con = self .con
1869- con .executescript ("""
1870- CREATE TABLE test(foo);
1871- INSERT INTO test(foo) VALUES (5);
1872- """ )
1873- result = con .execute ("select foo from test" ).fetchone ()[0 ]
1874- self .assertEqual (result , 5 , "Basic test of Connection.executescript" )
18751843
18761844
18771845class ClosedConTests (unittest .TestCase ):
0 commit comments