Skip to content

fix(csharp): metadata(csharp): GetTables TABLE_TYPE/REMARKS/TABLE_NAME value normalization differs (Thrift REMARKS=UNKNOWN vs SEA "") (#527)#544

Open
peco-engineer-bot[bot] wants to merge 9 commits into
mainfrom
ai/bugfix-527
Open

fix(csharp): metadata(csharp): GetTables TABLE_TYPE/REMARKS/TABLE_NAME value normalization differs (Thrift REMARKS=UNKNOWN vs SEA "") (#527)#544
peco-engineer-bot[bot] wants to merge 9 commits into
mainfrom
ai/bugfix-527

Conversation

@peco-engineer-bot

Copy link
Copy Markdown
Contributor

Summary

Automated fix for #527 — metadata(csharp): GetTables TABLE_TYPE/REMARKS/TABLE_NAME value normalization differs (Thrift REMARKS=UNKNOWN vs SEA "").

Fixed Thrift GetTables value parity (#527): DatabricksStatement.GetTablesAsync now normalizes TABLE_TYPE (null/empty → "TABLE") and REMARKS (null/empty or legacy "UNKNOWN" → "") so the Thrift path matches SEA/JDBC. Verified red→green with a live E2E test against hive_metastore.default (where the Thrift server emits the placeholders), and all 9 SeaMetadataE2ETests pass.

Test plan

  • Added a regression test that reproduces the bug; it fails before the fix
    and passes after. Full suite run on the runner before this PR was opened.

Fixes #527

🤖 Generated by engineer-bot (bug-fix flow)

@peco-engineer-bot peco-engineer-bot Bot added engineer-bot engineer-bot may fix this issue / take over this PR review-bot reviewer-bot reviews this PR labels Jun 22, 2026

@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

Looks mostly sound — the TABLE_TYPE→"TABLE" default matches JDBC and the Thrift-only override is correctly scoped. One medium concern: the case-insensitive "UNKNOWN" REMARKS match can erase legitimate table comments and isn't actually mirrored by JDBC, plus a low note on undisposed Arrow arrays when rebuilding batches. Nit (summary-only): the regression test lives in SeaMetadataE2ETests despite exercising the Thrift path, and as a SkippableFact requiring live credentials it can't fail in unconfigured CI — consistent with existing E2E conventions but worth a comment.

Comment thread csharp/src/DatabricksStatement.cs Outdated
Comment thread csharp/src/DatabricksStatement.cs Outdated
Addresses:
  - #3450274269 at csharp/src/DatabricksStatement.cs:925
  - #3450274274 at csharp/src/DatabricksStatement.cs:906

@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

Targeted, correctly Thrift-scoped fix for #527 (SEA uses a separate statement class, so SEA results are untouched), and the source-array disposal ownership is handled carefully. Main concern is that normalization eagerly buffers the entire GetTables result into memory (medium); two minor robustness notes on the is StringArray fall-through and partial-batch leak on exception.

Comment thread csharp/src/DatabricksStatement.cs Outdated
Comment thread csharp/src/DatabricksStatement.cs Outdated
Comment thread csharp/src/DatabricksStatement.cs Outdated
Addresses:
  - #3450326128 at csharp/src/DatabricksStatement.cs:890
  - #3450326129 at csharp/src/DatabricksStatement.cs:898

@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-contained fix: the Thrift GetTablesAsync path now normalizes TABLE_TYPE (empty → "TABLE") and REMARKS (empty/"UNKNOWN" → "") via a lazy streaming wrapper that preserves incremental consumption and disposes replaced Arrow buffers correctly. Implementation looks correct; my notes are about test enforcement (the regression is a skip-able live E2E test with no deterministic unit coverage), a possible TABLE_NAME scope gap vs. the title, and a live-data-dependent assertion.

Comment thread csharp/test/E2E/StatementExecution/SeaMetadataE2ETests.cs Outdated
Comment thread csharp/src/DatabricksStatement.cs
Comment thread csharp/test/E2E/StatementExecution/SeaMetadataE2ETests.cs Outdated
Addresses:
  - #3450407685 at csharp/test/E2E/StatementExecution/SeaMetadataE2ETests.cs:174
  - #3450407691 at csharp/src/DatabricksStatement.cs:822
  - #3450407692 at csharp/test/E2E/StatementExecution/SeaMetadataE2ETests.cs:196

@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: 2 Low

Looks good — the TABLE_TYPE/REMARKS normalization is correctly scoped to the Thrift path (SEA uses a separate statement class), streams lazily without buffering, and disposes replaced columns without double-disposing reused ones. Two low-severity notes on the E2E test's assertion strength/brittleness; the precise normalization logic is well covered by the new unit tests.

Comment thread csharp/test/E2E/StatementExecution/SeaMetadataE2ETests.cs
Comment thread csharp/test/E2E/StatementExecution/SeaMetadataE2ETests.cs
Addresses:
  - #3450494568 at csharp/test/E2E/StatementExecution/SeaMetadataE2ETests.cs:191
  - #3450494571 at csharp/test/E2E/StatementExecution/SeaMetadataE2ETests.cs:205

@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: 2 Low

Looks good — the TABLE_TYPE/REMARKS normalization is implemented cleanly via a lazy streaming wrapper, ownership/dispose of replaced vs. reused Arrow columns is handled correctly, and the unit tests cover the case-sensitive UNKNOWN handling well. Two low-severity test-robustness notes around the new E2E test (protocol hardcoding vs. the suite's cross-protocol convention, and a hard assertion on live hive_metastore state).

Comment thread csharp/test/E2E/StatementExecution/SeaMetadataE2ETests.cs
Comment thread csharp/test/E2E/StatementExecution/SeaMetadataE2ETests.cs
Addresses:
  - #3450541869 at csharp/test/E2E/StatementExecution/SeaMetadataE2ETests.cs:178
  - #3450541875 at csharp/test/E2E/StatementExecution/SeaMetadataE2ETests.cs:184

@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-documented fix that normalizes Thrift GetTables REMARKS/TABLE_TYPE to match SEA, with lazy/streaming batch rewriting and correct array disposal; SEA's separate GetTablesAsync path is correctly untouched. One low note: the E2E test only checks invariants and can pass without exercising the fix (the unit tests are the real guard).

Comment thread csharp/test/E2E/StatementExecution/SeaMetadataE2ETests.cs
Addresses:
  - #3450586455 at csharp/test/E2E/StatementExecution/SeaMetadataE2ETests.cs:220

@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 solid — the normalization is correctly scoped to the Thrift DatabricksStatement path (SEA uses a separate StatementExecutionStatement), is applied lazily without buffering, preserves row count, and is covered by deterministic unit tests on the pure NormalizeStringColumn logic. One low-severity note inline about the silent non-StringArray fall-through. Two non-blocking observations: (1) issue #527's title also names TABLE_NAME, which this PR explicitly chooses not to normalize — worth confirming TABLE_NAME parity actually holds before the issue is closed; (2) the E2E test self-admittedly can pass green with the fix reverted, but that's acceptable since the unit tests are the authoritative guard.

Comment thread csharp/src/DatabricksStatement.cs
Addresses:
  - #3450631606 at csharp/src/DatabricksStatement.cs:938

@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 — focused, well-documented fix that normalizes TABLE_TYPE/REMARKS on the Thrift GetTables path (the override lives on DatabricksStatement : SparkStatement, so SEA is correctly unaffected), with lazy streaming, preserved row count, and careful disposal that avoids double-dispose. One low concern: the StringArray type guard silently no-ops in Release builds if the column layout ever changes, since the only guardrail is a Debug.Assert. Unit + E2E coverage are appropriate (the E2E test honestly documents itself as a smoke check, not the authoritative guard).

Comment thread csharp/src/DatabricksStatement.cs
Addresses:
  - #3450669941 at csharp/src/DatabricksStatement.cs:951

@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 — clean, well-contained fix. Thrift GetTablesAsync now lazily normalizes TABLE_TYPE (null/empty → "TABLE") and REMARKS (null/empty/case-sensitive "UNKNOWN" → "") to match SEA/JDBC, with careful Arrow buffer disposal, a Debug.Assert + Release-safe Trace warning guardrail for schema drift, and genuine red→green unit coverage. One low-severity note: the fix intentionally omits TABLE_NAME despite the issue title listing it (justified inline). Nit: the regression E2E test lives in SeaMetadataE2ETests.cs but pins thrift — documented in the test, so acceptable.

// Scope note (issue #527): only TABLE_TYPE/REMARKS carry placeholder values that
// diverge between Thrift and SEA. TABLE_NAME is the server-supplied table identifier
// and is returned identically by both paths, so it is intentionally not normalized
// here (rewriting it would risk corrupting a real name).

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 — Issue #527's title lists three divergent columns — TABLE_TYPE, REMARKS, and TABLE_NAME — but this fix only normalizes TABLE_TYPE and REMARKS. The inline comment justifies excluding TABLE_NAME ("server-supplied table identifier ... returned identically by both paths ... rewriting it would risk corrupting a real name"), which is a sound default. Flagging only so the partial scope is a deliberate, visible decision: if #527 actually documented a concrete TABLE_NAME divergence (e.g. casing or qualification differences between Thrift and SEA), this PR does not close that portion and the issue should not be auto-resolved as fully fixed. No code change required if the TABLE_NAME mention in the title was incidental.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is a deliberate, documented scope decision — the fix normalizes only TABLE_TYPE and REMARKS, the two columns that actually carry divergent placeholder values between the Thrift and SEA paths, and the inline scope note explains why TABLE_NAME is intentionally left alone (it's the server-supplied identifier, returned identically by both paths, and rewriting it could corrupt a real name). No code change is warranted on the current evidence. A human should confirm whether issue #527's title mention of TABLE_NAME refers to a real, reproducible Thrift-vs-SEA divergence (e.g. casing or qualification) before resolving #527 as fully fixed; if such a divergence exists, it should be tracked/fixed separately rather than closed by this PR. That verification requires reading the #527 issue body and exercising a live warehouse, which is outside what I can settle on this thread.

/// is nothing to normalize. Row count is preserved because normalization only rewrites
/// values in place and never adds or drops rows.
/// </summary>
private static QueryResult NormalizeTablesResult(QueryResult result)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What is JDBC driver doing? Is it also calling this extra normalize function for Thrift?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good question — to be precise about what is and isn't a "JDBC rule" here:

TABLE_TYPE default → "TABLE": Yes, this mirrors the JDBC driver. JDBC's MetadataResultSetBuilder (the common layer that builds getTables result sets) coerces a null/empty table classification to "TABLE", and it does so in the result-set-building layer regardless of transport — i.e. it applies to the Thrift/hive_metastore path too, not just SEA. That's why our normalization runs after base.GetTablesAsync on the Thrift path: we're matching the same builder-level coercion JDBC performs, rather than relying on the server to send the canonical value.

REMARKS "UNKNOWN"/empty → "": This part is not a JDBC rule — it's parity with SEA, which returns "" for tables without a comment while legacy hive_metastore Thrift returns the literal "UNKNOWN" sentinel (or empty). I deliberately worded the code comment to attribute only the TABLE_TYPE default to JDBC and the REMARKS behavior to SEA, to avoid implying JDBC dictates the REMARKS value.

So: JDBC doesn't call this function (it's our C# driver), but it does perform the equivalent TABLE_TYPE normalization in its own metadata builder across both transports, which is the precedent this change follows. The net effect is that all three — JDBC, SEA, and now our Thrift path — agree on TABLE_TYPE, and our Thrift path additionally matches SEA on REMARKS.

eric-wang-1990 added a commit that referenced this pull request Jul 1, 2026
…xt-repos)

Picks up engine #84: the follow-up flow now wires the .bot/context-repos.yaml
allowlist into its agent (parity with the author phase), so a review-comment
reply can fetch/read reference repos (e.g. databricks-jdbc) to VERIFY a
cross-driver parity claim instead of answering from memory (the gap behind the
#544 JDBC answer). All four workflows bumped in lockstep.

Co-authored-by: Isaac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

engineer-bot engineer-bot may fix this issue / take over this PR review-bot reviewer-bot reviews this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

metadata(csharp): GetTables TABLE_TYPE/REMARKS/TABLE_NAME value normalization differs (Thrift REMARKS=UNKNOWN vs SEA "")

1 participant