Make CREATE MATERIALIZED VIEW DDL pluggable via MaterializedViewDdlHandler#18639
Merged
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #18639 +/- ##
============================================
+ Coverage 64.38% 64.40% +0.01%
- Complexity 1282 1291 +9
============================================
Files 3359 3364 +5
Lines 207825 207935 +110
Branches 32447 32467 +20
============================================
+ Hits 133818 133919 +101
- Misses 63244 63249 +5
- Partials 10763 10767 +4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
81a00ee to
90c91f3
Compare
xiangfu0
commented
May 31, 2026
Contributor
Author
xiangfu0
left a comment
There was a problem hiding this comment.
Found a high-signal issue; see inline comment.
90c91f3 to
69f4e4a
Compare
Jackie-Jiang
approved these changes
Jun 1, 2026
c00300f to
5f534c0
Compare
xiangfu0
commented
Jun 1, 2026
Contributor
Author
xiangfu0
left a comment
There was a problem hiding this comment.
Found a high-signal issue; see inline comment.
…ndler Adds a MaterializedViewDdlHandler extension point so CREATE MATERIALIZED VIEW can target an alternative engine / minion task type. The default handler targets the single-stage engine (re-compiles the AS-clause as a single-stage Pinot query, rejecting JOIN / multi-source, routes under MaterializedViewTask); a downstream distribution can register an MSE handler that accepts joins and stamps its own task type. The handler — installed via DdlCompiler.setMaterializedViewDdlHandler — owns engine-specific verification (validateDefinedQuery) and whether projection schema inference is allowed (supportsSchemaInference). DdlCompiler fails fast with a clear message if a handler returns a null/unstamped task type. MaterializedViewPropertyRouter.apply gains a taskType-parameterized overload, and the "MV's own task type" matching is generalized from the hard-coded MaterializedViewTask to that task type so task.<taskType>.* knobs route correctly (and are not dropped) for custom task types. Documents the extension-point contract: a handler stamping a non-built-in task type owns that type's complete runtime including definition-metadata persistence and consistency tracking. The built-in controller-side MV machinery (MaterializedViewDefinitionMetadata persistence + MaterializedViewConsistencyManager) keys on MaterializedViewTask and now intentionally and explicitly skips MVs stamped with a different task type (logged at INFO, not WARN), leaving freshness/consistency to the owning task type. Behavior is unchanged when no alternative handler is registered. All pinot-sql-ddl tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5f534c0 to
c91cccd
Compare
Contributor
Author
|
Opened the docs follow-up PR for this change: pinot-contrib/pinot-docs#847 |
xiangfu0
added a commit
to pinot-contrib/pinot-docs
that referenced
this pull request
Jun 2, 2026
## Summary - document that the built-in OSS materialized-view path is still the single-source `MaterializedViewTask` flow by default - add plugin-architecture guidance for the new `MaterializedViewDdlHandler` extension point - clarify that custom handlers can require explicit MV column lists and own alternate task/runtime wiring ## Cross-check - verified the merged Apache Pinot behavior against `apache/pinot#18639`, including `MaterializedViewDdlHandler`, `DdlCompiler`, and the default built-in behavior ## Validation - `git diff --check`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Makes
CREATE MATERIALIZED VIEW ... AS <query>DDL pluggable via a newMaterializedViewDdlHandlerextension point, so downstream distributions can support materialized views that are materialized by a different engine / minion task type (e.g. a multi-stage-engine MV whoseASclause is a JOIN) without forking the DDL compiler.OSS behavior is byte-for-byte unchanged when no alternative handler is registered: a JOIN in the
ASclause is still rejected, and the MV is still routed under the built-inMaterializedViewTask.Motivation
Today the single-source / single-stage assumption is hardcoded in
DdlCompiler.compileCreateMaterializedView:ASclause is rejected unconditionally, andMaterializedViewTask.A distribution that wants a richer MV (e.g. materialize the result of a JOIN through the multi-stage engine via its own minion task type) has no clean seam — it cannot reuse the DDL compile path. Because the controller validates the resulting
TableConfig(running the task generator's validation) before persisting, simply "allowing the JOIN at compile" is insufficient: the handler must be able to stamp a task type whose generator can validate that definition.What changed (
pinot-sql-ddl)MaterializedViewDdlHandlerwith two methods:validateDefinedQuery(queryNode, properties)(query/join policy, run before column resolution) andapplyTaskConfig(properties, definedSql, schedule, builder)(routes the MV task config and returns the task type stamped). Includes a shared staticcontainsJoin(SqlNode)helper.DefaultMaterializedViewDdlHandler— preserves current behavior exactly (reject JOINs, route underMaterializedViewTask).MaterializedViewDdlHandlerRegistry— process-wide registry, defaults to the single-source handler; a distribution registers its handler once at controller startup (mirrors existing pluggable-component registry patterns).DdlCompiler.compileCreateMaterializedViewdelegates query validation + task routing to the registered handler, and validates MV consistency (bucketTimePeriodpresent) against the task type the handler stamped.MaterializedViewPropertyRouter.applygains ataskType-parameterized overload so a handler can route the MV task config under an alternative task type (the no-arg form delegates withMaterializedViewTask).verifyDefinedSqlIsParseablenow does a syntactic parse (compileToSqlNodeAndOptions) rather than full single-stage compilation (compileToPinotQuery). The slicing-bug guard only needs to confirm the extracted text is well-formed; the syntactic parse also accepts multi-stage shapes (e.g. JOINs) a handler may permit. Engine-specific validity is still enforced later by the MV analyzer / task generator for whichever task type the handler stamped. JOINs remain rejected by default (the default handler rejects them earlier, before this check).Testing
pinot-sql-ddltests pass (169), includingDdlCompilerMaterializedViewTest(40) — default behavior (single-source, JOIN rejected,MaterializedViewTaskrouting) is unchanged.Backward compatibility
No config, wire-format, or default-behavior changes. The extension point is opt-in via the registry; absent any registration, the default handler reproduces the prior code path.
🤖 Generated with Claude Code