@@ -289,12 +289,12 @@ async def test_parameterized_query_with_special_chars(connection: Connection) ->
289289 [
290290 (
291291 "fb_numeric" ,
292- 'INSERT INTO "test_tbl " VALUES ($1, $2)' ,
292+ 'INSERT INTO "{table} " VALUES ($1, $2)' ,
293293 [(1 , "alice" ), (2 , "bob" ), (3 , "charlie" )],
294294 ),
295295 (
296296 "qmark" ,
297- 'INSERT INTO "test_tbl " VALUES (?, ?)' ,
297+ 'INSERT INTO "{table} " VALUES (?, ?)' ,
298298 [(4 , "david" ), (5 , "eve" ), (6 , "frank" )],
299299 ),
300300 ],
@@ -312,7 +312,7 @@ async def test_executemany_bulk_insert_paramstyles(
312312 firebolt .async_db .paramstyle = paramstyle
313313 # Generate a unique label for this test execution
314314 unique_label = f"test_bulk_insert_async_{ paramstyle } _{ randint (100000 , 999999 )} "
315- table_name = "test_tbl"
315+ table_name = create_drop_test_table_setup_teardown_async
316316
317317 try :
318318 c = connection .cursor ()
@@ -323,7 +323,7 @@ async def test_executemany_bulk_insert_paramstyles(
323323
324324 # Execute bulk insert
325325 await c .executemany (
326- query ,
326+ query . format ( table = table_name ) ,
327327 test_data ,
328328 bulk_insert = True ,
329329 )
@@ -767,3 +767,90 @@ async def test_select_quoted_bigint(
767767 assert result [0 ][0 ] == int (
768768 long_bigint_value
769769 ), "Invalid data returned by fetchall"
770+
771+
772+ async def test_transaction_commit (
773+ connection : Connection , create_drop_test_table_setup_teardown_async : Callable
774+ ) -> None :
775+ """Test transaction SQL statements with COMMIT."""
776+ table_name = create_drop_test_table_setup_teardown_async
777+ async with connection .cursor () as c :
778+ # Test successful transaction with COMMIT
779+ result = await c .execute ("BEGIN TRANSACTION" )
780+ assert result == 0 , "BEGIN TRANSACTION should return 0 rows"
781+
782+ await c .execute (f"INSERT INTO \" { table_name } \" VALUES (1, 'committed')" )
783+
784+ result = await c .execute ("COMMIT TRANSACTION" )
785+ assert result == 0 , "COMMIT TRANSACTION should return 0 rows"
786+
787+ # Verify the data was committed
788+ await c .execute (f'SELECT * FROM "{ table_name } " WHERE id = 1' )
789+ data = await c .fetchall ()
790+ assert len (data ) == 1 , "Committed data should be present"
791+ assert data [0 ] == [
792+ 1 ,
793+ "committed" ,
794+ ], "Committed data should match inserted values"
795+
796+
797+ async def test_transaction_rollback (
798+ connection : Connection , create_drop_test_table_setup_teardown_async : Callable
799+ ) -> None :
800+ """Test transaction SQL statements with ROLLBACK."""
801+ table_name = create_drop_test_table_setup_teardown_async
802+ async with connection .cursor () as c :
803+ # Test transaction with ROLLBACK
804+ result = await c .execute ("BEGIN" ) # Test short form
805+ assert result == 0 , "BEGIN should return 0 rows"
806+
807+ await c .execute (f"INSERT INTO \" { table_name } \" VALUES (1, 'rolled_back')" )
808+
809+ # Verify data is visible within transaction
810+ await c .execute (f'SELECT * FROM "{ table_name } " WHERE id = 1' )
811+ data = await c .fetchall ()
812+ assert len (data ) == 1 , "Data should be visible within transaction"
813+
814+ result = await c .execute ("ROLLBACK" ) # Test short form
815+ assert result == 0 , "ROLLBACK should return 0 rows"
816+
817+ # Verify the data was rolled back
818+ await c .execute (f'SELECT * FROM "{ table_name } " WHERE id = 1' )
819+ data = await c .fetchall ()
820+ assert len (data ) == 0 , "Rolled back data should not be present"
821+
822+
823+ async def test_transaction_cursor_isolation (
824+ connection : Connection , create_drop_test_table_setup_teardown_async : Callable
825+ ) -> None :
826+ """Test that one cursor can't see another's data until it commits."""
827+ table_name = create_drop_test_table_setup_teardown_async
828+ cursor1 = connection .cursor ()
829+ cursor2 = connection .cursor ()
830+
831+ # Start transaction in cursor1 and insert data
832+ result = await cursor1 .execute ("BEGIN TRANSACTION" )
833+ assert result == 0 , "BEGIN TRANSACTION should return 0 rows"
834+
835+ await cursor1 .execute (f"INSERT INTO \" { table_name } \" VALUES (1, 'isolated_data')" )
836+
837+ # Verify cursor1 can see its own uncommitted data
838+ await cursor1 .execute (f'SELECT * FROM "{ table_name } " WHERE id = 1' )
839+ data1 = await cursor1 .fetchall ()
840+ assert len (data1 ) == 1 , "Cursor1 should see its own uncommitted data"
841+ assert data1 [0 ] == [1 , "isolated_data" ], "Cursor1 data should match inserted values"
842+
843+ # Verify cursor2 cannot see cursor1's uncommitted data
844+ await cursor2 .execute (f'SELECT * FROM "{ table_name } " WHERE id = 1' )
845+ data2 = await cursor2 .fetchall ()
846+ assert len (data2 ) == 0 , "Cursor2 should not see cursor1's uncommitted data"
847+
848+ # Commit the transaction in cursor1
849+ result = await cursor1 .execute ("COMMIT TRANSACTION" )
850+ assert result == 0 , "COMMIT TRANSACTION should return 0 rows"
851+
852+ # Now cursor2 should be able to see the committed data
853+ await cursor2 .execute (f'SELECT * FROM "{ table_name } " WHERE id = 1' )
854+ data2 = await cursor2 .fetchall ()
855+ assert len (data2 ) == 1 , "Cursor2 should see committed data after commit"
856+ assert data2 [0 ] == [1 , "isolated_data" ], "Cursor2 should see the committed data"
0 commit comments