Skip to content

Spark: Make the view stored-schema coercion configurable - #17453

Closed
bmorck wants to merge 2 commits into
apache:mainfrom
bmorck:spark-view-schema-binding-mode
Closed

Spark: Make the view stored-schema coercion configurable#17453
bmorck wants to merge 2 commits into
apache:mainfrom
bmorck:spark-view-schema-binding-mode

Conversation

@bmorck

@bmorck bmorck commented Jul 31, 2026

Copy link
Copy Markdown

ResolveViews rebuilds a view's output from the stored schema and wraps each column in an UpCast. UpCast only widens, so a view whose stored type is narrower than what its SQL produces cannot be read at all and gets an error like the following:

[CANNOT_UP_CAST_DATATYPE] Cannot up cast id from "DOUBLE" to "BIGINT"

There is currently no way to relax that. Spark's has thespark.sql.legacy.viewSchemaBindingMode and spark.sql.legacy.viewSchemaCompensation confs to relax this behavior on the v1 SessionCatalog view path, but this doesn't apply to v2 views.

This adds spark.sql.iceberg.view.schema-binding-mode, taking its mode names from Spark's ViewSchemaMode:

value coercion
BINDING UpCast(col, storedType) — the current behaviour, and the default
COMPENSATION Cast(col, storedType, ansiEnabled = true) — narrowing allowed
TYPE_EVOLUTION no cast, so the view reports the types its SQL produces

These mirror Spark's SessionCatalog.castColToType behavior.

  1. TYPE_EVOLUTION here is the read-side coercion only and doesn't follow the methodology of Spark's WITH SCHEMA TYPE EVOLUTION, which also syncs the corrected schema back to the catalog, through ViewSyncSchemaToMetaStore. This was an intentional choice since syncing the schema back to the catalog seems wrong to do from a session-level conf, since any reader would then mutate a shared view definition; it would belong with a per-view property, as Spark stores the mode on the view itself.

  2. When the conf is unset, Spark's two legacy confs above are honored instead, reproducing how Spark's SessionCatalog.castColToType treats SchemaUnsupported. The benefit of reading the Spark's spark.sql.legacy.viewSchemaBindingMode is that it provides a single conf to relax the upcast across both v1 and v2 view implementations, but happy to drop the fallback if folks think it is best left out, the Iceberg conf is sufficient as is.

Neither of Spark's confs can select TYPE_EVOLUTION, since there it is a per-view clause rather than a session default. The Iceberg conf takes precedence when both are set. The mode is read on each view resolution rather than cached on the rule, so SET applies within a session.

Tests, in TestViews for each Spark version, over a view whose stored schema declares BIGINT for a column its SQL produces as DOUBLE: the default still fails; COMPENSATION reads the rows as LongType; TYPE_EVOLUTION reads them as DoubleType and keeps the stored column name

ResolveViews rebuilds a view's output from the stored schema, by position,
wrapping each column in an UpCast. UpCast only widens, so a view whose
stored type is narrower than what its SQL produces cannot be read at all,
and there is no way to relax it.

Add spark.sql.iceberg.view.schema-binding-mode, taking its mode names and
coercions from Spark's ViewSchemaMode: BINDING (UpCast, the default and
current behaviour), COMPENSATION (an ANSI cast, allowing narrowing) and
TYPE_EVOLUTION (no cast, so the view reports the types its SQL produces).
All three keep the stored column name and metadata.

When the conf is unset, Spark's spark.sql.legacy.viewSchemaBindingMode and
viewSchemaCompensation are honored instead, reproducing how
SessionCatalog.castColToType treats SchemaUnsupported.
@github-actions github-actions Bot added the spark label Jul 31, 2026
@bmorck bmorck changed the title Spark 4.1, 4.0, 3.5: Make the view stored-schema coercion configurable Spark: Make the view stored-schema coercion configurable Jul 31, 2026
@bmorck
bmorck marked this pull request as ready for review July 31, 2026 16:23
@bryanck

bryanck commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

You should open a PR just for the latest version of Spark, to start with. Once that's merged then we can open PRs to backport to older versions.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants