Skip to content

[7.0 Cherry-pick] Tests | Fix TVP query hint test timeouts against shared Azure SQL DB (#4593) - #4594

Merged
cheenamalhotra merged 1 commit into
release/7.0from
dev/automation/port-tvp-query-hints-timeouts-7.0
Aug 28, 2026
Merged

[7.0 Cherry-pick] Tests | Fix TVP query hint test timeouts against shared Azure SQL DB (#4593)#4594
cheenamalhotra merged 1 commit into
release/7.0from
dev/automation/port-tvp-query-hints-timeouts-7.0

Conversation

@cheenamalhotra

@cheenamalhotra cheenamalhotra commented Aug 25, 2026

Copy link
Copy Markdown
Member

Port of #4593 to release/7.0.

Fixes the TvpQueryHintsTests "Execution Timeout Expired" failures seen in the sqlclient_manual_azure_* legs.

Problem

TvpQueryHintsTests created its table type and stored procedure in the constructor and dropped them in Dispose. xUnit constructs the class once per test, so the 5 tests issued 20 DDL statements against the shared test database. On Azure SQL Database the resulting schema-modification lock contention pushed CREATE/DROP TYPE and CREATE/DROP PROCEDURE past the default 30 second command timeout.

Fix

  • Create the type and procedure once per class via an IClassFixture — 20 DDL statements down to 4.
  • Raise the command timeout to 120s to absorb the contention that remains.
  • Make the fixture exception-safe so a transient failure during setup or teardown cannot orphan the type in the shared database.

The drop guards use TYPE_ID for the user-defined type and OBJECT_ID for the procedure. User-defined types live in sys.types rather than sys.objects, so OBJECT_ID never resolves them — using it there silently skips the drop and leaks the type. Both lookups are parameterized.

Scope note

release/7.0 does not contain the RAII UserDefinedType fixture introduced in #4050, so the OBJECT_ID -> TYPE_ID fixture fix and the fixture parameterization changes from #4593 do not apply to this branch. Its Table/DatabaseUser/ServerLogin fixtures are already parameterized. Only the DDL-volume fix is ported.

release/6.1 and release/6.0 are not affected: they have no TvpQueryHintsTests.cs, and the query-hint scenarios there run inside a single private QueryHintsTest() method in TvpTest.cs that creates the type and procedure once, so there is no DDL amplification.

Validation

Verified against SQL Server 2022:

  • All 5 tests pass.
  • Zero orphaned QHint types or procedures remain after the run.
  • The class runs ~2x faster (131ms -> 64ms) even with no contention.
  • Tests added or updated
  • Public API changes documented (n/a - test-only change)
  • Verified against customer repro
  • Ensure no breaking changes introduced

…ared Azure SQL DB (#4593)

Port of #4593 (main) adapted to release/7.0.

TvpQueryHintsTests created its table type and stored procedure in the
constructor and dropped them in Dispose, so the 5 tests in the class issued
20 DDL statements against the shared test database. On Azure SQL Database
the resulting schema-modification lock contention pushed CREATE/DROP TYPE
and CREATE/DROP PROCEDURE past the default 30 second command timeout,
surfacing as sporadic 'Execution Timeout Expired' failures in the manual
test legs.

Create the type and procedure once per class via an IClassFixture (20 DDL
statements -> 4) and raise the command timeout to 120s to absorb the
contention that remains.

The drop guards use TYPE_ID for the user-defined type and OBJECT_ID for the
procedure. User-defined types live in sys.types rather than sys.objects, so
OBJECT_ID never resolves them; using it there would silently skip the drop
and leak the type into the shared database. Both lookups are parameterized.

Note: release/7.0 does not contain the RAII UserDefinedType fixture from
#4050, so the OBJECT_ID/TYPE_ID fix and the fixture parameterization changes
in #4593 do not apply to this branch; only the DDL-volume fix is ported.

Verified against SQL Server 2022: all 5 tests pass, zero orphaned QHint
types or procedures remain, and the class runs ~2x faster (131ms -> 64ms)
even without contention.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cfc64bc6-a9e6-490d-88b1-4b78d25aa103
@cheenamalhotra
cheenamalhotra requested a review from a team as a code owner August 25, 2026 16:00
Copilot AI lite review requested due to automatic review settings August 25, 2026 16:00
@github-project-automation github-project-automation Bot moved this to To triage in SqlClient Board Aug 25, 2026
@cheenamalhotra cheenamalhotra added this to the 7.0.3 milestone Aug 25, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Ports the TVP query-hint test timeout fix to release/7.0 by reducing shared Azure SQL DDL contention.

Changes:

  • Shares type and procedure setup through a class fixture.
  • Raises the command timeout to 120 seconds.
  • Adds parameterized existence checks and cleanup handling.
Suppressed comments (2)

src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/TvpQueryHintsTests.cs:107

  • The finally blocks guarantee that DropType() is invoked, but not that it succeeds. A timeout or broken connection during either drop can leave the object on the shared database, and Connection.Dispose() immediately removes the only connection available for another cleanup attempt. Since avoiding orphaned objects is the purpose of this fixture, teardown needs best-effort retry/fresh-connection cleanup rather than treating a single failed drop as complete.
                try
                {
                    DropType();
                }
                finally
                {
                    Connection.Dispose();

src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ParameterTest/TvpQueryHintsTests.cs:87

  • If CREATE TYPE completes on the server but ExecuteNonQuery() then reports a timeout or network error, this catch only disposes the connection. The type is left behind in the shared database—the same ambiguous-completion case this fixture is meant to handle. The outer setup cleanup should attempt the guarded type drop before disposing while preserving the original failure.
            catch
            {
                Connection.Dispose();
                throw;

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

cheenamalhotra added a commit to cheenamalhotra/SqlClient that referenced this pull request Aug 25, 2026
… connections

Captures review feedback raised on dotnet#4594 against TvpQueryHintsFixture. Both
findings apply verbatim to main's copy of that fixture, and to every other
consumer of the shared DatabaseObject fixture base, so they are fixed at the
base rather than in one test class:

- A CREATE that fails *after* the server committed it (command timeout, dropped
  connection) left the object behind. Creation failure now makes a best-effort
  drop before rethrowing the original exception.
- A DROP that failed left the object orphaned forever, because names embed a
  GUID and the connection was disposed immediately afterwards. Dispose now
  retries once on a reconnected connection, rethrowing the original exception
  only if the retry also fails.

The retry closes and reopens the existing SqlConnection rather than building a
new one from its connection string: Persist Security Info defaults to false, so
the password is no longer readable once the connection has been opened.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2327ee86-547d-468a-815a-04146f5fd7a5
@cheenamalhotra cheenamalhotra moved this from To triage to In review in SqlClient Board Aug 25, 2026
@cheenamalhotra cheenamalhotra added the Area\Tests Issues that are targeted to tests or test projects label Aug 25, 2026
@cheenamalhotra
cheenamalhotra enabled auto-merge (squash) August 26, 2026 16:26
@cheenamalhotra
cheenamalhotra merged commit 5e4fb10 into release/7.0 Aug 28, 2026
303 of 307 checks passed
@github-project-automation github-project-automation Bot moved this from In review to Done in SqlClient Board Aug 28, 2026
@cheenamalhotra
cheenamalhotra deleted the dev/automation/port-tvp-query-hints-timeouts-7.0 branch August 28, 2026 03:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area\Tests Issues that are targeted to tests or test projects

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants