Skip to content

[SPARK-58940][SDP][DOC] Add migration notes for Declarative Pipelines case sensitivity - #58222

Open
szehon-ho wants to merge 1 commit into
apache:masterfrom
szehon-ho:docs-sdp-case-sensitivity-migration-note
Open

[SPARK-58940][SDP][DOC] Add migration notes for Declarative Pipelines case sensitivity#58222
szehon-ho wants to merge 1 commit into
apache:masterfrom
szehon-ho:docs-sdp-case-sensitivity-migration-note

Conversation

@szehon-ho

Copy link
Copy Markdown
Member

What changes were proposed in this pull request?

Adds two entries to the "Upgrading from Spark SQL 4.2 to 4.3" section of
docs/sql-migration-guide.md, documenting the behavior change made by
SPARK-58517 (#57722):

  • Declarative Pipelines now honors spark.sql.caseSensitive when inferring and
    evolving pipeline table schemas. Under case-insensitive resolution (the
    default), column names differing only in case identify the same column, so
    flows contribute a single column rather than one per spelling, and the note
    states which spelling survives.
  • All flows writing to one pipeline table must agree on the effective
    spark.sql.caseSensitive, or the update fails with the new
    CONFLICTING_PIPELINE_FLOW_CASE_SENSITIVITY error condition.

Documentation only; no code change.

Why are the changes needed?

SPARK-58517 first ships in 4.3.0 (merged to master, branch-4.x, and
branch-4.3), and the behavior it changed has been in place since 4.1.0:
SchemaMergingUtils.mergeSchemas merged positionally, leaving
StructType.merge's caseSensitive = true default; DataflowGraph.inferredSchema
merged with reduce(SchemaMergingUtils.mergeSchemas); and
SchemaInferenceUtils.diffSchemas keyed columns on exact field names. Users
upgrading from 4.1.x or 4.2.x will see two observable differences that a
migration note should cover:

  • A target schema that previously evolved to carry both spellings, then failed
    later with errors such as COLUMN_ALREADY_EXISTS or AMBIGUOUS_REFERENCE,
    now folds into a single column.
  • A pipeline whose flows disagree on spark.sql.caseSensitive now fails up
    front with CONFLICTING_PIPELINE_FLOW_CASE_SENSITIVITY.

Does this PR introduce any user-facing change?

No. This is a documentation-only change. It documents a user-facing change that
was already made by SPARK-58517.

How was this patch tested?

No tests; documentation only. The error condition names in the notes were
checked against the tree (CONFLICTING_PIPELINE_FLOW_CASE_SENSITIVITY in
error-conditions.json, UNABLE_TO_INFER_PIPELINE_TABLE_SCHEMA in
GraphErrors.scala), as was the "lowest flow identifier wins" rule
(SchemaInferenceUtils.inferSchemaFromFlows sorts by
_.identifier.unquotedString). The link form
declarative-pipelines-programming-guide.html matches the existing link in
docs/index.md.

Was this patch authored or co-authored using generative AI tooling?

Generated-by: Claude Opus 5 (Cursor)

… case sensitivity

SPARK-58517 made Declarative Pipelines honor spark.sql.caseSensitive when
inferring and evolving pipeline table schemas, but described the change as
affecting only unreleased branches, so no migration note was added. The
previous case-sensitive-only behavior did ship in 4.1.x and 4.2.x, and the
change also introduces a new error condition when flows disagree on the
effective value.

@anew anew left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This looks good to me. Thanks @szehon-ho !

@uros-b

uros-b commented Aug 22, 2026

Copy link
Copy Markdown
Member

+1, thank you @szehon-ho and @anew!

- Since Spark 4.3, the Spark-recognized time-travel options (`versionAsOf` and `timestampAsOf`, or the keys configured by `spark.sql.timeTravelVersionKey` and `spark.sql.timeTravelTimestampKey`) are rejected with `UNSUPPORTED_FEATURE.TIME_TRAVEL` on catalog-backed Data Source V2 writes, including table creation and replacement through `DataFrameWriterV2`, because writes must target the current table state rather than a historical version. Previously, Spark passed them to the connector as ordinary write options.
- Since Spark 4.3, `HAVING` is evaluated before window functions when the `SELECT` list also contains generator functions such as `explode`. Previously, window functions could include groups removed by `HAVING` and produce incorrect results.
- Since Spark 4.3, the Spark Connect session errors `INVALID_HANDLE.SESSION_CHANGED`/`SESSION_CLOSED`/`SESSION_NOT_FOUND` carry SQLSTATE `08003` instead of `HY000`; the condition names are unchanged. Code matching these errors on SQLSTATE should match `08003` or class `08`.
- Since Spark 4.3, [Declarative Pipelines](declarative-pipelines-programming-guide.html) honors `spark.sql.caseSensitive` when inferring and evolving pipeline table schemas. Under case-insensitive resolution (the default), column names that differ only in case now identify the same column: flows writing to one table contribute a single column rather than one per spelling, and a column that differs only in case from one already persisted in the target is written to that column instead of being added alongside it. Previously such names were always treated as distinct, producing a table schema that Spark's own resolver could not disambiguate and that could fail later with errors such as `COLUMN_ALREADY_EXISTS` or `AMBIGUOUS_REFERENCE`. When two flows' columns fold together but their types are incompatible, the update now fails at validation with `UNABLE_TO_INFER_PIPELINE_TABLE_SCHEMA`. Where the spellings differ, the surviving one comes from the flow with the lowest identifier, or, when the target table already has the column, its persisted spelling. Set `spark.sql.caseSensitive` to `true` to keep names differing only in case distinct, as before.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Optional since maybe its unnecessarily specific:

when the target table already has the column

Only applies to incremental target tables (STs) and not MVs, which re-infer schema every update. And if a table defined in the pipeline explicitly defines its schema, the spelling there is always respected over the inferred spelling from flows.

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.

6 participants