Skip to content

Cache sp_columns_170 availability per connection in getColumns() - #3019

Open
Muskan Gupta (muskan124947) wants to merge 3 commits into
mainfrom
users/muskgupta/sp_columns_170_cache
Open

Cache sp_columns_170 availability per connection in getColumns()#3019
Muskan Gupta (muskan124947) wants to merge 3 commits into
mainfrom
users/muskgupta/sp_columns_170_cache

Conversation

@muskan124947

Copy link
Copy Markdown
Contributor

sp_columns_170 only exists on SQL Server 2025 and later. getColumns() probed it on every call, so on older servers each call produced a failed server request before falling back to sp_columns_100. Importing a catalog of N tables therefore issued N failed requests.

Availability is a property of the server, so the outcome is now cached on SQLServerConnection as a tri-state flag (null = undetermined, TRUE = present, FALSE = absent). sp_columns_170 is probed at most once per connection and later calls on a server without it go straight to sp_columns_100.

The try/catch around the probe is kept so the driver still recovers if the procedure is unavailable unexpectedly. The flag is only cached as FALSE when the server explicitly reports error 2812 (Could not find stored procedure). Any other failure leaves the state undetermined so a transient error cannot permanently downgrade the connection to sp_columns_100 and silently drop metadata for types that only sp_columns_170 reports.

Also stop wrapping buildAzureDWResultSet() in the fallback try block on Azure DW, where a failure while building the result set incorrectly triggered a fallback, and factor the duplicated prepare/bind/execute blocks into helpers.

Fixes #3013

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

This PR improves SQLServerDatabaseMetaData#getColumns() by avoiding repeated failed attempts to call sp_columns_170 on servers where it does not exist (SQL Server < 2025), caching the procedure’s availability as a per-connection tri-state on SQLServerConnection, and cleaning up the Azure DW fallback flow.

Changes:

  • Cache sp_columns_170 availability per physical connection (tri-state) to avoid repeated probe failures and reduce server load.
  • Refactor duplicated prepare/bind/execute logic into helpers for both non-Azure DW and Azure DW code paths.
  • Add tests intended to validate the “probe at most once per connection” behavior and connection scoping of the cache.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java Implements per-connection caching and refactors getColumns() execution/fallback logic (including Azure DW handling).
src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java Adds a volatile tri-state flag with accessor methods to cache sp_columns_170 support per connection.
src/test/java/com/microsoft/sqlserver/jdbc/databasemetadata/DatabaseMetaDataTest.java Adds tests to validate probing/caching behavior and connection scoping for sp_columns_170.
Suppressed comments (1)

src/test/java/com/microsoft/sqlserver/jdbc/databasemetadata/DatabaseMetaDataTest.java:2103

  • This assertion assumes the sp_columns_170 support flag is always decided after the first getColumns() call. However, recordSpColumns170Failure intentionally leaves the state undetermined (null) for non-2812 failures (timeouts/transient errors), so this can be flaky. Consider asserting the cached value only when a "procedure not found" fallback was observed.
            // Once the probe has run, the connection must have a decided state rather than remaining undetermined.
            assertNotNull(getSpColumns170SupportedFlag(sqlServerConnection),
                    "sp_columns_170 support should be cached on the connection after the first getColumns() call");

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

Comment thread src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java Outdated
@codecov

codecov Bot commented Aug 14, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 52.05479% with 35 lines in your changes missing coverage. Please review.
✅ Project coverage is 60.29%. Comparing base (34285fd) to head (ee5383c).

Files with missing lines Patch % Lines
...soft/sqlserver/jdbc/SQLServerDatabaseMetaData.java 49.27% 31 Missing and 4 partials ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #3019      +/-   ##
============================================
- Coverage     60.74%   60.29%   -0.46%     
+ Complexity     5332     5183     -149     
============================================
  Files           153      153              
  Lines         36679    36709      +30     
  Branches       6733     6738       +5     
============================================
- Hits          22282    22132     -150     
- Misses        10738    10759      +21     
- Partials       3659     3818     +159     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@machavan Mahendra Chavan (machavan) added this to the 13.6.0 milestone Aug 14, 2026
sp_columns_170 only exists on SQL Server 2025 and later. getColumns() probed
it on every call, so on older servers each call produced a failed server
request before falling back to sp_columns_100. Importing a catalog of N tables
therefore issued N failed requests.

Availability is a property of the server, so the outcome is now cached on
SQLServerConnection as a tri-state flag (null = undetermined, TRUE = present,
FALSE = absent). sp_columns_170 is probed at most once per connection and
later calls on a server without it go straight to sp_columns_100.

The try/catch around the probe is kept so the driver still recovers if the
procedure is unavailable unexpectedly. The flag is only cached as FALSE when
the server explicitly reports error 2812 (Could not find stored procedure).
Any other failure leaves the state undetermined so a transient error cannot
permanently downgrade the connection to sp_columns_100 and silently drop
metadata for types that only sp_columns_170 reports.

Also stop wrapping buildAzureDWResultSet() in the fallback try block on Azure
DW, where a failure while building the result set incorrectly triggered a
fallback, and factor the duplicated prepare/bind/execute blocks into helpers.

Fixes #3013

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 6d6a904a-1e9d-44f7-90bf-5a251e71dc30
Keep the cached sp_columns_170 state unchanged for failures other than error 2812, so a transient error no longer discards support that has already been proven.

Count only the procedure-not-found fallback in the probe test, and read the cached state through the package private accessor instead of the private field.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 6d6a904a-1e9d-44f7-90bf-5a251e71dc30
Adds two tests that seed the connection-scoped sp_columns_170 state to
FALSE and verify getColumns() goes straight to sp_columns_100, on both
the regular SQL Server path and the Azure DW path.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 6d6a904a-1e9d-44f7-90bf-5a251e71dc30
@muskan124947
Muskan Gupta (muskan124947) force-pushed the users/muskgupta/sp_columns_170_cache branch from 53ca356 to ee5383c Compare August 21, 2026 09:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

getColumns() probes sp_columns_170 unconditionally, producing one failed server request per table on every server below SQL Server 2025

3 participants