Skip to content

Add Thrift-native metadata support - #1641

Open
vuanhphung wants to merge 2 commits into
mainfrom
vu-phung_data/productionize-thrift-native-metadata
Open

Add Thrift-native metadata support#1641
vuanhphung wants to merge 2 commits into
mainfrom
vu-phung_data/productionize-thrift-native-metadata

Conversation

@vuanhphung

@vuanhphung vuanhphung commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds opt-in EnableThriftNativeMetadata support for metadata operations executed through SEA. The server can return Thrift-shaped metadata rows through the Statement Execution API, while the driver preserves the same filtering, normalization, error behavior, and JDBC metadata exposed by the Thrift client.

Supported operations are catalogs, schemas, tables, columns, functions, primary keys, and cross references. Procedures and procedure columns continue to use the existing SEA path.

Request and result flow

DatabaseMetaData request
  → send X-Databricks-Metadata-Operation-Type
  → when enabled and supported, request Thrift-native metadata
  → inspect ResultManifest.is_native_metadata_result
      false / absent → existing SEA SHOW-result processing
      true           → copy native rows and rebuild them with the existing
                       Thrift normalization and JDBC metadata builders

The manifest flag is authoritative: neither the request header nor a native-looking schema changes how a result is processed. This keeps the feature opt-in and preserves legacy behavior when the server does not return a native result.

Requests requiring special handling

  • getTables: the native path sends catalog and types to runtime, then reapplies the JDBC filters to returned rows. This is necessary because runtime treats catalog as a pattern, may return temporary views outside the requested catalog, and does not consistently handle empty or exact table-type filters. SEA native results reuse this processing to preserve existing JDBC-over-Thrift behavior.

    Path Catalog behavior types behavior
    Native GetTables Applies the direct-Thrift exact filter using the original JDBC catalog null accepts every runtime-returned type, an empty array returns no rows, and a non-empty array is matched exactly
    SHOW TABLES SQL is scoped to the resolved catalog null uses the driver's supported default types because SHOW has no JDBC types argument
  • getFunctions: the runtime paths have different catalog semantics:

    Path Search behavior Runtime FUNCTION_CAT Driver handling
    Native GetFunctions Ignores the requested catalog and searches the session catalog Always "" Replaces it with the original DatabaseMetaData.getFunctions catalog, including null
    SHOW FUNCTIONS Searches the requested/resolved catalog Returns the function identifier's catalog Leaves it unchanged

    The driver therefore saves the original JDBC catalog before resolving a catalog for SQL construction and passes that original value only when rebuilding a manifest-confirmed native result. This preserves Thrift compatibility, but it is a column-label correction rather than catalog filtering: native rows can come from catalog A and be labeled as catalog B.

  • getCrossReference: the SQL query narrows only the foreign-key side, so the returned native rows are additionally filtered by the requested parent catalog, schema, and table.

  • Native metadata failures use Thrift-compatible propagation and timeout codes instead of the legacy SHOW-query compatibility fallbacks.

SQLState correction

Key-based metadata validation now reports the applicable SQLState (42000 or 08000) and keeps EXECUTE_STATEMENT_FAILED (1003) as the driver error code. Previously these errors were constructed with DatabricksDriverErrorCode.INVALID_STATE, which incorrectly exposed INVALID_STATE through SQLException.getSQLState().

Tests: mvn spotless:check; focused core metadata suites (331 tests).

@peco-review-bot peco-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Verdict: 1 Low

Looks good — solid, well-tested opt-in feature with strong unit coverage across the native/legacy split, error-code/SQLState alignment, and JSON round-trip. One low-severity note about asymmetric native error propagation (listTables/listColumns propagate errors under native mode, but listFunctions/key-based ops still swallow object-not-found) — worth confirming it's intentional.

@vuanhphung
vuanhphung force-pushed the vu-phung_data/productionize-thrift-native-metadata branch from d535038 to 76205fa Compare August 14, 2026 21:35

@peco-review-bot peco-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Verdict: 1 Medium · 1 Low

Solid, well-tested opt-in feature; native metadata routing delegates cleanly to existing row builders and the SQLState/errorCode alignment looks correct. One medium concern: the fallback-bypass guard keys off the connection flag rather than the actual result, so enabling EnableThriftNativeMetadata changes getColumns/getTables error semantics even for legacy (non-native) responses. One low note on a tautological test.

@vuanhphung
vuanhphung force-pushed the vu-phung_data/productionize-thrift-native-metadata branch from 76205fa to 0a99a83 Compare August 14, 2026 22:04

@peco-review-bot peco-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Verdict: 1 Medium · 2 Low

