[SPARK-58311][SQL] Gate generated column values on write with a table capability#57481
Open
szehon-ho wants to merge 1 commit into
Open
[SPARK-58311][SQL] Gate generated column values on write with a table capability#57481szehon-ho wants to merge 1 commit into
szehon-ho wants to merge 1 commit 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.
| * <p> | ||
| * When this capability is present, Spark will: | ||
| * <ul> | ||
| * <li>Auto-compute missing generated column values using the generation expression.</li> |
Contributor
There was a problem hiding this comment.
Please scope this promise to by-name writes. Ordinary by-position resolution rejects a short input before a missing generated column can be filled.
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.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)