@@ -10114,7 +10114,11 @@ def test_procedures_result_set_info(cursor, db_connection):
1011410114
1011510115 # Test execution of the procedures to verify they work
1011610116 cursor.execute("EXEC pytest_proc_schema.test_no_results")
10117- assert cursor.fetchall() == [], "test_no_results should return no results"
10117+ # Procedures with no results should have no description and calling fetchall() should raise an error
10118+ assert (
10119+ cursor.description is None,
10120+ ), "test_no_results should have no description (no result set)"
10121+ # Don't call fetchall() on procedures with no results - this is invalid in ODBC
1011810122
1011910123 cursor.execute("EXEC pytest_proc_schema.test_one_result")
1012010124 rows = cursor.fetchall()
@@ -14656,6 +14660,100 @@ def test_fixed_length_binary_type(cursor, db_connection):
1465614660 pytest.fail(f"Fixed-length BINARY test failed: {e}")
1465714661
1465814662
14663+ def test_fetchall_with_integrity_constraint(cursor, db_connection):
14664+ """
14665+ Test that UNIQUE constraint errors are appropriately triggered for multi-row INSERT
14666+ statements that use OUTPUT inserted.
14667+
14668+ This test covers a specific case where SQL Server's protocol has error conditions
14669+ that do not become apparent until rows are fetched, requiring special handling
14670+ in fetchall().
14671+ """
14672+ try:
14673+ # Setup table with unique constraint
14674+ cursor.execute("DROP TABLE IF EXISTS #uniq_cons_test")
14675+ cursor.execute(
14676+ """
14677+ CREATE TABLE #uniq_cons_test (
14678+ id INTEGER NOT NULL IDENTITY,
14679+ data VARCHAR(50) NULL,
14680+ PRIMARY KEY (id),
14681+ UNIQUE (data)
14682+ )
14683+ """
14684+ )
14685+
14686+ # Insert initial row - should work
14687+ cursor.execute(
14688+ "INSERT INTO #uniq_cons_test (data) OUTPUT inserted.id VALUES (?)", ("the data 1",)
14689+ )
14690+ cursor.fetchall() # Complete the operation
14691+
14692+ # Test single row duplicate - should raise IntegrityError
14693+ with pytest.raises(mssql_python.IntegrityError):
14694+ cursor.execute(
14695+ "INSERT INTO #uniq_cons_test (data) OUTPUT inserted.id VALUES (?)", ("the data 1",)
14696+ )
14697+ cursor.fetchall() # Error should be detected here
14698+
14699+ # Insert two valid rows in one statement - should work
14700+ cursor.execute(
14701+ "INSERT INTO #uniq_cons_test (data) OUTPUT inserted.id VALUES (?), (?)",
14702+ ("the data 2", "the data 3"),
14703+ )
14704+ cursor.fetchall()
14705+
14706+ # Verify current state
14707+ cursor.execute("SELECT * FROM #uniq_cons_test ORDER BY id")
14708+ rows = cursor.fetchall()
14709+ expected_before = [(1, "the data 1"), (3, "the data 2"), (4, "the data 3")]
14710+ actual_before = [tuple(row) for row in rows]
14711+ assert actual_before == expected_before
14712+
14713+ # THE CRITICAL TEST: Multi-row INSERT with duplicate values
14714+ # This should raise IntegrityError during fetchall()
14715+ with pytest.raises(mssql_python.IntegrityError):
14716+ cursor.execute(
14717+ "INSERT INTO #uniq_cons_test (data) OUTPUT inserted.id VALUES (?), (?)",
14718+ ("the data 4", "the data 4"),
14719+ ) # Duplicate in same statement
14720+
14721+ # The error should be detected HERE during fetchall()
14722+ cursor.fetchall()
14723+
14724+ # Verify table state after failed multi-row insert
14725+ cursor.execute("SELECT * FROM #uniq_cons_test ORDER BY id")
14726+ rows = cursor.fetchall()
14727+ expected_after = [(1, "the data 1"), (3, "the data 2"), (4, "the data 3")]
14728+ actual_after = [tuple(row) for row in rows]
14729+ assert actual_after == expected_after, "Table should be unchanged after failed insert"
14730+
14731+ # Test timing: execute() should succeed, error detection happens in fetchall()
14732+ try:
14733+ cursor.execute(
14734+ "INSERT INTO #uniq_cons_test (data) OUTPUT inserted.id VALUES (?), (?)",
14735+ ("the data 5", "the data 5"),
14736+ )
14737+ execute_succeeded = True
14738+ except Exception:
14739+ execute_succeeded = False
14740+
14741+ assert execute_succeeded, "execute() should succeed, error detection happens in fetchall()"
14742+
14743+ # fetchall() should raise the IntegrityError
14744+ with pytest.raises(mssql_python.IntegrityError):
14745+ cursor.fetchall()
14746+
14747+ except Exception as e:
14748+ pytest.fail(f"Integrity constraint multi-row test failed: {e}")
14749+ finally:
14750+ # Cleanup
14751+ try:
14752+ cursor.execute("DROP TABLE IF EXISTS #uniq_cons_test")
14753+ except:
14754+ pass
14755+
14756+
1465914757def test_close(db_connection):
1466014758 """Test closing the cursor"""
1466114759 try:
0 commit comments