Solid, well-tested feature addition — opt-in Thrift-native SEA metadata with the manifest flag as the authoritative switch, good coverage across builders and header wiring. Main concerns are around the enabled-flag error-handling path: enabling the flag disables old-DBR SHOW fallbacks for the whole connection (F1), an inconsistent SQLState between null vs empty table (F2), and the native-propagation guard not applied uniformly to key-based ops (F3). All are behavior/consistency questions rather than clear defects.

@vuanhphung
vuanhphung force-pushed the vu-phung_data/productionize-thrift-native-metadata branch 3 times, most recently from 0750722 to 6eac609 Compare August 14, 2026 22:39

@peco-review-bot peco-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Verdict: 1 Low

Solid, well-structured feature with strong test coverage (manifest-flag gating, native vs SHOW paths, SQLState/error-code corrections, and the new post-filtering are all exercised). One low-severity robustness observation about the implicit positional-column contract between native results and the builders; otherwise the correctness, error-propagation, and JSON round-trip changes look correct.

@vuanhphung
vuanhphung force-pushed the vu-phung_data/productionize-thrift-native-metadata branch from 6eac609 to e22b219 Compare August 14, 2026 22:53
Signed-off-by: Vu Anh Phung <vu.phung@databricks.com>
@vuanhphung
vuanhphung force-pushed the vu-phung_data/productionize-thrift-native-metadata branch from e22b219 to 9273799 Compare August 14, 2026 22:54

@peco-review-bot peco-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Verdict: 1 Medium

Solid, well-tested opt-in feature. The manifest-flag-authoritative design is clean and the new unit coverage (native-vs-thrift equivalence, filter preservation, SQLState corrections, header behavior) is thorough. One medium note about inconsistent error-fallback behavior between metadata operations when the flag is enabled.

@peco-review-bot peco-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Verdict: 1 Medium · 1 Low

Solid, well-tested feature addition — the manifest-authoritative native-metadata path, SQLState corrections, and Thrift error-code preservation all carry matching unit coverage. One medium concern: the native error-propagation guard keys off the feature flag rather than the actual result, which can disable the legacy object-not-found/parse-error fallbacks (and make getTables/getColumns throw instead of returning empty) even for non-native SEA results; plus a low note on that policy being applied inconsistently vs. getFunctions.

getResultSet(SQL, session, MetadataOperationType.GET_TABLES), validatedTableTypes);
resultSet, requestedCatalog, resultTableTypes);
} catch (SQLException e) {
if (isThriftNativeMetadataRequested()) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium — The error-propagation guard keys off isThriftNativeMetadataRequested() (i.e. whether the feature flag is enabled) rather than whether the result was actually native. Because the exception is thrown by getResultSet(...) before any manifest is available, there is no way at this point to know if the server actually returned a native result. The PR design states the manifest flag is authoritative and legacy behavior is preserved when the server does not return a native result — but here, once EnableThriftNativeMetadata=1, both listTables (L176) and listColumns (L227) short-circuit all the legacy fallbacks, including isObjectNotFoundException(e).

Concrete consequence: with the flag enabled against a server that does not support native metadata (older DBR that ignores the header and runs the SHOW query, or a genuinely non-existent catalog/object), getTables/getColumns now throw instead of returning an empty ResultSet. Returning empty for object-not-found is the pre-existing JDBC-contract behavior for these calls. Enabling this opt-in flag therefore silently regresses the object-not-found and SHOW ... IN ALL CATALOGS parse-error fallbacks even when the server produced a legacy SEA result. Worth confirming this is the intended tradeoff (and documenting it), or gating the propagation on something closer to "native result was actually returned."

getResultSet(SQL, session, MetadataOperationType.GET_FUNCTIONS);
return metadataResultSetBuilder.getFunctionsResult(
getResultSet(SQL, session, MetadataOperationType.GET_FUNCTIONS), catalog);
resultSet, resultSet.isThriftNativeMetadataResult() ? requestedCatalog : catalog);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 Low — The native error-handling policy is applied inconsistently across the supported operations. listTables (L176) and listColumns (L227) rethrow immediately when isThriftNativeMetadataRequested(), bypassing their isObjectNotFoundException fallback, but listFunctions (here) keeps its isObjectNotFoundException(e) → empty-result fallback with no equivalent native guard. If the intent is Thrift-compatible propagation for native metadata, functions diverges from tables/columns; if returning empty on object-not-found is the desired native behavior, then tables/columns diverge instead. Please confirm the intended policy is uniform, or add a comment explaining why functions is treated differently.

(Anchored to the nearest changed line — see the description for the exact location.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant