Skip to content

FIX: include client_secret hash in SP credential cache key

75ba643
Select commit
Loading
Failed to load commit list.
Draft

FEAT: [WIP] Add ActiveDirectoryServicePrincipal support for bulk copy #576

FIX: include client_secret hash in SP credential cache key
75ba643
Select commit
Loading
Failed to load commit list.
Azure Pipelines / MSSQL-Python-PR-Validation failed May 25, 2026 in 1h 5m 38s

Build #pr-validation-pipeline had test failures

Details

Tests

  • Failed: 1,104 (3.73%)
  • Passed: 27,546 (93.06%)
  • Other: 950 (3.21%)
  • Total: 29,600
Code coverage

  • 7084 of 27204 line covered (26.04%)

Annotations

Check failure on line 2226 in Build log

See this annotation in the file changed.

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

Build log #L2226

Bash exited with code '1'.

Check failure on line 78643 in Build log

See this annotation in the file changed.

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

Build log #L78643

Job cancelled due to worker timeout.

Check failure on line 109 in Build log

See this annotation in the file changed.

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

Build log #L109

Step cancelled due to worker timeout

Check failure on line 110 in Build log

See this annotation in the file changed.

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

Build log #L110

The operation was canceled.

Check failure on line 1 in test_commit_does_not_block_other_python_threads

See this annotation in the file changed.

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

test_commit_does_not_block_other_python_threads

AssertionError: Heartbeat thread was starved across cursor.execute+commit. Got 15 ticks, expected >= 16.
assert 15 >= 16
Raw output
conn_str = 'Server=tcp:127.0.0.1,1433;Database=master;Uid=SA;Pwd=Azure@123!;TrustServerCertificate=yes'

    def test_commit_does_not_block_other_python_threads(conn_str):
        """
        Smoke test for the SQLEndTran GIL-release added to ``Connection::commit``
        and ``Connection::rollback``. A heartbeat must keep ticking across an
        explicit commit on a connection that just executed a (short) WAITFOR.
    
        SQLEndTran on a localhost connection is typically sub-millisecond, so we
        can't reliably measure starvation from it alone. Instead we just assert
        that the commit completes and the heartbeat made meaningful progress
        over the whole transaction, including the WAITFOR.
        """
        mssql_python.pooling(enabled=False)
    
        heartbeat_interval = 0.05
        stop_event = threading.Event()
        tick_count = [0]
        txn_error = []
    
        def heartbeat():
            while not stop_event.is_set():
                tick_count[0] += 1
                time.sleep(heartbeat_interval)
    
        # Open the connection on the main thread *before* starting the heartbeat
        # measurement window. The Python-side wrapper around connect() (connstr
        # parsing, handle alloc, attr setup, etc.) legitimately holds the GIL,
        # and including it in the window would give false starvation signals —
        # especially on macOS CI where scheduler jitter is larger. We want to
        # measure ticks across cursor.execute(WAITFOR) + commit only.
        conn = connect(conn_str)
    
        def run_txn():
            try:
                try:
                    cursor = conn.cursor()
                    try:
                        cursor.execute(WAITFOR_SQL)
                    finally:
                        cursor.close()
                    conn.commit()
                finally:
                    conn.close()
            except Exception as exc:
                txn_error.append(str(exc))
    
        hb = threading.Thread(target=heartbeat, daemon=True)
        tt = threading.Thread(target=run_txn, daemon=True)
    
        hb.start()
        time.sleep(0.1)
        ticks_before = tick_count[0]
    
        tt.start()
        tt.join(timeout=WAITFOR_SECONDS + 30)
        ticks_after = tick_count[0]
        stop_event.set()
        hb.join(timeout=5)
    
        assert not tt.is_alive(), "Transaction thread did not finish in time"
        assert not txn_error, f"Transaction thread error: {txn_error}"
    
        ticks_during = ticks_after - ticks_before
        # 40% of theoretical max gives margin against macOS CI scheduler noise
        # (sleep(0.05) overshoot + GIL re-acquisition latency) while still
        # catching real GIL starvation, which would yield <= ~2 ticks.
        expected_min_ticks = int(WAITFOR_SECONDS / heartbeat_interval * 0.4)
        print(
            f"\n[HEARTBEAT] ticks during WAITFOR+commit: {ticks_during} "
            f"(expected >= {expected_min_ticks})"
        )
>       assert ticks_during >= expected_min_ticks, (
            f"Heartbeat thread was starved across cursor.execute+commit. "
            f"Got {ticks_during} ticks, expected >= {expected_min_ticks}."
        )
E       AssertionError: Heartbeat thread was starved across cursor.execute+commit. Got 15 ticks, expected >= 16.
E       assert 15 >= 16

tests/test_022_concurrent_query_gil_release.py:207: AssertionError

Check failure on line 1 in test_lowercase_concurrent_access_with_db

See this annotation in the file changed.

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

