@@ -139,6 +139,45 @@ def test_rollback_cursor_consistency(self):
139139 con .rollback ()
140140 self .assertEqual (cur .fetchall (), [(1 ,), (2 ,), (3 ,)])
141141
142+ def test_multiple_cursors_and_iternext (self ):
143+ # gh-94028: statements are cleared and reset in cursor iternext.
144+
145+ # Provoke the gh-94028 by using a cursor cache.
146+ CURSORS = {}
147+ def sql (cx , sql , * args ):
148+ cu = cx .cursor ()
149+ cu .execute (sql , args )
150+ CURSORS [id (sql )] = cu
151+ return cu
152+
153+ self .con1 .execute ("create table t(t)" )
154+ sql (self .con1 , "insert into t values (?), (?), (?)" , "u1" , "u2" , "u3" )
155+ self .con1 .commit ()
156+
157+ # On second connection, verify rows are visible, then delete them.
158+ count = sql (self .con2 , "select count(*) from t" ).fetchone ()[0 ]
159+ self .assertEqual (count , 3 )
160+ changes = sql (self .con2 , "delete from t" ).rowcount
161+ self .assertEqual (changes , 3 )
162+ self .con2 .commit ()
163+
164+ # Back in original connection, create 2 new users.
165+ sql (self .con1 , "insert into t values (?)" , "u4" )
166+ sql (self .con1 , "insert into t values (?)" , "u5" )
167+
168+ # The second connection cannot see uncommitted changes.
169+ count = sql (self .con2 , "select count(*) from t" ).fetchone ()[0 ]
170+ self .assertEqual (count , 0 )
171+
172+ # First connection can see its own changes.
173+ count = sql (self .con1 , "select count(*) from t" ).fetchone ()[0 ]
174+ self .assertEqual (count , 2 )
175+
176+ # The second connection can now see the changes.
177+ self .con1 .commit ()
178+ count = sql (self .con2 , "select count(*) from t" ).fetchone ()[0 ]
179+ self .assertEqual (count , 2 )
180+
142181
143182class RollbackTests (unittest .TestCase ):
144183 """bpo-44092: sqlite3 now leaves it to SQLite to resolve rollback issues"""
0 commit comments