[FLINK-39957][table] Support EXPLAIN of CREATE [OR ALTER] MATERIALIZED TABLE#28510
[FLINK-39957][table] Support EXPLAIN of CREATE [OR ALTER] MATERIALIZED TABLE#28510raminqaf wants to merge 8 commits into
Conversation
…LE in the SQL parser
…translatable as ModifyOperation
…R to a sink RelNode for EXPLAIN
… manager and add EXPLAIN ITs
…-table conversion
| throw new SqlExecutionException( | ||
| "No Statement Set to submit. 'END' statement should be used after 'BEGIN STATEMENT SET'."); | ||
| } else if (op instanceof ModifyOperation) { | ||
| } else if (op instanceof ModifyOperation && !(op instanceof MaterializedTableOperation)) { |
There was a problem hiding this comment.
is there a reason MaterializedTableOperation is not a ModifyOperation
however after that we call callModifyOperations ?
There was a problem hiding this comment.
MaterializedTableOperation is a marker shared by SUSPEND, RESUME, REFRESH and DROP too. Those have no definition query, so they can't implement the ModifyOperation contract (getChild() / accept(visitor)) in any meaningful way. More importantly, if the marker were a ModifyOperation, every MT op would fall into the callModifyOperations branch and execute as an INSERT.
That's what the && !(op instanceof MaterializedTableOperation) guard enforces. So only the query-bearing operations implement ModifyOperation, and purely so the planner can translate them into a sink for EXPLAIN. Execution still goes through the manager for all of them.
| * golden resource. The per-test catalog name is normalized to {@code $CATALOG} before | ||
| * comparison. | ||
| */ | ||
| static void verifyExplainPlan( |
There was a problem hiding this comment.
why do we need to create another plan verifier if there is already existing framework for this?
See TableTestBase
There was a problem hiding this comment.
Good point. I wanted to do the verification in the IT cases of the Gateway. Now, I removed the custom helper and moved plan-content verification into the planner tests.
Gateway ITs no longer assert plan text. They only check that EXPLAIN returns a single non-empty plan, succeeds, and is is side-effect-free.
Dropped MaterializedTableTestUtils.verifyExplainPlan and the gateway golden files
| public static PlannerQueryOperation validateAndConvertAsQuery( | ||
| SqlNode asQuery, ConvertContext context) { | ||
| final FlinkPlannerImpl flinkPlanner = context.getFlinkPlanner(); | ||
| final SqlNode validated = flinkPlanner.validate(asQuery); | ||
| final Operation operation = | ||
| SqlNodeToOperationConversion.convert( | ||
| flinkPlanner, context.getCatalogManager(), validated) | ||
| .orElseThrow( | ||
| () -> | ||
| new TableException( |
There was a problem hiding this comment.
method has pretty generic name, then somewhere in the middle it throws
"Unsupported materialized table definition query: "
either make it generic or may be rename and move into. materializedTableUtils
There was a problem hiding this comment.
I will make it more generic. We can even replace the AsQuery validation of RTAS and CTAS with this method. Should I do it in this PR as a separate commit or leave the code there untouched?
| null, | ||
| isOverwrite, | ||
| sink, | ||
| null); // conflictStrategy |
There was a problem hiding this comment.
what does this comment mean?
| return convertSinkToRel( | ||
| relBuilder, | ||
| input, | ||
| Collections.emptyMap(), |
There was a problem hiding this comment.
| Collections.emptyMap(), | |
| Map.of(), |
here and in other places
What is the purpose of the change
EXPLAINpreviously rejected materialized table DDL, so users had no way to inspect the plan that populates a materialized table without actually running it. This change addsEXPLAINsupport forCREATE MATERIALIZED TABLE ... AS,CREATE OR ALTER MATERIALIZED TABLE ... AS(both the alter-on-existing and the in-placetable-to-materialized-table conversion path from FLINK-39847), and
ALTER MATERIALIZED TABLE ... AS. The produced plan is the sink that writes the definition query into the materialized table, mirroring how CTAS/RTAS are explained.EXPLAINstays side-effect-free: no table is created, altered, or converted, and no refresh job is submitted.Note on scope: building the sink for a brand-new managed materialized table at
EXPLAINtime is not covered, because a managed table's storage options (e.g.path) are only assigned by the catalog at creation time. The alter and conversion paths work because they reuse the existing table's already-resolved connectoroptions. Resolving managed options at plan time without persisting is left as a follow-up.
Brief change log
CREATE/ALTER MATERIALIZED TABLEstatements afterEXPLAIN, and reject a non-ASALTERunderEXPLAINwith a clear message.ModifyOperation, carrying the validatedASquery as the sink input;ModifyOperationVisitorgains the correspondingvisitmethods.RelNodethat writes into the resulting table (reusing the existing table's resolved options for alter/convert).MaterializedTableManagerrather than the genericModifyOperationtranslation path (the newModifyOperationrole only enablesEXPLAIN, it must not change execution).Verifying this change
This change added tests and can be verified as follows:
EXPLAINofCREATE/CREATE OR ALTER/ALTER MATERIALIZED TABLE, including the rejection of a non-ASALTER.TableSinkTest) asserting the AST / optimized physical / optimized execution plans for the create and alter variants.EXPLAINplan end-to-end (against golden resources) forALTER ... AS,CREATE OR ALTERon an existing materialized table, and the table-to-materialized-table conversion, plus assertions thatEXPLAINleaves the catalog object unchanged.Does this pull request potentially affect one of the following parts:
@Public(Evolving): noDocumentation
EXPLAINsupport on the materialized table /EXPLAINstatement docs)AI-tooling disclosure
Generated cleanups by Claude Opus 4.8