Skip to content

[FLINK-40496][table-planner] Apply append-only column rules consistently when altering a materialized table - #29034

Merged
AHeise merged 1 commit into
apache:masterfrom
AHeise:FLINK-40496-coa-mt-column-position
Sep 2, 2026
Merged

[FLINK-40496][table-planner] Apply append-only column rules consistently when altering a materialized table#29034
AHeise merged 1 commit into
apache:masterfrom
AHeise:FLINK-40496-coa-mt-column-position

Conversation

@AHeise

@AHeise AHeise commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

What is the purpose of the change

CREATE OR ALTER MATERIALIZED TABLE derived its column changes differently from ALTER ... AS and did not surface a query-driven column reorder to the append-only validation, so reordering existing columns behaved inconsistently: silently applied when the query text was unchanged (rewriting the stored column order with no error), rejected otherwise. The silent path left the stored schema disagreeing with the query and miscompiled the positional refresh INSERT.

Given users_shops = (user_id, shop_id, ds, order_cnt):

CREATE OR ALTER MATERIALIZED TABLE users_shops (shop_id, user_id, ds, order_cnt)
  AS SELECT user_id, shop_id, ds, COUNT(order_id) AS order_cnt FROM ...

The bare column list reorders the columns but the query text is unchanged, so no ModifyDefinitionQuery is produced and the append-only check is skipped — before this change the reorder was applied silently.

Brief change log

  • CREATE OR ALTER computes its column diff from the query (via validateAndExtractColumnChanges), positioning old columns by their rank among the columns that survive into the new schema so retained non-persisted columns do not skew the diff.
  • The append-only column rules apply to every query-carrying alter (CREATE OR ALTER and ALTER ... AS): existing columns may not be reordered or retyped even when the query text is unchanged. Metadata-only DDL alters are unaffected.
  • Second commit: ALTER ... AS and CREATE OR ALTER now share one diff implementation; buildSchemaTableChanges is removed.

Verifying this change

Added and updated tests:

  • MaterializedTableStatementITCaseCREATE OR ALTER and ALTER ... AS reject reordering existing columns end-to-end, including a bare-list reorder with an unchanged query.
  • SqlMaterializedTableNodeToOperationConverterTest, SqlNodeToOperationSqlCreateOrAlterMaterializedTableConverterTest, AlterMaterializedTableAsQueryOperationValidationTest, ValidateAndExtractColumnChangesTest — operation- and guard-level coverage of the reject/accept cases.

Does this pull request potentially affect one of the following parts:

  • Dependencies (does it add or upgrade a dependency): no
  • The public API, i.e., is any changed class annotated with @Public(Evolving): no
  • The serializers: no
  • The runtime per-record code paths (performance sensitive): no
  • Anything that affects deployment or recovery: JobManager (and its components), Checkpointing, Kubernetes/Yarn, ZooKeeper: no
  • The S3 file system connector: no

Documentation

  • Does this pull request introduce a new feature? no
  • If yes, how is the feature documented? not applicable

Was generative AI tooling used to co-author this PR?
  • Yes (please specify the tool below)

Generated-by: Claude Code (Claude Opus 4.8)

@flinkbot

flinkbot commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

CI report:

Bot commands The @flinkbot bot supports the following commands:
  • @flinkbot run azure re-run the last Azure build

