[FLINK-40496][table-planner] Apply append-only column rules consistently when altering a materialized table - #29034
Conversation
f49fb94 to
bdac042
Compare
446af6c to
0831111
Compare
0831111 to
07a6c29
Compare
85c03d2 to
9167191
Compare
9167191 to
745323d
Compare
| List<TableChange> tableChanges = | ||
| new ArrayList<>( | ||
| MaterializedTableUtils.buildSchemaTableChanges(oldSchema, newSchema)); | ||
| MaterializedTableUtils.validateAndExtractColumnChanges( |
There was a problem hiding this comment.
Unifies both schema changing parts: ALTER ... AS and CoA.
745323d to
16d0dc3
Compare
| 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]."), |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
16d0dc3 to
72297fb
Compare
…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>
72297fb to
7604fa9
Compare
What is the purpose of the change
CREATE OR ALTER MATERIALIZED TABLEderived its column changes differently fromALTER ... ASand 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 refreshINSERT.Given
users_shops = (user_id, shop_id, ds, order_cnt):The bare column list reorders the columns but the query text is unchanged, so no
ModifyDefinitionQueryis produced and the append-only check is skipped — before this change the reorder was applied silently.Brief change log
CREATE OR ALTERcomputes its column diff from the query (viavalidateAndExtractColumnChanges), 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.CREATE OR ALTERandALTER ... AS): existing columns may not be reordered or retyped even when the query text is unchanged. Metadata-only DDL alters are unaffected.ALTER ... ASandCREATE OR ALTERnow share one diff implementation;buildSchemaTableChangesis removed.Verifying this change
Added and updated tests:
MaterializedTableStatementITCase—CREATE OR ALTERandALTER ... ASreject 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:
@Public(Evolving): noDocumentation
Was generative AI tooling used to co-author this PR?
Generated-by: Claude Code (Claude Opus 4.8)