This is an automated email from the ASF dual-hosted git repository. englefly pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push: new 98b715a1d32 [feat](nereids) derive operative slots (#48738) 98b715a1d32 is described below commit 98b715a1d32358dbb492b7e1de2f24614eba9927 Author: minghong <zhoumingh...@selectdb.com> AuthorDate: Fri Mar 14 10:10:40 2025 +0800 [feat](nereids) derive operative slots (#48738) ### What problem does this PR solve? used for (in next pr) 1. lazy materialization 2. only fetch column stats for operative slots in StatsCalculator 3. print less col stats in profile --- .../doris/nereids/jobs/executor/Rewriter.java | 4 +- .../org/apache/doris/nereids/rules/RuleType.java | 2 + .../doris/nereids/rules/analysis/BindRelation.java | 8 +- .../exploration/mv/MaterializedViewUtils.java | 3 +- .../LogicalOlapScanToPhysicalOlapScan.java | 3 +- .../rules/rewrite/OperativeColumnDerive.java | 146 +++++++++++++++++++++ .../trees/plans/algebra/CatalogRelation.java | 15 +++ .../plans/logical/LogicalCatalogRelation.java | 15 ++- .../trees/plans/logical/LogicalOlapScan.java | 80 ++++++++--- .../trees/plans/physical/PhysicalOlapScan.java | 38 ++++-- .../translator/PhysicalPlanTranslatorTest.java | 3 +- .../doris/nereids/jobs/RewriteTopDownJobTest.java | 3 +- .../postprocess/MergeProjectPostProcessTest.java | 2 +- .../PushDownFilterThroughProjectTest.java | 4 +- .../rules/rewrite/OperativeColumnDeriveTest.java | 90 +++++++++++++ .../doris/nereids/trees/plans/PlanEqualsTest.java | 9 +- .../nereids/trees/plans/PlanToStringTest.java | 2 +- .../apache/doris/nereids/util/PlanConstructor.java | 2 +- .../nereids_p0/stats/partitionRowCount.groovy | 2 +- .../operative_slots/operative_slots.groovy | 79 +++++++++++ 20 files changed, 462 insertions(+), 48 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Rewriter.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Rewriter.java index b080df1df4f..80c8760d0e5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Rewriter.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Rewriter.java @@ -101,6 +101,7 @@ import org.apache.doris.nereids.rules.rewrite.MergeSetOperations; import org.apache.doris.nereids.rules.rewrite.MergeSetOperationsExcept; import org.apache.doris.nereids.rules.rewrite.MergeTopNs; import org.apache.doris.nereids.rules.rewrite.NormalizeSort; +import org.apache.doris.nereids.rules.rewrite.OperativeColumnDerive; import org.apache.doris.nereids.rules.rewrite.OrExpansion; import org.apache.doris.nereids.rules.rewrite.ProjectOtherJoinConditionForNestedLoopJoin; import org.apache.doris.nereids.rules.rewrite.PruneEmptyPartition; @@ -503,7 +504,8 @@ public class Rewriter extends AbstractBatchJobExecutor { new CheckAfterRewrite() ) ), - topDown(new CollectCteConsumerOutput()) + topDown(new CollectCteConsumerOutput()), + custom(RuleType.OPERATIVE_COLUMN_DERIVE, OperativeColumnDerive::new) ) ); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java index 254af1bf1f5..744268e9793 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java @@ -377,6 +377,8 @@ public enum RuleType { REWRITE_SENTINEL(RuleTypeClass.REWRITE), COLLECT_COLUMNS(RuleTypeClass.REWRITE), + OPERATIVE_COLUMN_DERIVE(RuleTypeClass.REWRITE), + // topn opts DEFER_MATERIALIZE_TOP_N_RESULT(RuleTypeClass.REWRITE), // short circuit rule diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java index 0ae11ee4707..82dddc9575a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindRelation.java @@ -186,7 +186,9 @@ public class BindRelation extends OneAnalysisRuleFactory { if (!CollectionUtils.isEmpty(partIds) && !unboundRelation.getIndexName().isPresent()) { scan = new LogicalOlapScan(unboundRelation.getRelationId(), (OlapTable) table, qualifier, partIds, - tabletIds, unboundRelation.getHints(), unboundRelation.getTableSample()); + tabletIds, unboundRelation.getHints(), + unboundRelation.getTableSample(), + ImmutableList.of()); } else { Optional<String> indexName = unboundRelation.getIndexName(); // For direct mv scan. @@ -204,11 +206,11 @@ public class BindRelation extends OneAnalysisRuleFactory { (OlapTable) table, qualifier, tabletIds, CollectionUtils.isEmpty(partIds) ? ((OlapTable) table).getPartitionIds() : partIds, indexId, preAggStatus, CollectionUtils.isEmpty(partIds) ? ImmutableList.of() : partIds, - unboundRelation.getHints(), unboundRelation.getTableSample()); + unboundRelation.getHints(), unboundRelation.getTableSample(), ImmutableList.of()); } else { scan = new LogicalOlapScan(unboundRelation.getRelationId(), (OlapTable) table, qualifier, tabletIds, unboundRelation.getHints(), - unboundRelation.getTableSample()); + unboundRelation.getTableSample(), ImmutableList.of()); } } if (!tabletIds.isEmpty()) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewUtils.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewUtils.java index ddae11fb735..74cc21e0342 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewUtils.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/mv/MaterializedViewUtils.java @@ -229,7 +229,8 @@ public class MaterializedViewUtils { ImmutableList.of(), // this must be empty, or it will be used to sample ImmutableList.of(), - Optional.empty()); + Optional.empty(), + ImmutableList.of()); return BindRelation.checkAndAddDeleteSignFilter(olapScan, cascadesContext.getConnectContext(), olapScan.getTable()); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalOlapScanToPhysicalOlapScan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalOlapScanToPhysicalOlapScan.java index 472d2e169db..4d006e557ac 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalOlapScanToPhysicalOlapScan.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalOlapScanToPhysicalOlapScan.java @@ -61,7 +61,8 @@ public class LogicalOlapScanToPhysicalOlapScan extends OneImplementationRuleFact olapScan.getOutputByIndex(olapScan.getTable().getBaseIndexId()), Optional.empty(), olapScan.getLogicalProperties(), - olapScan.getTableSample()) + olapScan.getTableSample(), + olapScan.getOperativeSlots()) ).toRule(RuleType.LOGICAL_OLAP_SCAN_TO_PHYSICAL_OLAP_SCAN_RULE); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/OperativeColumnDerive.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/OperativeColumnDerive.java new file mode 100644 index 00000000000..74a97fc2c64 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/OperativeColumnDerive.java @@ -0,0 +1,146 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.doris.nereids.rules.rewrite; + +import org.apache.doris.nereids.jobs.JobContext; +import org.apache.doris.nereids.rules.rewrite.OperativeColumnDerive.DeriveContext; +import org.apache.doris.nereids.trees.expressions.NamedExpression; +import org.apache.doris.nereids.trees.expressions.Slot; +import org.apache.doris.nereids.trees.expressions.SlotReference; +import org.apache.doris.nereids.trees.plans.Plan; +import org.apache.doris.nereids.trees.plans.logical.LogicalCatalogRelation; +import org.apache.doris.nereids.trees.plans.logical.LogicalProject; +import org.apache.doris.nereids.trees.plans.logical.LogicalSink; +import org.apache.doris.nereids.trees.plans.logical.LogicalUnion; +import org.apache.doris.nereids.trees.plans.visitor.CustomRewriter; +import org.apache.doris.nereids.trees.plans.visitor.DefaultPlanRewriter; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * derive operative columns + */ +public class OperativeColumnDerive extends DefaultPlanRewriter<DeriveContext> implements CustomRewriter { + + @Override + public Plan rewriteRoot(Plan plan, JobContext jobContext) { + return plan.accept(this, new DeriveContext()); + } + + @Override + public Plan visit(Plan plan, DeriveContext context) { + context.addOperativeSlots(plan.getInputSlots()); + return visitChildren(this, plan, context); + } + + @Override + public Plan visitLogicalSink(LogicalSink<? extends Plan> sink, DeriveContext context) { + return visitChildren(this, sink, context); + } + + private Plan deriveUnion(LogicalUnion union, DeriveContext context) { + for (int i = 0; i < union.getOutput().size(); i++) { + Slot output = union.getOutput().get(i); + if (context.operativeSlots.contains(output)) { + for (List<SlotReference> childOutput : union.getRegularChildrenOutputs()) { + context.operativeSlots.add(childOutput.get(i)); + } + } + } + return visitChildren(this, union, context); + } + + @Override + public Plan visitLogicalUnion(LogicalUnion union, DeriveContext context) { + Plan round1 = deriveUnion(union, context); + // check for back propagation + boolean needBackPropagation = false; + for (int i = 0; i < union.getOutput().size(); i++) { + Slot output = union.getOutput().get(i); + if (!context.operativeSlots.contains(output)) { + for (List<SlotReference> childOutput : union.getRegularChildrenOutputs()) { + if (context.operativeSlots.contains(childOutput.get(i))) { + // if any child output is operative, this output is operative + context.operativeSlots.add(output); + needBackPropagation = true; + break; + } + } + } + } + if (needBackPropagation) { + return deriveUnion(union, context); + } else { + return round1; + } + } + + @Override + public Plan visitLogicalProject(LogicalProject<? extends Plan> project, DeriveContext context) { + for (NamedExpression ne : project.getProjects()) { + if (!(ne instanceof Slot)) { + if (ne.child(0) instanceof Slot) { + if (context.operativeSlots.contains(ne.toSlot())) { + context.operativeSlots.add((Slot) ne.child(0)); + } + } else { + context.addOperativeSlots(ne.getInputSlots()); + context.addOperativeSlot(ne.toSlot()); + } + } + } + Plan plan = visitChildren(this, project, context); + // back propagate + for (NamedExpression ne : project.getProjects()) { + if (!(ne instanceof Slot) && ne.child(0) instanceof Slot) { + if (context.operativeSlots.contains(((Slot) ne.child(0)))) { + context.addOperativeSlot(ne.toSlot()); + } + } + } + return plan; + } + + @Override + public Plan visitLogicalCatalogRelation(LogicalCatalogRelation relation, DeriveContext context) { + Set<Slot> intersectSlots = new HashSet<>(relation.getOutput()); + intersectSlots.retainAll(context.operativeSlots); + return (Plan) relation.withOperativeSlots(intersectSlots); + } + + /** + * DeriveContext + */ + public static class DeriveContext { + public Set<Slot> operativeSlots; + + public DeriveContext() { + this.operativeSlots = new HashSet<>(); + } + + public void addOperativeSlot(Slot slot) { + operativeSlots.add(slot); + } + + public void addOperativeSlots(Set<Slot> slots) { + operativeSlots.addAll(slots); + } + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/CatalogRelation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/CatalogRelation.java index d713ba16a8a..04e96345906 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/CatalogRelation.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/CatalogRelation.java @@ -20,6 +20,12 @@ package org.apache.doris.nereids.trees.plans.algebra; import org.apache.doris.catalog.DatabaseIf; import org.apache.doris.catalog.TableIf; import org.apache.doris.nereids.exceptions.AnalysisException; +import org.apache.doris.nereids.trees.expressions.Slot; + +import com.google.common.collect.ImmutableList; + +import java.util.Collection; +import java.util.List; /** CatalogRelation */ public interface CatalogRelation extends Relation { @@ -27,4 +33,13 @@ public interface CatalogRelation extends Relation { TableIf getTable(); DatabaseIf getDatabase() throws AnalysisException; + + default CatalogRelation withOperativeSlots(Collection<Slot> operativeSlots) { + return this; + } + + default List<Slot> getOperativeSlots() { + return ImmutableList.of(); + } + } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalCatalogRelation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalCatalogRelation.java index 5eb9d868cdb..d6e90804830 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalCatalogRelation.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalCatalogRelation.java @@ -43,6 +43,7 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; +import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -57,17 +58,24 @@ public abstract class LogicalCatalogRelation extends LogicalRelation implements // [catalogName, databaseName] protected final ImmutableList<String> qualifier; + protected final ImmutableList<Slot> operativeSlots; + public LogicalCatalogRelation(RelationId relationId, PlanType type, TableIf table, List<String> qualifier) { - super(relationId, type); - this.table = Objects.requireNonNull(table, "table can not be null"); - this.qualifier = ImmutableList.copyOf(Objects.requireNonNull(qualifier, "qualifier can not be null")); + this(relationId, type, table, qualifier, Optional.empty(), Optional.empty()); } public LogicalCatalogRelation(RelationId relationId, PlanType type, TableIf table, List<String> qualifier, Optional<GroupExpression> groupExpression, Optional<LogicalProperties> logicalProperties) { + this(relationId, type, table, qualifier, groupExpression, logicalProperties, ImmutableList.of()); + } + + public LogicalCatalogRelation(RelationId relationId, PlanType type, TableIf table, List<String> qualifier, + Optional<GroupExpression> groupExpression, Optional<LogicalProperties> logicalProperties, + Collection<Slot> operativeSlots) { super(relationId, type, groupExpression, logicalProperties); this.table = Objects.requireNonNull(table, "table can not be null"); this.qualifier = ImmutableList.copyOf(Objects.requireNonNull(qualifier, "qualifier can not be null")); + this.operativeSlots = ImmutableList.copyOf(operativeSlots); } @Override @@ -196,4 +204,5 @@ public abstract class LogicalCatalogRelation extends LogicalRelation implements public void computeFd(DataTrait.Builder builder) { // don't generate any equal pair } + } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapScan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapScan.java index 3cffa3136e7..ce57f026ea5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapScan.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOlapScan.java @@ -35,6 +35,7 @@ import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.PlanType; import org.apache.doris.nereids.trees.plans.PreAggStatus; import org.apache.doris.nereids.trees.plans.RelationId; +import org.apache.doris.nereids.trees.plans.algebra.CatalogRelation; import org.apache.doris.nereids.trees.plans.algebra.OlapScan; import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; import org.apache.doris.nereids.util.Utils; @@ -55,6 +56,7 @@ import org.json.JSONObject; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -149,34 +151,35 @@ public class LogicalOlapScan extends LogicalCatalogRelation implements OlapScan ImmutableList.of(), -1, false, PreAggStatus.unset(), ImmutableList.of(), ImmutableList.of(), Maps.newHashMap(), Optional.empty(), false, ImmutableMap.of(), - ImmutableList.of()); + ImmutableList.of(), ImmutableList.of()); } public LogicalOlapScan(RelationId id, OlapTable table, List<String> qualifier, List<Long> tabletIds, - List<String> hints, Optional<TableSample> tableSample) { + List<String> hints, Optional<TableSample> tableSample, Collection<Slot> operativeSlots) { this(id, table, qualifier, Optional.empty(), Optional.empty(), table.getPartitionIds(), false, tabletIds, -1, false, PreAggStatus.unset(), ImmutableList.of(), hints, Maps.newHashMap(), - tableSample, false, ImmutableMap.of(), ImmutableList.of()); + tableSample, false, ImmutableMap.of(), ImmutableList.of(), operativeSlots); } public LogicalOlapScan(RelationId id, OlapTable table, List<String> qualifier, List<Long> specifiedPartitions, - List<Long> tabletIds, List<String> hints, Optional<TableSample> tableSample) { + List<Long> tabletIds, List<String> hints, Optional<TableSample> tableSample, List<Slot> operativeSlots) { this(id, table, qualifier, Optional.empty(), Optional.empty(), // must use specifiedPartitions here for prune partition by sql like 'select * from t partition p1' specifiedPartitions, false, tabletIds, -1, false, PreAggStatus.unset(), specifiedPartitions, hints, Maps.newHashMap(), - tableSample, false, ImmutableMap.of(), ImmutableList.of()); + tableSample, false, ImmutableMap.of(), ImmutableList.of(), operativeSlots); } public LogicalOlapScan(RelationId id, OlapTable table, List<String> qualifier, List<Long> tabletIds, List<Long> selectedPartitionIds, long selectedIndexId, PreAggStatus preAggStatus, - List<Long> specifiedPartitions, List<String> hints, Optional<TableSample> tableSample) { + List<Long> specifiedPartitions, List<String> hints, Optional<TableSample> tableSample, + Collection<Slot> operativeSlots) { this(id, table, qualifier, Optional.empty(), Optional.empty(), selectedPartitionIds, false, tabletIds, selectedIndexId, true, preAggStatus, specifiedPartitions, hints, Maps.newHashMap(), tableSample, true, ImmutableMap.of(), - ImmutableList.of()); + ImmutableList.of(), operativeSlots); } /** @@ -189,9 +192,10 @@ public class LogicalOlapScan extends LogicalCatalogRelation implements OlapScan PreAggStatus preAggStatus, List<Long> specifiedPartitions, List<String> hints, Map<Pair<Long, String>, Slot> cacheSlotWithSlotName, Optional<TableSample> tableSample, boolean directMvScan, - Map<String, Set<List<String>>> colToSubPathsMap, List<Long> specifiedTabletIds) { + Map<String, Set<List<String>>> colToSubPathsMap, List<Long> specifiedTabletIds, + Collection<Slot> operativeSlots) { super(id, PlanType.LOGICAL_OLAP_SCAN, table, qualifier, - groupExpression, logicalProperties); + groupExpression, logicalProperties, operativeSlots); Preconditions.checkArgument(selectedPartitionIds != null, "selectedPartitionIds can not be null"); this.selectedTabletIds = Utils.fastToImmutableList(selectedTabletIds); @@ -239,7 +243,8 @@ public class LogicalOlapScan extends LogicalCatalogRelation implements OlapScan "qualified", qualifiedName(), "indexName", getSelectedMaterializedIndexName().orElse("<index_not_selected>"), "selectedIndexId", selectedIndexId, - "preAgg", preAggStatus + "preAgg", preAggStatus, + "operativeCol", operativeSlots ); } @@ -278,7 +283,8 @@ public class LogicalOlapScan extends LogicalCatalogRelation implements OlapScan groupExpression, Optional.of(getLogicalProperties()), selectedPartitionIds, partitionPruned, selectedTabletIds, selectedIndexId, indexSelected, preAggStatus, manuallySpecifiedPartitions, - hints, cacheSlotWithSlotName, tableSample, directMvScan, colToSubPathsMap, manuallySpecifiedTabletIds); + hints, cacheSlotWithSlotName, tableSample, directMvScan, colToSubPathsMap, manuallySpecifiedTabletIds, + operativeSlots); } @Override @@ -287,15 +293,20 @@ public class LogicalOlapScan extends LogicalCatalogRelation implements OlapScan return new LogicalOlapScan(relationId, (Table) table, qualifier, groupExpression, logicalProperties, selectedPartitionIds, partitionPruned, selectedTabletIds, selectedIndexId, indexSelected, preAggStatus, manuallySpecifiedPartitions, - hints, cacheSlotWithSlotName, tableSample, directMvScan, colToSubPathsMap, manuallySpecifiedTabletIds); + hints, cacheSlotWithSlotName, tableSample, directMvScan, colToSubPathsMap, manuallySpecifiedTabletIds, + operativeSlots); } + /** + * withSelectedPartitionIds + */ public LogicalOlapScan withSelectedPartitionIds(List<Long> selectedPartitionIds) { return new LogicalOlapScan(relationId, (Table) table, qualifier, Optional.empty(), Optional.of(getLogicalProperties()), selectedPartitionIds, true, selectedTabletIds, selectedIndexId, indexSelected, preAggStatus, manuallySpecifiedPartitions, - hints, cacheSlotWithSlotName, tableSample, directMvScan, colToSubPathsMap, manuallySpecifiedTabletIds); + hints, cacheSlotWithSlotName, tableSample, directMvScan, colToSubPathsMap, manuallySpecifiedTabletIds, + operativeSlots); } public LogicalOlapScan withMaterializedIndexSelected(long indexId) { @@ -303,39 +314,55 @@ public class LogicalOlapScan extends LogicalCatalogRelation implements OlapScan Optional.empty(), Optional.of(getLogicalProperties()), selectedPartitionIds, partitionPruned, selectedTabletIds, indexId, true, PreAggStatus.unset(), manuallySpecifiedPartitions, hints, cacheSlotWithSlotName, - tableSample, directMvScan, colToSubPathsMap, manuallySpecifiedTabletIds); + tableSample, directMvScan, colToSubPathsMap, manuallySpecifiedTabletIds, operativeSlots); } + /** + * withSelectedTabletIds + */ public LogicalOlapScan withSelectedTabletIds(List<Long> selectedTabletIds) { return new LogicalOlapScan(relationId, (Table) table, qualifier, Optional.empty(), Optional.of(getLogicalProperties()), selectedPartitionIds, partitionPruned, selectedTabletIds, selectedIndexId, indexSelected, preAggStatus, manuallySpecifiedPartitions, - hints, cacheSlotWithSlotName, tableSample, directMvScan, colToSubPathsMap, manuallySpecifiedTabletIds); + hints, cacheSlotWithSlotName, tableSample, directMvScan, colToSubPathsMap, manuallySpecifiedTabletIds, + operativeSlots); } + /** + * withPreAggStatus + */ public LogicalOlapScan withPreAggStatus(PreAggStatus preAggStatus) { return new LogicalOlapScan(relationId, (Table) table, qualifier, Optional.empty(), Optional.of(getLogicalProperties()), selectedPartitionIds, partitionPruned, selectedTabletIds, selectedIndexId, indexSelected, preAggStatus, manuallySpecifiedPartitions, - hints, cacheSlotWithSlotName, tableSample, directMvScan, colToSubPathsMap, manuallySpecifiedTabletIds); + hints, cacheSlotWithSlotName, tableSample, directMvScan, colToSubPathsMap, manuallySpecifiedTabletIds, + operativeSlots); } + /** + * constructor + */ public LogicalOlapScan withColToSubPathsMap(Map<String, Set<List<String>>> colToSubPathsMap) { return new LogicalOlapScan(relationId, (Table) table, qualifier, Optional.empty(), Optional.empty(), selectedPartitionIds, partitionPruned, selectedTabletIds, selectedIndexId, indexSelected, preAggStatus, manuallySpecifiedPartitions, - hints, cacheSlotWithSlotName, tableSample, directMvScan, colToSubPathsMap, manuallySpecifiedTabletIds); + hints, cacheSlotWithSlotName, tableSample, directMvScan, colToSubPathsMap, manuallySpecifiedTabletIds, + operativeSlots); } + /** + * constructor + */ public LogicalOlapScan withManuallySpecifiedTabletIds(List<Long> manuallySpecifiedTabletIds) { return new LogicalOlapScan(relationId, (Table) table, qualifier, Optional.empty(), Optional.of(getLogicalProperties()), selectedPartitionIds, partitionPruned, selectedTabletIds, selectedIndexId, indexSelected, preAggStatus, manuallySpecifiedPartitions, - hints, cacheSlotWithSlotName, tableSample, directMvScan, colToSubPathsMap, manuallySpecifiedTabletIds); + hints, cacheSlotWithSlotName, tableSample, directMvScan, colToSubPathsMap, manuallySpecifiedTabletIds, + operativeSlots); } @Override @@ -345,7 +372,8 @@ public class LogicalOlapScan extends LogicalCatalogRelation implements OlapScan Optional.empty(), Optional.empty(), selectedPartitionIds, false, selectedTabletIds, selectedIndexId, indexSelected, preAggStatus, manuallySpecifiedPartitions, - hints, Maps.newHashMap(), tableSample, directMvScan, colToSubPathsMap, selectedTabletIds); + hints, Maps.newHashMap(), tableSample, directMvScan, colToSubPathsMap, selectedTabletIds, + operativeSlots); } @Override @@ -632,6 +660,16 @@ public class LogicalOlapScan extends LogicalCatalogRelation implements OlapScan } } + @Override + public CatalogRelation withOperativeSlots(Collection<Slot> operativeSlots) { + return new LogicalOlapScan(relationId, (Table) table, qualifier, + groupExpression, Optional.of(getLogicalProperties()), + selectedPartitionIds, partitionPruned, selectedTabletIds, + selectedIndexId, indexSelected, preAggStatus, manuallySpecifiedPartitions, + hints, cacheSlotWithSlotName, tableSample, directMvScan, colToSubPathsMap, + manuallySpecifiedTabletIds, operativeSlots); + } + Map<Slot, Slot> constructReplaceMap(MTMV mtmv) { Map<Slot, Slot> replaceMap = new HashMap<>(); // Need remove invisible column, and then mapping them @@ -661,4 +699,8 @@ public class LogicalOlapScan extends LogicalCatalogRelation implements OlapScan } return replaceMap; } + + public List<Slot> getOperativeSlots() { + return operativeSlots; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapScan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapScan.java index 698a189aa26..74c5cb0be3b 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapScan.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOlapScan.java @@ -28,6 +28,7 @@ import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.PlanType; import org.apache.doris.nereids.trees.plans.PreAggStatus; import org.apache.doris.nereids.trees.plans.RelationId; +import org.apache.doris.nereids.trees.plans.algebra.CatalogRelation; import org.apache.doris.nereids.trees.plans.algebra.OlapScan; import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; import org.apache.doris.nereids.util.Utils; @@ -36,6 +37,7 @@ import org.apache.doris.statistics.Statistics; import com.google.common.collect.ImmutableList; import org.json.JSONObject; +import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -52,6 +54,7 @@ public class PhysicalOlapScan extends PhysicalCatalogRelation implements OlapSca private final PreAggStatus preAggStatus; private final List<Slot> baseOutputs; private final Optional<TableSample> tableSample; + private final ImmutableList<Slot> operativeSlots; /** * Constructor for PhysicalOlapScan. @@ -60,10 +63,12 @@ public class PhysicalOlapScan extends PhysicalCatalogRelation implements OlapSca List<Long> selectedTabletIds, List<Long> selectedPartitionIds, DistributionSpec distributionSpec, PreAggStatus preAggStatus, List<Slot> baseOutputs, Optional<GroupExpression> groupExpression, LogicalProperties logicalProperties, - Optional<TableSample> tableSample) { - this(id, olapTable, qualifier, selectedIndexId, selectedTabletIds, selectedPartitionIds, distributionSpec, - preAggStatus, baseOutputs, groupExpression, logicalProperties, null, null, - tableSample); + Optional<TableSample> tableSample, List<Slot> operativeSlots) { + this(id, olapTable, qualifier, + selectedIndexId, selectedTabletIds, selectedPartitionIds, distributionSpec, + preAggStatus, baseOutputs, + groupExpression, logicalProperties, null, + null, tableSample, operativeSlots); } /** @@ -73,7 +78,9 @@ public class PhysicalOlapScan extends PhysicalCatalogRelation implements OlapSca List<Long> selectedTabletIds, List<Long> selectedPartitionIds, DistributionSpec distributionSpec, PreAggStatus preAggStatus, List<Slot> baseOutputs, Optional<GroupExpression> groupExpression, LogicalProperties logicalProperties, - PhysicalProperties physicalProperties, Statistics statistics, Optional<TableSample> tableSample) { + PhysicalProperties physicalProperties, Statistics statistics, + Optional<TableSample> tableSample, + Collection<Slot> operativeSlots) { super(id, PlanType.PHYSICAL_OLAP_SCAN, olapTable, qualifier, groupExpression, logicalProperties, physicalProperties, statistics); this.selectedIndexId = selectedIndexId; @@ -83,6 +90,7 @@ public class PhysicalOlapScan extends PhysicalCatalogRelation implements OlapSca this.preAggStatus = preAggStatus; this.baseOutputs = ImmutableList.copyOf(baseOutputs); this.tableSample = tableSample; + this.operativeSlots = ImmutableList.copyOf(operativeSlots); } @Override @@ -131,7 +139,11 @@ public class PhysicalOlapScan extends PhysicalCatalogRelation implements OlapSca if (selectedPartitionIds.size() != partitionCount) { partitions = " partitions(" + selectedPartitionIds.size() + "/" + partitionCount + ")"; } - return Utils.toSqlString("PhysicalOlapScan[" + table.getName() + index + partitions + "]" + String operativeCol = ""; + if (!operativeSlots.isEmpty()) { + operativeCol = " operativeSlots(" + operativeSlots + ")"; + } + return Utils.toSqlString("PhysicalOlapScan[" + table.getName() + index + partitions + operativeCol + "]" + getGroupIdWithPrefix(), "stats", statistics, "RFs", builder ); @@ -172,7 +184,7 @@ public class PhysicalOlapScan extends PhysicalCatalogRelation implements OlapSca public PhysicalOlapScan withGroupExpression(Optional<GroupExpression> groupExpression) { return new PhysicalOlapScan(relationId, getTable(), qualifier, selectedIndexId, selectedTabletIds, selectedPartitionIds, distributionSpec, preAggStatus, baseOutputs, - groupExpression, getLogicalProperties(), tableSample); + groupExpression, getLogicalProperties(), tableSample, operativeSlots); } @Override @@ -180,7 +192,7 @@ public class PhysicalOlapScan extends PhysicalCatalogRelation implements OlapSca Optional<LogicalProperties> logicalProperties, List<Plan> children) { return new PhysicalOlapScan(relationId, getTable(), qualifier, selectedIndexId, selectedTabletIds, selectedPartitionIds, distributionSpec, preAggStatus, baseOutputs, groupExpression, - logicalProperties.get(), tableSample); + logicalProperties.get(), tableSample, operativeSlots); } @Override @@ -188,7 +200,7 @@ public class PhysicalOlapScan extends PhysicalCatalogRelation implements OlapSca PhysicalProperties physicalProperties, Statistics statistics) { return new PhysicalOlapScan(relationId, getTable(), qualifier, selectedIndexId, selectedTabletIds, selectedPartitionIds, distributionSpec, preAggStatus, baseOutputs, groupExpression, - getLogicalProperties(), physicalProperties, statistics, tableSample); + getLogicalProperties(), physicalProperties, statistics, tableSample, operativeSlots); } @Override @@ -208,4 +220,12 @@ public class PhysicalOlapScan extends PhysicalCatalogRelation implements OlapSca public Optional<TableSample> getTableSample() { return tableSample; } + + @Override + public CatalogRelation withOperativeSlots(Collection<Slot> operativeSlots) { + return new PhysicalOlapScan(relationId, (OlapTable) table, qualifier, selectedIndexId, selectedTabletIds, + selectedPartitionIds, distributionSpec, preAggStatus, baseOutputs, + groupExpression, getLogicalProperties(), getPhysicalProperties(), statistics, + tableSample, operativeSlots); + } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslatorTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslatorTest.java index d27223a9d3b..5fc63eea3bb 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslatorTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslatorTest.java @@ -67,7 +67,8 @@ public class PhysicalPlanTranslatorTest { LogicalProperties t1Properties = new LogicalProperties(() -> t1Output, () -> DataTrait.EMPTY_TRAIT); PhysicalOlapScan scan = new PhysicalOlapScan(StatementScopeIdGenerator.newRelationId(), t1, qualifier, t1.getBaseIndexId(), Collections.emptyList(), Collections.emptyList(), null, PreAggStatus.on(), - ImmutableList.of(), Optional.empty(), t1Properties, Optional.empty()); + ImmutableList.of(), Optional.empty(), t1Properties, Optional.empty(), + ImmutableList.of()); Literal t1FilterRight = new IntegerLiteral(1); Expression t1FilterExpr = new GreaterThan(col1, t1FilterRight); PhysicalFilter<PhysicalOlapScan> filter = diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/RewriteTopDownJobTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/RewriteTopDownJobTest.java index f4adc72b32a..5fb4e16988c 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/RewriteTopDownJobTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/RewriteTopDownJobTest.java @@ -105,7 +105,8 @@ public class RewriteTopDownJobTest { private static class LogicalBoundRelation extends LogicalCatalogRelation { public LogicalBoundRelation(TableIf table, List<String> qualifier) { - super(StatementScopeIdGenerator.newRelationId(), PlanType.LOGICAL_BOUND_RELATION, table, qualifier); + super(StatementScopeIdGenerator.newRelationId(), PlanType.LOGICAL_BOUND_RELATION, table, qualifier, + Optional.empty(), Optional.empty()); } public LogicalBoundRelation(TableIf table, List<String> qualifier, Optional<GroupExpression> groupExpression, diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/postprocess/MergeProjectPostProcessTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/postprocess/MergeProjectPostProcessTest.java index 203c2ef36ca..c4648ed5a6b 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/postprocess/MergeProjectPostProcessTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/postprocess/MergeProjectPostProcessTest.java @@ -78,7 +78,7 @@ public class MergeProjectPostProcessTest { LogicalProperties t1Properties = new LogicalProperties(() -> t1Output, () -> DataTrait.EMPTY_TRAIT); PhysicalOlapScan scan = new PhysicalOlapScan(RelationId.createGenerator().getNextId(), t1, qualifier, 0L, Collections.emptyList(), Collections.emptyList(), null, PreAggStatus.on(), ImmutableList.of(), - Optional.empty(), t1Properties, Optional.empty()); + Optional.empty(), t1Properties, Optional.empty(), ImmutableList.of()); Alias x = new Alias(a, "x"); List<NamedExpression> projList3 = Lists.newArrayList(x, b, c); PhysicalProject proj3 = new PhysicalProject(projList3, placeHolder, scan); diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/postprocess/PushDownFilterThroughProjectTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/postprocess/PushDownFilterThroughProjectTest.java index aa3cef4c86b..d93b1111c19 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/postprocess/PushDownFilterThroughProjectTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/postprocess/PushDownFilterThroughProjectTest.java @@ -93,7 +93,7 @@ public class PushDownFilterThroughProjectTest { PhysicalOlapScan scan = new PhysicalOlapScan(RelationId.createGenerator().getNextId(), t1, qualifier, 0L, Collections.emptyList(), Collections.emptyList(), null, PreAggStatus.on(), ImmutableList.of(), Optional.empty(), t1Properties, - Optional.empty()); + Optional.empty(), ImmutableList.of()); Alias x = new Alias(a, "x"); List<NamedExpression> projList3 = Lists.newArrayList(x, b, c); PhysicalProject proj3 = new PhysicalProject(projList3, placeHolder, scan); @@ -132,7 +132,7 @@ public class PushDownFilterThroughProjectTest { PhysicalOlapScan scan = new PhysicalOlapScan(RelationId.createGenerator().getNextId(), t1, qualifier, 0L, Collections.emptyList(), Collections.emptyList(), null, PreAggStatus.on(), ImmutableList.of(), Optional.empty(), t1Properties, - Optional.empty()); + Optional.empty(), ImmutableList.of()); Alias x = new Alias(a, "x"); List<NamedExpression> projList3 = Lists.newArrayList(x, b, c); PhysicalProject proj3 = new PhysicalProject(projList3, placeHolder, scan); diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/OperativeColumnDeriveTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/OperativeColumnDeriveTest.java new file mode 100644 index 00000000000..5c9a6213ffa --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/rewrite/OperativeColumnDeriveTest.java @@ -0,0 +1,90 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.doris.nereids.rules.rewrite; + +import org.apache.doris.nereids.util.MemoPatternMatchSupported; +import org.apache.doris.nereids.util.PlanChecker; +import org.apache.doris.utframe.TestWithFeService; + +import org.junit.jupiter.api.Test; + +public class OperativeColumnDeriveTest extends TestWithFeService implements MemoPatternMatchSupported { + @Override + protected void runBeforeAll() throws Exception { + createDatabase("test"); + + createTable("create table test.student (\n" + "id int not null,\n" + "name varchar(128),\n" + + "age int,sex int)\n" + "distributed by hash(id) buckets 10\n" + + "properties('replication_num' = '1');"); + + createTable("create table test.score (\n" + "sid int not null, \n" + "cid int not null, \n" + "grade double)\n" + + "distributed by hash(sid,cid) buckets 10\n" + "properties('replication_num' = '1');"); + + createTable("create table test.course (\n" + "cid int not null, \n" + "cname varchar(128), \n" + + "teacher varchar(128))\n" + "distributed by hash(cid) buckets 10\n" + + "properties('replication_num' = '1');"); + + connectContext.setDatabase("test"); + } + + @Test + public void testProject() { + PlanChecker.from(connectContext) + .analyze("select sid+1, grade as x from score") + .customRewrite(new OperativeColumnDerive()) + .matches(logicalProject( + logicalOlapScan().when(scan -> + scan.getOperativeSlots().size() == 1 + && scan.getOperativeSlots().get(0).getName().equals("sid")) + )); + } + + @Test + public void testUnionAll() { + PlanChecker.from(connectContext) + .analyze("select a, b from (select sid as a, cid as b from score union all select id as a, age as b from student) T") + .customRewrite(new OperativeColumnDerive()) + .matches(logicalUnion( + logicalProject( + logicalOlapScan().when(scan -> scan.getOperativeSlots().isEmpty()) + ), + logicalProject( + logicalOlapScan().when(scan -> scan.getOperativeSlots().isEmpty()) + ) + )); + } + + @Test + public void testUnionAllBackPropagate() { + PlanChecker.from(connectContext) + .analyze("select a, b from (select sid as a, cid as b from score where cid > 0 union all select id as a, age as b from student) T") + .customRewrite(new OperativeColumnDerive()) + .matches(logicalUnion( + logicalProject( + logicalFilter( + logicalOlapScan().when(scan -> scan.getOperativeSlots().size() == 1 + && scan.getOperativeSlots().get(0).getName().equals("cid") + )) + ), + logicalProject( + logicalOlapScan().when(scan -> scan.getOperativeSlots().size() == 1 + && scan.getOperativeSlots().get(0).getName().equals("age")) + ) + )); + } +} diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/PlanEqualsTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/PlanEqualsTest.java index f76f2a83d5c..062bd3e71b9 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/PlanEqualsTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/PlanEqualsTest.java @@ -267,18 +267,21 @@ class PlanEqualsTest { PhysicalOlapScan actual = new PhysicalOlapScan(id, olapTable, Lists.newArrayList("a"), 1L, selectedTabletId, olapTable.getPartitionIds(), distributionSpecHash, PreAggStatus.on(), ImmutableList.of(), Optional.empty(), logicalProperties, - Optional.empty()); + Optional.empty(), + ImmutableList.of()); PhysicalOlapScan expected = new PhysicalOlapScan(id, olapTable, Lists.newArrayList("a"), 1L, selectedTabletId, olapTable.getPartitionIds(), distributionSpecHash, PreAggStatus.on(), ImmutableList.of(), Optional.empty(), logicalProperties, - Optional.empty()); + Optional.empty(), + ImmutableList.of()); Assertions.assertEquals(expected, actual); PhysicalOlapScan unexpected = new PhysicalOlapScan(id, olapTable, Lists.newArrayList("b"), 12345L, selectedTabletId, olapTable.getPartitionIds(), distributionSpecHash, PreAggStatus.on(), ImmutableList.of(), Optional.empty(), logicalProperties, - Optional.empty()); + Optional.empty(), + ImmutableList.of()); Assertions.assertNotEquals(unexpected, actual); } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/PlanToStringTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/PlanToStringTest.java index 312afd22b92..9a16337346e 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/PlanToStringTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/PlanToStringTest.java @@ -84,7 +84,7 @@ public class PlanToStringTest { Assertions.assertTrue( plan.toString().matches("LogicalOlapScan \\( qualified=db\\.table, " + "indexName=<index_not_selected>, " - + "selectedIndexId=-1, preAgg=UNSET \\)")); + + "selectedIndexId=-1, preAgg=UNSET, operativeCol=\\[] \\)")); } @Test diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanConstructor.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanConstructor.java index 3866ce98bf3..73c07dd47d3 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanConstructor.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/PlanConstructor.java @@ -113,7 +113,7 @@ public class PlanConstructor { int hashColumn, List<Long> selectedPartitions) { return new LogicalOlapScan(RelationId.createGenerator().getNextId(), newOlapTable(tableId, tableName, hashColumn), ImmutableList.of("db"), - selectedPartitions, ImmutableList.of(), Optional.empty()); + selectedPartitions, ImmutableList.of(), Optional.empty(), ImmutableList.of()); } public static RelationId getNextRelationId() { diff --git a/regression-test/suites/nereids_p0/stats/partitionRowCount.groovy b/regression-test/suites/nereids_p0/stats/partitionRowCount.groovy index 1250db62fe5..f18232b1dae 100644 --- a/regression-test/suites/nereids_p0/stats/partitionRowCount.groovy +++ b/regression-test/suites/nereids_p0/stats/partitionRowCount.groovy @@ -35,7 +35,7 @@ suite("partitionRowCount") { sql """physical plan select * from partitionRowCountTable where a < 250; """ - contains("PhysicalOlapScan[partitionRowCountTable partitions(2/3)]@0 ( stats=4 )") + contains("PhysicalOlapScan[partitionRowCountTable partitions(2/3) operativeSlots([a#0])]@0 ( stats=4 )") } } \ No newline at end of file diff --git a/regression-test/suites/query_p0/operative_slots/operative_slots.groovy b/regression-test/suites/query_p0/operative_slots/operative_slots.groovy new file mode 100644 index 00000000000..c8f4f89c6c4 --- /dev/null +++ b/regression-test/suites/query_p0/operative_slots/operative_slots.groovy @@ -0,0 +1,79 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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. + +suite("operative_slots") { + sql """ + drop table if exists vt; + CREATE TABLE IF NOT EXISTS vt ( + `user_id` int NOT NULL COMMENT "用户id", + `name` STRING COMMENT "用户年龄", + `v` VARIANT NULL + ) + DISTRIBUTED BY HASH(user_id) PROPERTIES("replication_num" = "1"); + + insert into vt values (6, 'doris6', '{"k1" : 100, "k2": 1}'), (7, 'doris7', '{"k1" : 2, "k2": 2}'); + + drop table if exists t; + CREATE TABLE `t` ( + `k` int NULL, + `v1` bigint NULL, + `v2` bigint NULL + ) ENGINE=OLAP + UNIQUE KEY(`k`) + DISTRIBUTED BY HASH(`k`) BUCKETS 1 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1" + ); + + insert into t values (1, 2, 3); + + set disable_join_reorder = true; + """ + + + explain { + sql "physical plan select * from t join[broadcast] vt on t.k = vt.v['k1'];" + contains("operativeSlots([k#0, __DORIS_DELETE_SIGN__#3])") + contains("operativeSlots([v['k1']#17])") + // expect plan + // PhysicalResultSink[311] ( outputExprs=[k#0, v1#1, user_id#4, name#5, v#6] ) + // +--PhysicalDistribute[306]@6 ( stats=1, distributionSpec=DistributionSpecGather ) + // +--PhysicalProject[301]@6 ( stats=1, projects=[k#0, v1#1, user_id#4, name#5, v#6] ) + // +--PhysicalHashJoin[296]@5 ( stats=1, type=INNER_JOIN, hashCondition=[(k#0 = expr_cast(element_at(v, 'k1') as INT)#7)], otherCondition=[], markCondition=[], hint=[broadcast] ) + // |--PhysicalProject[280]@2 ( stats=1, projects=[k#0, v1#1] ) + // | +--PhysicalFilter[275]@1 ( stats=1, predicates=(__DORIS_DELETE_SIGN__#2 = 0) ) + // | +--PhysicalOlapScan[t operativeSlots([k#0, __DORIS_DELETE_SIGN__#2])]@0 ( stats=1 ) + // +--PhysicalDistribute[291]@4 ( stats=1, distributionSpec=DistributionSpecReplicated ) + // +--PhysicalProject[286]@4 ( stats=1, projects=[user_id#4, name#5, v#6, cast(v['k1']#15 as INT) AS `expr_cast(element_at(v, 'k1') as INT)`#7] ) + // +--PhysicalOlapScan[vt operativeSlots([v['k1']#15])]@3 ( stats=1 ) + } + + explain { + sql "physical plan select * from t where v1=0;" + contains("operativeSlots([v1#1, __DORIS_DELETE_SIGN__#3]") + } + + explain { + sql "physical plan select sum(k) from t group by v1;" + contains("operativeSlots([k#0, v1#1, __DORIS_DELETE_SIGN__#3])") + } + + explain { + sql "physical plan select rank() over (partition by v2 order by v1) from t;" + contains("operativeSlots([v1#1, v2#2, __DORIS_DELETE_SIGN__#3])") + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org