Skip to content

PERF: Reduce Python Row indexing overhead - #822

Merged
Jahnvi Thakkar (jahnvi480) merged 2 commits into
mainfrom
jahnvi/python-row-overhead
Sep 28, 2026
Merged

Jahnvi Thakkar (jahnvi480) merged 2 commits into
mainfrom
jahnvi/python-row-overhead

Merge branch 'main' into jahnvi/python-row-overhead

60519f5
Select commit
Loading
Failed to load commit list.
Azure Pipelines / MSSQL-Python-PR-Validation succeeded Sep 28, 2026 in 14m 27s

Build #pr-validation-pipeline had test failures

Details

Tests

  • Failed: 1 (0.00%)
  • Passed: 94,705 (97.75%)
  • Other: 2,177 (2.25%)
  • Total: 96,883
Code coverage

  • 9376 of 11059 lines covered (84.78%)

Annotations

Check failure on line 1 in test_native_destructor_rolls_back_pending_dml[True-False]

See this annotation in the file changed.

@azure-pipelines azure-pipelines / MSSQL-Python-PR-Validation

test_native_destructor_rolls_back_pending_dml[True-False]

Failed: Subprocess test body failed
--- stdout ---

--- stderr ---
Traceback (most recent call last):
  File "<string>", line 66, in <module>
    assert time.monotonic() < deadline, "Native session survived destruction"
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError: Native session survived destruction
Raw output
conn_str = 'Database=TestDB;PWD=***;Server=localhost;TrustServerCertificate=yes;UID=testuser'
use_pool = False, autocommit = True

    @pytest.mark.parametrize("use_pool", [False, True])
    @pytest.mark.parametrize("autocommit", [False, True])
    def test_native_destructor_rolls_back_pending_dml(conn_str, use_pool, autocommit):
        """Native destruction must release transactions, locks, and the server session."""
>       _run_in_subprocess(
            f"use_pool = {use_pool!r}\nautocommit = {autocommit!r}\n" + textwrap.dedent("""
                import gc
                import os
                import sys
                import time
                import uuid
    
                from mssql_python import connect, ddbc_bindings as ddbc, pooling
    
                conn_str = os.environ["DB_CONNECTION_STRING"]
                pool_key = "pytest_native_cleanup_" + uuid.uuid4().hex
                table = pool_key
                pooling(max_size=1, idle_timeout=30)
                observer = connect(conn_str, autocommit=True)
                native = ddbc.Connection(conn_str, use_pool, {}, pool_key, None)
                statement = native.alloc_statement_handle()
                try:
                    assert ddbc.DDBCSQLExecDirect(statement, "SELECT @@SPID") in (0, 1)
                    row = []
                    assert ddbc.DDBCSQLFetchOne(statement, row) in (0, 1)
                    session_id = row[0]
                    statement.free()
    
                    cursor = observer.cursor()
                    try:
                        cursor.execute(
                            "SELECT session_id FROM sys.dm_exec_sessions WHERE session_id = ?",
                            [session_id],
                        )
                    except Exception as exc:
                        if "permission" in str(exc).lower():
                            print("Observer cannot inspect the native session", file=sys.stderr)
                            sys.exit(77)
                        raise
                    if cursor.fetchone() is None:
                        print("Observer cannot inspect the native session", file=sys.stderr)
                        sys.exit(77)
    
                    cursor.execute("SET LOCK_TIMEOUT 1000")
                    cursor.execute(f"CREATE TABLE {table} (id INT)")
                    try:
                        native.set_autocommit(autocommit)
                        statement = native.alloc_statement_handle()
                        sql = f"INSERT INTO {table} VALUES (1)"
                        if autocommit:
                            sql = "BEGIN TRANSACTION; " + sql
                        assert ddbc.DDBCSQLExecDirect(statement, sql) in (0, 1)
                        statement.free()
                        statement = None
                        native = None
                        gc.collect()
    
                        cursor.execute(f"SELECT COUNT(*) FROM {table} WITH (READCOMMITTEDLOCK)")
                        assert cursor.fetchone()[0] == 0, "Destructor committed abandoned work"
    
                        deadline = time.monotonic() + 5
                        while True:
                            cursor.execute(
                                "SELECT session_id FROM sys.dm_exec_sessions WHERE session_id = ?",
                                [session_id],
                            )
                            if cursor.fetchone() is None:
                                break
                            assert time.monotonic() < deadline, "Native session survived destruction"
                            time.sleep(0.05)
    
                        replacement = ddbc.Connection(conn_str, use_pool, {}, pool_key, None)
                        replacement_statement = replacement.alloc_stat
... [The stack trace has been truncated as it exceeded the maximum allowed size. Please refer to the complete log available in the Test Run attachments for full details.]