@@ -816,3 +816,38 @@ async def test_transaction_rollback(
816816 await c .execute ('SELECT * FROM "test_tbl" WHERE id = 1' )
817817 data = await c .fetchall ()
818818 assert len (data ) == 0 , "Rolled back data should not be present"
819+
820+
821+ async def test_transaction_cursor_isolation (
822+ connection : Connection , create_drop_test_table_setup_teardown_async : Callable
823+ ) -> None :
824+ """Test that one cursor can't see another's data until it commits."""
825+ cursor1 = connection .cursor ()
826+ cursor2 = connection .cursor ()
827+
828+ # Start transaction in cursor1 and insert data
829+ result = await cursor1 .execute ("BEGIN TRANSACTION" )
830+ assert result == 0 , "BEGIN TRANSACTION should return 0 rows"
831+
832+ await cursor1 .execute ("INSERT INTO \" test_tbl\" VALUES (1, 'isolated_data')" )
833+
834+ # Verify cursor1 can see its own uncommitted data
835+ await cursor1 .execute ('SELECT * FROM "test_tbl" WHERE id = 1' )
836+ data1 = await cursor1 .fetchall ()
837+ assert len (data1 ) == 1 , "Cursor1 should see its own uncommitted data"
838+ assert data1 [0 ] == [1 , "isolated_data" ], "Cursor1 data should match inserted values"
839+
840+ # Verify cursor2 cannot see cursor1's uncommitted data
841+ await cursor2 .execute ('SELECT * FROM "test_tbl" WHERE id = 1' )
842+ data2 = await cursor2 .fetchall ()
843+ assert len (data2 ) == 0 , "Cursor2 should not see cursor1's uncommitted data"
844+
845+ # Commit the transaction in cursor1
846+ result = await cursor1 .execute ("COMMIT TRANSACTION" )
847+ assert result == 0 , "COMMIT TRANSACTION should return 0 rows"
848+
849+ # Now cursor2 should be able to see the committed data
850+ await cursor2 .execute ('SELECT * FROM "test_tbl" WHERE id = 1' )
851+ data2 = await cursor2 .fetchall ()
852+ assert len (data2 ) == 1 , "Cursor2 should see committed data after commit"
853+ assert data2 [0 ] == [1 , "isolated_data" ], "Cursor2 should see the committed data"
0 commit comments