Skip to content

Conversation

@snuyanzin
Copy link
Contributor

What is the purpose of the change

The issue is that right now validation logic (the one which is not related to common syntax) is hard coded in converter.
From another side converters do not allow to extend them.
The idea is to move validation to operation. Operations could be custom and could contain slightly relaxed validation logic.

Brief change log

Materialized table operations

Verifying this change

Mostly existed tests
however some new test also added

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 )

@flinkbot
Copy link
Collaborator

flinkbot commented Jan 28, 2026

CI report:

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

Copy link
Contributor

@liuyongvs liuyongvs left a comment

Choose a reason for hiding this comment

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

LGTM +1

Comment on lines -819 to -825
AlterMaterializedTableChangeOperation alterMaterializedTableChangeOperation =
new AlterMaterializedTableChangeOperation(
tableIdentifier,
op.getTableChanges(),
op.getCatalogMaterializedTable());
return operationExecutor.callExecutableOperation(
handle, alterMaterializedTableChangeOperation);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

anyway here and in other places it is just a copy as AlterMaterializedTableChangeOperation since AlterMaterializedTableAsQueryOperation#execute fails with UnsupportedOperationException
not sure why it is done like that initially. Do not change the logic, just make code a bit more compact here

+ "Unsupported table change detected: %s. ",
op.getTableIdentifier(), tableChange));
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

since now AlterMaterializedTableChangeOperation contains old table and a list of changes, there is no need to generate new list of changes to calculate rollbacked table

}

private void applyTableChanges(List<TableChange> tableChanges) {
isQueryChange = tableChanges.stream().anyMatch(t -> t instanceof ModifyDefinitionQuery);
Copy link
Contributor Author

@snuyanzin snuyanzin Jan 29, 2026

Choose a reason for hiding this comment

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

depending on whether it is a query change or not the validation is slightly different

*/
static ModifyDefinitionQuery modifyDefinitionQuery(String definitionQuery) {
return new ModifyDefinitionQuery(definitionQuery);
static ModifyDefinitionQuery modifyDefinitionQuery(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

looks like it was missed when original query was added


// Used to build changes introduced by changed query like
// ALTER MATERIALIZED TABLE ... AS ...
public static List<TableChange> buildSchemaTableChanges(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

generation of table change based on query change
In case of table schema changes the generation is happening at SchemaConverter

The reason why it is not used here is that SchemaConverter works with AST objects

@github-actions github-actions bot added the community-reviewed PR has been reviewed by the community. label Jan 29, 2026
Copy link
Contributor

@AHeise AHeise left a comment

Choose a reason for hiding this comment

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

First pass. Looks very good already. My main question is if we can restructure the change application to avoid the 100 if(change instanceof ...) checks.

Comment on lines +122 to +124
.comment(oldTable.getComment())
.partitionKeys(oldTable.getPartitionKeys())
.options(oldTable.getOptions())
Copy link
Contributor

Choose a reason for hiding this comment

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

Does that mean that we currently don't support changing these fields?
(I'm fine if this is also the current behavior)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The only way how partition might be changed is

ALTER MATERIALIZED TABLE [catalog_name.][db_name.]table_name REFRESH [PARTITION (key1=val1, key2=val2, ...)]

and this is handled with completely different operation/converter AlterMaterializedTableRefreshOperation, SqlAlterMaterializedTableRefreshConverter and I don't see any specific validations there, just conversion to operation

other's change is impossible for no, yes

"(\n"
+ " `m` STRING METADATA VIRTUAL,\n"
+ " `calc` AS 'a' || 'b',\n"
+ " `calc` AS ['a' || 'b'],\n"
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are these changes necessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

together with validation resolving moved to operation level
square brackets mean unresolved expression

// indicates that this is an unresolved expression consistent with unresolved data types
private static final String FORMAT = "[%s]";

List.of(
TableChange.add(physical("b", DataTypes.INT())),
TableChange.dropColumn("a"))),
TestSpec.of(
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we also need tests for column type changes (e.g. widening)? If that's not supported yet, ignore this comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added a test

Comment on lines +242 to +248
handleColumns(tableChange);
handleDistribution(tableChange);
handleWatermark(tableChange);
handleUniqueConstraint(tableChange);
handleRefreshStatus(tableChange);
handleRefreshHandler(tableChange);
handleModifyDefinitionQuery(tableChange);
Copy link
Contributor

Choose a reason for hiding this comment

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

We could return true to short cut the handles on the first successful invocation.
Alterantively, we could build nested Handler classes that provide a list of supported change classes. Then we can have an index from type -> handler.
Going further we could have just 1 handler per change class, where we use a generic type to capture the handled change and automatically extract the change class to builld the inex.

WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

probably I forgot to fix if condition at the very beginning
fixed that
thanks 👍

Comment on lines +340 to +341
primaryKeyName = null;
primaryKeyColumns = null;
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you need to verify if the drop constraint is actually for that particular primary key? Or is this always the case?

Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to sequence the changes somehow? If I change the PK from pk1 to pk2, do I get a DropConstraint and an AddUniqueConstraint. If so, we need to drop first before readding, right?
Can this also happen for other changes?
Since changes is a list, do we already have the sequence? If so, please document that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For now it is impossible to have several primary keys for one [materialized ]table
for that reason while dropping there is no name, just this command

ALTER MATERIALIZED TABLE DROP PRIMARY KEY;

Copy link
Contributor Author

@snuyanzin snuyanzin Jan 29, 2026

Choose a reason for hiding this comment

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

Do we need to sequence the changes somehow? If I change the PK from pk1 to pk2, do I get a DropConstraint and an AddUniqueConstraint. If so, we need to drop first before readding, right?
Can this also happen for other changes?
Since changes is a list, do we already have the sequence? If so, please document that.

may be in future we will have such cases
right now I don't know how I could tell to Flink just with changing query operation (what I should put in SQL...)

Anyway I will put the comment about ordering just in case

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.

4 participants