-
Notifications
You must be signed in to change notification settings - Fork 5.5k
feat(planner): Add MaterializedViewScanNode #26492
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,6 +15,7 @@ | |
|
|
||
| import com.facebook.presto.Session; | ||
| import com.facebook.presto.SystemSessionProperties; | ||
| import com.facebook.presto.common.QualifiedObjectName; | ||
| import com.facebook.presto.common.predicate.TupleDomain; | ||
| import com.facebook.presto.common.type.ArrayType; | ||
| import com.facebook.presto.common.type.MapType; | ||
|
|
@@ -35,6 +36,7 @@ | |
| import com.facebook.presto.spi.plan.FilterNode; | ||
| import com.facebook.presto.spi.plan.IntersectNode; | ||
| import com.facebook.presto.spi.plan.JoinNode; | ||
| import com.facebook.presto.spi.plan.MaterializedViewScanNode; | ||
| import com.facebook.presto.spi.plan.PlanNode; | ||
| import com.facebook.presto.spi.plan.PlanNodeIdAllocator; | ||
| import com.facebook.presto.spi.plan.ProjectNode; | ||
|
|
@@ -182,6 +184,11 @@ public RelationPlan process(Node node, @Nullable SqlPlannerContext context) | |
| @Override | ||
| protected RelationPlan visitTable(Table node, SqlPlannerContext context) | ||
| { | ||
| Optional<Analysis.MaterializedViewInfo> materializedViewInfo = analysis.getMaterializedViewInfo(node); | ||
| if (materializedViewInfo.isPresent()) { | ||
sourcery-ai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return planMaterializedView(node, materializedViewInfo.get(), context); | ||
| } | ||
|
|
||
| NamedQuery namedQuery = analysis.getNamedQuery(node); | ||
| Scope scope = analysis.getScope(node); | ||
|
|
||
|
|
@@ -304,6 +311,59 @@ private RelationPlan addColumnMasks(Table table, RelationPlan plan, SqlPlannerCo | |
| return new RelationPlan(planBuilder.getRoot(), plan.getScope(), newMappings.build()); | ||
| } | ||
|
|
||
| private RelationPlan planMaterializedView(Table node, Analysis.MaterializedViewInfo materializedViewInfo, SqlPlannerContext context) | ||
| { | ||
| RelationPlan dataTablePlan = process(materializedViewInfo.getDataTable(), context); | ||
| RelationPlan viewQueryPlan = process(materializedViewInfo.getViewQuery(), context); | ||
|
|
||
| Scope scope = analysis.getScope(node); | ||
|
|
||
| QualifiedObjectName materializedViewName = materializedViewInfo.getMaterializedViewName(); | ||
|
|
||
| RelationType dataTableDescriptor = dataTablePlan.getDescriptor(); | ||
| List<VariableReferenceExpression> dataTableVariables = dataTablePlan.getFieldMappings(); | ||
| List<VariableReferenceExpression> viewQueryVariables = viewQueryPlan.getFieldMappings(); | ||
|
|
||
| checkArgument( | ||
| dataTableVariables.size() == viewQueryVariables.size(), | ||
| "Materialized view %s has mismatched field counts: data table has %s fields but view query has %s fields", | ||
| materializedViewName, | ||
| dataTableVariables.size(), | ||
| viewQueryVariables.size()); | ||
|
|
||
| ImmutableList.Builder<VariableReferenceExpression> outputVariablesBuilder = ImmutableList.builder(); | ||
| ImmutableMap.Builder<VariableReferenceExpression, VariableReferenceExpression> dataTableMappingsBuilder = ImmutableMap.builder(); | ||
| ImmutableMap.Builder<VariableReferenceExpression, VariableReferenceExpression> viewQueryMappingsBuilder = ImmutableMap.builder(); | ||
|
|
||
| for (Field field : dataTableDescriptor.getVisibleFields()) { | ||
| int fieldIndex = dataTableDescriptor.indexOf(field); | ||
|
Comment on lines
+338
to
+339
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue (bug_risk): Potential mismatch if visible fields differ from output variable order. This approach relies on visible fields and output variables having matching order, which may not always be guaranteed. Please ensure consistency or clarify this assumption in the documentation. |
||
| VariableReferenceExpression dataTableVar = dataTableVariables.get(fieldIndex); | ||
| VariableReferenceExpression viewQueryVar = viewQueryVariables.get(fieldIndex); | ||
|
|
||
| VariableReferenceExpression outputVar = variableAllocator.newVariable(dataTableVar); | ||
| outputVariablesBuilder.add(outputVar); | ||
|
|
||
| dataTableMappingsBuilder.put(outputVar, dataTableVar); | ||
| viewQueryMappingsBuilder.put(outputVar, viewQueryVar); | ||
| } | ||
|
|
||
| List<VariableReferenceExpression> outputVariables = outputVariablesBuilder.build(); | ||
| Map<VariableReferenceExpression, VariableReferenceExpression> dataTableMappings = dataTableMappingsBuilder.build(); | ||
| Map<VariableReferenceExpression, VariableReferenceExpression> viewQueryMappings = viewQueryMappingsBuilder.build(); | ||
|
|
||
| MaterializedViewScanNode mvScanNode = new MaterializedViewScanNode( | ||
| getSourceLocation(node.getLocation()), | ||
| idAllocator.getNextId(), | ||
| dataTablePlan.getRoot(), | ||
| viewQueryPlan.getRoot(), | ||
| materializedViewName, | ||
| dataTableMappings, | ||
| viewQueryMappings, | ||
| outputVariables); | ||
|
|
||
| return new RelationPlan(mvScanNode, scope, outputVariables); | ||
| } | ||
|
|
||
| @Override | ||
| protected RelationPlan visitTableFunctionInvocation(TableFunctionInvocation node, SqlPlannerContext context) | ||
| { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| /* | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
| package com.facebook.presto.sql.planner.iterative.rule; | ||
|
|
||
| import com.facebook.presto.Session; | ||
| import com.facebook.presto.matching.Captures; | ||
| import com.facebook.presto.matching.Pattern; | ||
| import com.facebook.presto.metadata.Metadata; | ||
| import com.facebook.presto.spi.MaterializedViewStatus; | ||
| import com.facebook.presto.spi.analyzer.MetadataResolver; | ||
| import com.facebook.presto.spi.plan.Assignments; | ||
| import com.facebook.presto.spi.plan.MaterializedViewScanNode; | ||
| import com.facebook.presto.spi.plan.PlanNode; | ||
| import com.facebook.presto.spi.plan.ProjectNode; | ||
| import com.facebook.presto.spi.relation.VariableReferenceExpression; | ||
| import com.facebook.presto.sql.planner.iterative.Rule; | ||
|
|
||
| import java.util.Map; | ||
|
|
||
| import static com.facebook.presto.SystemSessionProperties.isLegacyMaterializedViews; | ||
| import static com.facebook.presto.SystemSessionProperties.isMaterializedViewDataConsistencyEnabled; | ||
| import static com.facebook.presto.spi.plan.ProjectNode.Locality.LOCAL; | ||
| import static com.facebook.presto.sql.planner.plan.Patterns.materializedViewScan; | ||
| import static com.google.common.base.Preconditions.checkState; | ||
| import static java.util.Objects.requireNonNull; | ||
|
|
||
| public class MaterializedViewRewrite | ||
| implements Rule<MaterializedViewScanNode> | ||
| { | ||
| private final Metadata metadata; | ||
|
|
||
| public MaterializedViewRewrite(Metadata metadata) | ||
| { | ||
| this.metadata = requireNonNull(metadata, "metadata is null"); | ||
| } | ||
|
|
||
| @Override | ||
| public Pattern<MaterializedViewScanNode> getPattern() | ||
| { | ||
| return materializedViewScan(); | ||
| } | ||
|
|
||
| @Override | ||
| public Result apply(MaterializedViewScanNode node, Captures captures, Context context) | ||
| { | ||
| Session session = context.getSession(); | ||
| checkState(!isLegacyMaterializedViews(session), "Materialized view rewrite rule should not fire when legacy materialized views are enabled"); | ||
| checkState(isMaterializedViewDataConsistencyEnabled(session), "Materialized view rewrite rule should not fire when materialized view data consistency is disabled"); | ||
|
|
||
| MetadataResolver metadataResolver = metadata.getMetadataResolver(session); | ||
|
|
||
| MaterializedViewStatus status = metadataResolver.getMaterializedViewStatus(node.getMaterializedViewName()); | ||
|
|
||
| boolean useDataTable = status.isFullyMaterialized(); | ||
| PlanNode chosenPlan = useDataTable ? node.getDataTablePlan() : node.getViewQueryPlan(); | ||
| Map<VariableReferenceExpression, VariableReferenceExpression> chosenMappings = | ||
| useDataTable ? node.getDataTableMappings() : node.getViewQueryMappings(); | ||
hantangwangd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| Assignments.Builder assignments = Assignments.builder(); | ||
| for (VariableReferenceExpression outputVariable : node.getOutputVariables()) { | ||
| VariableReferenceExpression sourceVariable = chosenMappings.get(outputVariable); | ||
| requireNonNull(sourceVariable, "No mapping found for output variable: " + outputVariable); | ||
| assignments.put(outputVariable, sourceVariable); | ||
| } | ||
|
|
||
| return Result.ofPlanNode(new ProjectNode( | ||
| node.getSourceLocation(), | ||
| context.getIdAllocator().getNextId(), | ||
| chosenPlan, | ||
| assignments.build(), | ||
| LOCAL)); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if the plans in the
MaterializedViewScanNodecould containCTEReferencenodes ? If so, we should move this above L316.If this is not possible, lets add an invariant for this in the
MaterializedViewScanNodeconstructor