Skip to content

[SPARK-58118][SDP] Allow user-specified AUTO CDC schema to omit the reserved metadata column - #57644

Open
naveenp2708 wants to merge 2 commits into
apache:masterfrom
naveenp2708:SPARK-58118-omit-reserved-column
Open

[SPARK-58118][SDP] Allow user-specified AUTO CDC schema to omit the reserved metadata column#57644
naveenp2708 wants to merge 2 commits into
apache:masterfrom
naveenp2708:SPARK-58118-omit-reserved-column

Conversation

@naveenp2708

@naveenp2708 naveenp2708 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

What changes were proposed in this pull request?

An AUTO CDC (SCD1) flow appends a reserved metadata column (__spark_autocdc_metadata) to its output schema. Because validateUserSpecifiedSchemas required the declared schema to exactly equal the inferred schema, a user declaring a schema on an AUTO CDC streaming table was forced to also declare this engine-internal column. This makes two changes so the user schema can describe just the logical data columns:

  1. GraphValidations.validateUserSpecifiedSchemas accepts a declared schema that differs from the inferred schema only by the reserved AUTO CDC metadata column(s). Any other mismatch still fails, and a schema that does declare the reserved column stays accepted.
  2. DatasetManager.materializeTable appends the reserved metadata column(s) to the created table's schema when a user schema omits them, so the SCD1 MERGE resolves them at runtime.

Why are the changes needed?

The reserved column is an engine implementation detail; users should not need to know its name or shape. Relaxing validation alone is insufficient because materializeTable uses the user schema verbatim, so the target table would be created without the column and the MERGE would fail at runtime with UNRESOLVED_COLUMN.

Does this PR introduce any user-facing change?

Yes. A user-specified schema on an AUTO CDC streaming table may now omit the reserved __spark_autocdc_metadata column.

How was this patch tested?

UserSpecifiedSchemaValidationSuite: data-only schema accepted (implicit and named flows), wrong data columns still rejected, declaring the metadata column still accepted.

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

No

…eserved metadata column

### What changes were proposed in this pull request?
An AUTO CDC (SCD1) flow appends a reserved metadata column (__spark_autocdc_metadata) to its
output schema. Because validateUserSpecifiedSchemas required the declared schema to exactly equal
the inferred schema, a user declaring a schema on an AUTO CDC streaming table was forced to also
declare this engine-internal column. This makes two changes so the user schema can describe just
the logical data columns:

1. GraphValidations.validateUserSpecifiedSchemas accepts a declared schema that differs from the
   inferred schema only by the reserved AUTO CDC metadata column(s). Any other mismatch still
   fails, and a schema that does declare the reserved column stays accepted.
2. DatasetManager.materializeTable appends the reserved metadata column(s) to the created table's
   schema when a user schema omits them, so the SCD1 MERGE resolves them at runtime.

### Why are the changes needed?
The reserved column is an engine implementation detail; users should not need to know its name or
shape. Relaxing validation alone is insufficient because materializeTable uses the user schema
verbatim, so the target table would be created without the column and the MERGE would fail at
runtime with UNRESOLVED_COLUMN.

### Does this PR introduce any user-facing change?
Yes. A user-specified schema on an AUTO CDC streaming table may now omit the reserved
__spark_autocdc_metadata column.

### How was this patch tested?
UserSpecifiedSchemaValidationSuite: data-only schema accepted (implicit and named flows), wrong
data columns still rejected, declaring the metadata column still accepted.

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

@HyukjinKwon HyukjinKwon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

0 blocking, 0 non-blocking, 1 nit.
Clean UX fix that stops a leaky engine-internal column from being required; one optional micro-nit.

Nits: 1 minor item (see inline comments).

Verification

Validation and materialization use the same AutoCdcMergeFlow reserved-field helpers (reservedFields/stripReservedFields on AutoCdcReservedNames.prefix, exact complements), so the accepted schema and the materialized table agree; stripReservedFields only removes reserved fields, so a genuine logical-column mismatch still fails validation, and filterNot prevents duplication if the user did declare the reserved column.

// so the created table matches what the AUTO CDC MERGE writes at runtime.
val omittedReservedFields = AutoCdcMergeFlow
.reservedFields(resolvedDataflowGraph.inferredSchema(table.identifier))
.filterNot(f => ss.fieldNames.contains(f.name))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Optional micro-nit: ss.fieldNames is recomputed (fresh Array) with a linear contains per reserved field. val specifiedNames = ss.fieldNames.toSet before the filterNot makes membership O(1). Materialization-time only, so take-it-or-leave-it.

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 call @HyukjinKwon , done. Switched ss.fieldNames to a Set before the filterNot.

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.

2 participants