test_lowercase_concurrent_access_with_db

failed on setup with "Failed: Database connection failed: Driver Error: Client unable to establish connection; DDBC Error: [Microsoft]TCP Provider: Error code 0x2726"
Raw output
conn_str = 'Server=tcp:127.0.0.1,1433;Database=master;Uid=SA;Pwd=Azure@123!;TrustServerCertificate=yes'

    @pytest.fixture(scope="module")
    def db_connection(conn_str):
        try:
>           conn = connect(conn_str)
                   ^^^^^^^^^^^^^^^^^

tests/conftest.py:43: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
mssql_python/db_connection.py:55: in connect
    conn = Connection(
mssql_python/connection.py:385: in __init__
    _raise_connection_error(e)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

e = RuntimeError('SQLSTATE:08001:[Microsoft][ODBC Driver 18 for SQL Server]TCP Provider: Error code 0x2726')

    def _raise_connection_error(e: RuntimeError) -> None:
        """Map a RuntimeError from the C++ pybind layer to the correct DB-API 2.0 exception.
    
        Connection::checkError() throws "SQLSTATE:XXXXX:<odbc_message>" so the SQLSTATE
        can be mapped via sqlstate_to_exception(), consistent with cursor-level error handling.
        """
        error_msg = str(e)
        match = _SQLSTATE_RE.match(error_msg)
        if match:
            sqlstate, ddbc_error = match.group(1), match.group(2)
            # Handle malformed SQLSTATE prefix (empty or invalid code)
            if not sqlstate or len(sqlstate) != 5:
                logger.error("Connection error (malformed SQLSTATE): %s", ddbc_error)
                raise OperationalError(
                    driver_error="Connection operation failed",
                    ddbc_error=ddbc_error,
                ) from None
            exc = sqlstate_to_exception(sqlstate, ddbc_error)
            if exc is None:
                logger.error("Unknown SQLSTATE %s, raising DatabaseError", sqlstate)
                raise DatabaseError(
                    driver_error=f"An error occurred with SQLSTATE code: {sqlstate}",
                    ddbc_error=ddbc_error,
                ) from None
            logger.error("Connection error (SQLSTATE %s): %s", sqlstate, ddbc_error)
>           raise exc from None
E           mssql_python.exceptions.OperationalError: Driver Error: Client unable to establish connection; DDBC Error: [Microsoft]TCP Provider: Error code 0x2726

mssql_python/connection.py:89: OperationalError

During handling of the above exception, another exception occurred:

conn_str = 'Server=tcp:127.0.0.1,1433;Database=master;Uid=SA;Pwd=Azure@123!;TrustServerCertificate=yes'

    @pytest.fixture(scope="module")
    def db_connection(conn_str):
        try:
            conn = connect(conn_str)
        except Exception as e:
            if "Timeout error" in str(e):
                print(f"Database connection failed due to Timeout: {e}. Retrying in 60 seconds.")
                time.sleep(60)
                conn = connect(conn_str)
            else:
>               pytest.fail(f"Database connection failed: {e}")
E               Failed: Database connection failed: Driver Error: Client unable to establish connection; DDBC Error: [Microsoft]TCP Provider: Error code 0x2726

tests/conftest.py:50: Failed

Check failure on line 1 in test_decimal_separator_with_db_operations

See this annotation in the file changed.

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

test_decimal_separator_with_db_operations

failed on setup with "Failed: Database connection failed: Driver Error: Client unable to establish connection; DDBC Error: [Microsoft]TCP Provider: Error code 0x2726"
Raw output
conn_str = 'Server=tcp:127.0.0.1,1433;Database=master;Uid=SA;Pwd=Azure@123!;TrustServerCertificate=yes'

    @pytest.fixture(scope="module")
    def db_connection(conn_str):
        try:
>           conn = connect(conn_str)
                   ^^^^^^^^^^^^^^^^^

tests/conftest.py:43: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
mssql_python/db_connection.py:55: in connect
    conn = Connection(
mssql_python/connection.py:385: in __init__
    _raise_connection_error(e)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

e = RuntimeError('SQLSTATE:08001:[Microsoft][ODBC Driver 18 for SQL Server]TCP Provider: Error code 0x2726')

    def _raise_connection_error(e: RuntimeError) -> None:
        """Map a RuntimeError from the C++ pybind layer to the correct DB-API 2.0 exception.
    
        Connection::checkError() throws "SQLSTATE:XXXXX:<odbc_message>" so the SQLSTATE
        can be mapped via sqlstate_to_exception(), consistent with cursor-level error handling.
        """
        error_msg = str(e)
        match = _SQLSTATE_RE.match(error_msg)
        if match:
            sqlstate, ddbc_error = match.group(1), match.group(2)
            # Handle malformed SQLSTATE prefix (empty or invalid code)
            if not sqlstate or len(sqlstate) != 5:
                logger.error("Connection error (malformed SQLSTATE): %s", ddbc_error)
                raise OperationalError(
                    driver_error="Connection operation failed",
                    ddbc_error=ddbc_error,
                ) from None
            exc = sqlstate_to_exception(sqlstate, ddbc_error)
            if exc is None:
                logger.error("Unknown SQLSTATE %s, raising DatabaseError", sqlstate)
                raise DatabaseError(
                    driver_error=f"An error occurred with SQLSTATE code: {sqlstate}",
                    ddbc_error=ddbc_error,
                ) from None
            logger.error("Connection error (SQLSTATE %s): %s", sqlstate, ddbc_error)
>           raise exc from None
E           mssql_python.exceptions.OperationalError: Driver Error: Client unable to establish connection; DDBC Error: [Microsoft]TCP Provider: Error code 0x2726

mssql_python/connection.py:89: OperationalError

During handling of the above exception, another exception occurred:

conn_str = 'Server=tcp:127.0.0.1,1433;Database=master;Uid=SA;Pwd=Azure@123!;TrustServerCertificate=yes'

    @pytest.fixture(scope="module")
    def db_connection(conn_str):
        try:
            conn = connect(conn_str)
        except Exception as e:
            if "Timeout error" in str(e):
                print(f"Database connection failed due to Timeout: {e}. Retrying in 60 seconds.")
                time.sleep(60)
                conn = connect(conn_str)
            else:
>               pytest.fail(f"Database connection failed: {e}")
E               Failed: Database connection failed: Driver Error: Client unable to establish connection; DDBC Error: [Microsoft]TCP Provider: Error code 0x2726

tests/conftest.py:50: Failed

Check failure on line 1 in test_decimal_separator_batch_operations

See this annotation in the file changed.

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

test_decimal_separator_batch_operations

failed on setup with "Failed: Database connection failed: Driver Error: Client unable to establish connection; DDBC Error: [Microsoft]TCP Provider: Error code 0x2726"
Raw output
conn_str = 'Server=tcp:127.0.0.1,1433;Database=master;Uid=SA;Pwd=Azure@123!;TrustServerCertificate=yes'

    @pytest.fixture(scope="module")
    def db_connection(conn_str):
        try:
>           conn = connect(conn_str)
                   ^^^^^^^^^^^^^^^^^

tests/conftest.py:43: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
mssql_python/db_connection.py:55: in connect
    conn = Connection(
mssql_python/connection.py:385: in __init__
    _raise_connection_error(e)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

e = RuntimeError('SQLSTATE:08001:[Microsoft][ODBC Driver 18 for SQL Server]TCP Provider: Error code 0x2726')

    def _raise_connection_error(e: RuntimeError) -> None:
        """Map a RuntimeError from the C++ pybind layer to the correct DB-API 2.0 exception.
    
        Connection::checkError() throws "SQLSTATE:XXXXX:<odbc_message>" so the SQLSTATE
        can be mapped via sqlstate_to_exception(), consistent with cursor-level error handling.
        """
        error_msg = str(e)
        match = _SQLSTATE_RE.match(error_msg)
        if match:
            sqlstate, ddbc_error = match.group(1), match.group(2)
            # Handle malformed SQLSTATE prefix (empty or invalid code)
            if not sqlstate or len(sqlstate) != 5:
                logger.error("Connection error (malformed SQLSTATE): %s", ddbc_error)
                raise OperationalError(
                    driver_error="Connection operation failed",
                    ddbc_error=ddbc_error,
                ) from None
            exc = sqlstate_to_exception(sqlstate, ddbc_error)
            if exc is None:
                logger.error("Unknown SQLSTATE %s, raising DatabaseError", sqlstate)
                raise DatabaseError(
                    driver_error=f"An error occurred with SQLSTATE code: {sqlstate}",
                    ddbc_error=ddbc_error,
                ) from None
            logger.error("Connection error (SQLSTATE %s): %s", sqlstate, ddbc_error)
>           raise exc from None
E           mssql_python.exceptions.OperationalError: Driver Error: Client unable to establish connection; DDBC Error: [Microsoft]TCP Provider: Error code 0x2726

mssql_python/connection.py:89: OperationalError

During handling of the above exception, another exception occurred:

conn_str = 'Server=tcp:127.0.0.1,1433;Database=master;Uid=SA;Pwd=Azure@123!;TrustServerCertificate=yes'

    @pytest.fixture(scope="module")
    def db_connection(conn_str):
        try:
            conn = connect(conn_str)
        except Exception as e:
            if "Timeout error" in str(e):
                print(f"Database connection failed due to Timeout: {e}. Retrying in 60 seconds.")
                time.sleep(60)
                conn = connect(conn_str)
            else:
>               pytest.fail(f"Database connection failed: {e}")
E               Failed: Database connection failed: Driver Error: Client unable to establish connection; DDBC Error: [Microsoft]TCP Provider: Error code 0x2726

tests/conftest.py:50: Failed