@AHeise
AHeise force-pushed the FLINK-40496-coa-mt-column-position branch 2 times, most recently from f49fb94 to bdac042 Compare August 28, 2026 13:00
@AHeise
AHeise marked this pull request as ready for review August 28, 2026 13:01
@AHeise
AHeise marked this pull request as draft August 28, 2026 13:02
@AHeise
AHeise force-pushed the FLINK-40496-coa-mt-column-position branch 3 times, most recently from 446af6c to 0831111 Compare August 28, 2026 14:44
@AHeise
AHeise marked this pull request as ready for review August 28, 2026 16:06
@AHeise
AHeise marked this pull request as draft August 31, 2026 20:48
@AHeise
AHeise force-pushed the FLINK-40496-coa-mt-column-position branch from 0831111 to 07a6c29 Compare September 1, 2026 10:06
@AHeise AHeise changed the title [FLINK-40496][table-planner] CREATE OR ALTER MATERIALIZED TABLE honors query column position [FLINK-40496][table-planner] Apply append-only column rules consistently when altering a materialized table Sep 1, 2026
@AHeise
AHeise force-pushed the FLINK-40496-coa-mt-column-position branch 2 times, most recently from 85c03d2 to 9167191 Compare September 1, 2026 13:46
@AHeise
AHeise marked this pull request as ready for review September 1, 2026 15:40
@AHeise
AHeise force-pushed the FLINK-40496-coa-mt-column-position branch from 9167191 to 745323d Compare September 1, 2026 15:45
List<TableChange> tableChanges =
new ArrayList<>(
MaterializedTableUtils.buildSchemaTableChanges(oldSchema, newSchema));
MaterializedTableUtils.validateAndExtractColumnChanges(

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.

Unifies both schema changing parts: ALTER ... AS and CoA.

@AHeise
AHeise force-pushed the FLINK-40496-coa-mt-column-position branch from 745323d to 16d0dc3 Compare September 2, 2026 05:54

@raminqaf raminqaf 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.

Thanks for handling this @AHeise! I left some comments!

Comment on lines -852 to -858
TestSpec.of(
"ALTER MATERIALIZED TABLE base_mtbl AS SELECT a, b, c, CAST('d' AS STRING) AS d FROM t3",
"When modifying the query of a materialized table, currently only support "
+ "appending columns at the end of original schema, dropping, "
+ "renaming, and reordering columns are not supported.\n"
+ "Column mismatch at position 4: Original column is [`d` STRING], "
+ "but new column is [`d` STRING NOT NULL]."),

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.

A bit confused here why this case was removed. If I understood correctly, we are replacing a nullable column with a non-nullable column. Did you removed it because it is a valid case now?

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.

Yes — tolerated now, not rejected. That case tightened nullability (nullable -> NOT NULL), which the unified diff treats as a query-inference artifact: CAST('123' AS STRING) AS d yields a NOT NULL type though the user changed nothing about d's declared type, so rejecting it would block legitimate query edits. The stored (nullable) type is kept — no change emitted, hence no error. The unsafe direction (NOT NULL -> nullable) is still rejected; see typeChanged and the loosen/tighten specs in ValidateAndExtractColumnChangesTest.

@github-actions github-actions Bot added the community-reviewed PR has been reviewed by the community. label Sep 2, 2026
@AHeise
AHeise force-pushed the FLINK-40496-coa-mt-column-position branch from 16d0dc3 to 72297fb Compare September 2, 2026 08:41
…tly when altering a materialized table

CREATE OR ALTER derived its column changes from a different diff implementation than ALTER ... AS and did not surface a query-driven column reorder to the append-only validation, so reordering existing columns behaved inconsistently: it was silently applied when the query text was unchanged - rewriting the stored column order with no error - and rejected otherwise. The silent path left the stored schema disagreeing with the query, which then miscompiled the positional refresh INSERT.

Route both statements through one diff (validateAndExtractColumnChanges, dropping buildSchemaTableChanges), computing the CREATE OR ALTER diff from the query the same way ALTER ... AS does and positioning old columns by their rank among the columns that survive into the new schema so retained non-persisted columns do not skew it. Apply the append-only rules to every query-carrying alter regardless of whether the query text changed, so reordering or retyping existing columns is rejected consistently; a query-inferred nullability change is treated directionally - a tightening flip such as STRING to STRING NOT NULL is tolerated as an inference artifact while a loosening flip from NOT NULL to nullable renders as a physical column type change and is rejected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@AHeise
AHeise force-pushed the FLINK-40496-coa-mt-column-position branch from 72297fb to 7604fa9 Compare September 2, 2026 11:09

@raminqaf raminqaf 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.

LGTM!

@AHeise
AHeise merged commit 7d19438 into apache:master Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community-reviewed PR has been reviewed by the community.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants