[SPARK-58311][SQL] Gate generated column values on write with a table capability#57481
Closed
szehon-ho wants to merge 2 commits into
Closed
[SPARK-58311][SQL] Gate generated column values on write with a table capability#57481szehon-ho wants to merge 2 commits into
szehon-ho wants to merge 2 commits into
Conversation
… capability Move the gate that decides whether Spark auto-fills and enforces generated column values on a DSv2 write from the catalog-level `TableCatalogCapability.SUPPORT_GENERATED_COLUMN_ON_WRITE` to a new per-table `TableCapability.GENERATE_COLUMN_VALUES_ON_WRITE`.
cloud-fan
reviewed
Jul 24, 2026
cloud-fan
left a comment
Contributor
There was a problem hiding this comment.
0 blocking, 1 non-blocking, 0 nits.
The implementation is coherent, but the new public capability contract promises broader auto-fill behavior than the resolver currently provides.
Correctness (1)
- sql/catalyst/src/main/java/org/apache/spark/sql/connector/catalog/TableCapability.java:117: The capability contract overstates auto-fill behavior. Ordinary by-position writes reject a short input before resolving generated expressions, so this bullet should scope auto-computation to by-name writes (or the implementation should add equivalent by-position support). -- see inline
Verification
Traced both resolution modes in TableOutputResolver: by-name resolution substitutes a missing generated expression, while ordinary by-position resolution rejects a short input before column resolution.
PR description suggestions
- Clarify that missing generated values are currently auto-filled for by-name writes, while ordinary by-position writes still require matching arity.
uros-b
approved these changes
Jul 25, 2026
uros-b
left a comment
Member
There was a problem hiding this comment.
Thank you @szehon-ho and @cloud-fan!
szehon-ho
added a commit
that referenced
this pull request
Jul 25, 2026
… capability ### What changes were proposed in this pull request? This PR moves the gate that decides whether Spark auto-fills and enforces generated column values on a DSv2 write from a **catalog-level** capability to a **table-level** capability. Specifically: - Adds `TableCapability.GENERATE_COLUMN_VALUES_ON_WRITE`, checked via `Table.capabilities()`. - Removes `TableCatalogCapability.SUPPORT_GENERATED_COLUMN_ON_WRITE` (added by SPARK-57644 and still unreleased). - `GeneratedColumn.supportsGeneratedColumnsOnWrite` now takes a `Table` and checks the table's capabilities instead of the `TableCatalog`'s. - Updates the four call sites to consult the table: - `Analyzer` (exposing generation-expression metadata to `TableOutputResolver` so missing values are auto-filled), - `ResolveTableConstraints` (adding the generated-column `CheckInvariant` constraints), - `RewriteRowLevelCommand` (blocking MERGE/UPDATE), - `ResolveWriteToStream` (blocking streaming writes). - Test infra: the in-memory test table advertises the new capability, gated by a `generate-column-values-on-write` table property (default `true`), mirroring the existing `accept-any-schema` / `auto-schema-evolution` toggles. ### Why are the changes needed? Whether Spark should generate/enforce generated column values is a property of an individual **table**, not of the whole **catalog**. A single catalog can expose tables from formats or protocol versions with differing generated-column support, so a catalog-wide flag is too coarse. This also aligns with how Delta Lake gates the feature: it is gated per-table on the table's protocol. `GeneratedColumn.satisfyGeneratedColumnProtocol(protocol)` returns `protocol.isFeatureSupported(GeneratedColumnsTableFeature)` -- i.e. it checks whether the `GeneratedColumnsTableFeature` is enabled in that specific table's protocol. A per-table `TableCapability` is the natural DSv2 analogue and matches the existing pattern for other per-table write behaviors (`BATCH_WRITE`, `OVERWRITE_DYNAMIC`, `TRUNCATE`, ...). ### Does this PR introduce _any_ user-facing change? No change relative to a released version. The catalog capability being removed (`SUPPORT_GENERATED_COLUMN_ON_WRITE`) was introduced by SPARK-57644 and has not shipped in any release, so this only reshapes an unreleased API within the development branch. Connectors opt in by having their `Table` advertise `TableCapability.GENERATE_COLUMN_VALUES_ON_WRITE`. Auto-filling missing generated column values applies to by-name writes; ordinary by-position writes must still provide a value for every table column. ### How was this patch tested? `GeneratedColumnWriteSuite` (69 tests) passes. The existing "connector without the write capability does not auto-fill or enforce generated columns" coverage is retained (renamed to "table without write capability ..."), now driven by creating a table with `TBLPROPERTIES ('generate-column-values-on-write' = 'false')` instead of a dedicated no-capability catalog. ### Was this patch authored or co-authored using generative AI tooling? Generated-by: Cursor (Opus 4.8) Closes #57481 from szehon-ho/dsv2-generated-column-gate. Authored-by: Szehon Ho <szehon.apache@gmail.com> Signed-off-by: Szehon Ho <szehon.apache@gmail.com> (cherry picked from commit 7865fb8) Signed-off-by: Szehon Ho <szehon.apache@gmail.com>
Member
Author
Member
Author
|
Thanks @uros-b , @cloud-fan for review! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changes were proposed in this pull request?
This PR moves the gate that decides whether Spark auto-fills and enforces generated column values on a DSv2 write from a catalog-level capability to a table-level capability.
Specifically:
TableCapability.GENERATE_COLUMN_VALUES_ON_WRITE, checked viaTable.capabilities().TableCatalogCapability.SUPPORT_GENERATED_COLUMN_ON_WRITE(added by SPARK-57644 and still unreleased).GeneratedColumn.supportsGeneratedColumnsOnWritenow takes aTableand checks the table's capabilities instead of theTableCatalog's.Analyzer(exposing generation-expression metadata toTableOutputResolverso missing values are auto-filled),ResolveTableConstraints(adding the generated-columnCheckInvariantconstraints),RewriteRowLevelCommand(blocking MERGE/UPDATE),ResolveWriteToStream(blocking streaming writes).generate-column-values-on-writetable property (defaulttrue), mirroring the existingaccept-any-schema/auto-schema-evolutiontoggles.Why are the changes needed?
Whether Spark should generate/enforce generated column values is a property of an individual table, not of the whole catalog. A single catalog can expose tables from formats or protocol versions with differing generated-column support, so a catalog-wide flag is too coarse.
This also aligns with how Delta Lake gates the feature: it is gated per-table on the table's protocol.
GeneratedColumn.satisfyGeneratedColumnProtocol(protocol)returnsprotocol.isFeatureSupported(GeneratedColumnsTableFeature)-- i.e. it checks whether theGeneratedColumnsTableFeatureis enabled in that specific table's protocol. A per-tableTableCapabilityis the natural DSv2 analogue and matches the existing pattern for other per-table write behaviors (BATCH_WRITE,OVERWRITE_DYNAMIC,TRUNCATE, ...).Does this PR introduce any user-facing change?
No change relative to a released version. The catalog capability being removed (
SUPPORT_GENERATED_COLUMN_ON_WRITE) was introduced by SPARK-57644 and has not shipped in any release, so this only reshapes an unreleased API within the development branch. Connectors opt in by having theirTableadvertiseTableCapability.GENERATE_COLUMN_VALUES_ON_WRITE. Auto-filling missing generated column values applies to by-name writes; ordinary by-position writes must still provide a value for every table column.How was this patch tested?
GeneratedColumnWriteSuite(69 tests) passes. The existing "connector without the write capability does not auto-fill or enforce generated columns" coverage is retained (renamed to "table without write capability ..."), now driven by creating a table withTBLPROPERTIES ('generate-column-values-on-write' = 'false')instead of a dedicated no-capability catalog.Was this patch authored or co-authored using generative AI tooling?
Generated-by: Cursor (Opus 4.8)