This is an automated email from the ASF dual-hosted git repository. morrysnow 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 5a7454e8ab0 [fix](Nerieds) using join bugs (#48030) 5a7454e8ab0 is described below commit 5a7454e8ab0452967ed6eb9f735b4e5dffac05a0 Author: morrySnow <zhangwen...@selectdb.com> AuthorDate: Fri Feb 21 20:17:42 2025 +0800 [fix](Nerieds) using join bugs (#48030) ### What problem does this PR solve? Related PR: #15311 Problem Summary: 1. select * should only return using columns from left relation 2. bind expression on using join should not do distinct slot by name on using join's output ### Release note change the return columns when select asterisk from using join. before return key column from both side. now only return key column from left side. --- .../org/apache/doris/nereids/analyzer/Scope.java | 40 +++- .../doris/nereids/parser/LogicalPlanBuilder.java | 5 +- .../nereids/properties/LogicalProperties.java | 37 +++- .../nereids/rules/analysis/BindExpression.java | 44 +++-- .../nereids/rules/analysis/ExpressionAnalyzer.java | 10 +- .../nereids/rules/analysis/SubExprAnalyzer.java | 3 +- .../doris/nereids/trees/plans/AbstractPlan.java | 9 +- .../nereids/trees/plans/DiffOutputInAsterisk.java | 39 ++++ .../apache/doris/nereids/trees/plans/FakePlan.java | 2 +- .../org/apache/doris/nereids/trees/plans/Plan.java | 8 + .../trees/plans/logical/LogicalAssertNumRows.java | 9 +- .../nereids/trees/plans/logical/LogicalFilter.java | 9 +- .../trees/plans/logical/LogicalGenerate.java | 12 +- .../nereids/trees/plans/logical/LogicalJoin.java | 111 +++++++---- .../trees/plans/logical/LogicalSelectHint.java | 8 +- .../trees/plans/logical/LogicalSubQueryAlias.java | 15 +- .../trees/plans/logical/LogicalUsingJoin.java | 149 ++++++++++++++ .../nereids/trees/plans/logical/UsingJoin.java | 217 --------------------- .../trees/plans/physical/PhysicalSqlCache.java | 2 +- .../org/apache/doris/nereids/util/JoinUtils.java | 36 +++- .../org/apache/doris/nereids/util/PlanUtils.java | 24 +++ .../rules/analysis/BindSlotReferenceTest.java | 19 +- .../data/nereids_p0/join/test_join2.out | Bin 1907 -> 1697 bytes .../data/nereids_p0/join/test_join3.out | Bin 408 -> 351 bytes .../data/nereids_syntax_p0/test_join3.out | Bin 408 -> 351 bytes .../data/nereids_syntax_p0/using_join.out | Bin 127 -> 2193 bytes regression-test/data/query_p0/join/test_join2.out | Bin 1907 -> 1697 bytes regression-test/data/query_p0/join/test_join3.out | Bin 408 -> 351 bytes .../suites/nereids_p0/join/test_join2.groovy | 20 +- .../suites/nereids_syntax_p0/using_join.groovy | 150 ++++++++++---- 30 files changed, 608 insertions(+), 370 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/Scope.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/Scope.java index 7c77c680ff2..cb74698a62b 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/Scope.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/Scope.java @@ -61,27 +61,44 @@ public class Scope { private final Optional<Scope> outerScope; private final List<Slot> slots; + private final List<Slot> asteriskSlots; private final Set<Slot> correlatedSlots; private final boolean buildNameToSlot; private final Supplier<ListMultimap<String, Slot>> nameToSlot; + private final Supplier<ListMultimap<String, Slot>> nameToAsteriskSlot; - public Scope(List<? extends Slot> slots) { + public Scope(List<Slot> slots) { this(Optional.empty(), slots); } + public Scope(Optional<Scope> outerScope, List<Slot> slots) { + this(outerScope, slots, slots); + } + + public Scope(List<Slot> slots, List<Slot> asteriskSlots) { + this(Optional.empty(), slots, asteriskSlots); + } + /** Scope */ - public Scope(Optional<Scope> outerScope, List<? extends Slot> slots) { + public Scope(Optional<Scope> outerScope, List<Slot> slots, List<Slot> asteriskSlots) { this.outerScope = Objects.requireNonNull(outerScope, "outerScope can not be null"); this.slots = Utils.fastToImmutableList(Objects.requireNonNull(slots, "slots can not be null")); this.correlatedSlots = Sets.newLinkedHashSet(); this.buildNameToSlot = slots.size() > 500; this.nameToSlot = buildNameToSlot ? Suppliers.memoize(this::buildNameToSlot) : null; + this.nameToAsteriskSlot = buildNameToSlot ? Suppliers.memoize(this::buildNameToAsteriskSlot) : null; + this.asteriskSlots = Utils.fastToImmutableList( + Objects.requireNonNull(asteriskSlots, "asteriskSlots can not be null")); } public List<Slot> getSlots() { return slots; } + public List<Slot> getAsteriskSlots() { + return asteriskSlots; + } + public Optional<Scope> getOuterScope() { return outerScope; } @@ -91,17 +108,18 @@ public class Scope { } /** findSlotIgnoreCase */ - public List<Slot> findSlotIgnoreCase(String slotName) { + public List<Slot> findSlotIgnoreCase(String slotName, boolean all) { + List<Slot> slots = all ? this.slots : this.asteriskSlots; + Supplier<ListMultimap<String, Slot>> nameToSlot = all ? this.nameToSlot : this.nameToAsteriskSlot; if (!buildNameToSlot) { - Object[] array = new Object[slots.size()]; + Slot[] array = new Slot[slots.size()]; int filterIndex = 0; - for (int i = 0; i < slots.size(); i++) { - Slot slot = slots.get(i); + for (Slot slot : slots) { if (slot.getName().equalsIgnoreCase(slotName)) { array[filterIndex++] = slot; } } - return (List) Arrays.asList(array).subList(0, filterIndex); + return Arrays.asList(array).subList(0, filterIndex); } else { return nameToSlot.get().get(slotName.toUpperCase(Locale.ROOT)); } @@ -114,4 +132,12 @@ public class Scope { } return map; } + + private ListMultimap<String, Slot> buildNameToAsteriskSlot() { + ListMultimap<String, Slot> map = LinkedListMultimap.create(asteriskSlots.size()); + for (Slot slot : asteriskSlots) { + map.put(slot.getName().toUpperCase(Locale.ROOT), slot); + } + return map; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java index c0ff406794a..0b56260042a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilder.java @@ -786,7 +786,7 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalSink; import org.apache.doris.nereids.trees.plans.logical.LogicalSort; import org.apache.doris.nereids.trees.plans.logical.LogicalSubQueryAlias; import org.apache.doris.nereids.trees.plans.logical.LogicalUnion; -import org.apache.doris.nereids.trees.plans.logical.UsingJoin; +import org.apache.doris.nereids.trees.plans.logical.LogicalUsingJoin; import org.apache.doris.nereids.types.AggStateType; import org.apache.doris.nereids.types.ArrayType; import org.apache.doris.nereids.types.BigIntType; @@ -3604,8 +3604,7 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> { last, plan(join.relationPrimary()), null); } else { - last = new UsingJoin<>(joinType, last, - plan(join.relationPrimary()), ImmutableList.of(), ids, distributeHint); + last = new LogicalUsingJoin<>(joinType, last, plan(join.relationPrimary()), ids, distributeHint); } if (distributeHint.distributeType != DistributeType.NONE diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/LogicalProperties.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/LogicalProperties.java index 3ac5a38c914..6383918ced7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/LogicalProperties.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/LogicalProperties.java @@ -37,27 +37,38 @@ import java.util.Set; */ public class LogicalProperties { protected final Supplier<List<Slot>> outputSupplier; - protected final Supplier<List<Id>> outputExprIdsSupplier; + protected final Supplier<List<Id<?>>> outputExprIdsSupplier; protected final Supplier<Set<Slot>> outputSetSupplier; protected final Supplier<Map<Slot, Slot>> outputMapSupplier; protected final Supplier<Set<ExprId>> outputExprIdSetSupplier; + protected final Supplier<List<Slot>> asteriskOutputSupplier; protected final Supplier<DataTrait> dataTraitSupplier; private Integer hashCode = null; + /** + * constructor when output same as asterisk's output. + */ + public LogicalProperties(Supplier<List<Slot>> outputSupplier, Supplier<DataTrait> dataTraitSupplier) { + // the second parameters should be null to reuse memorized output supplier + this(outputSupplier, null, dataTraitSupplier); + } + /** * constructor of LogicalProperties. * * @param outputSupplier provide the output. Supplier can lazy compute output without * throw exception for which children have UnboundRelation + * @param asteriskOutputSupplier provide the output when do select *. + * @param dataTraitSupplier provide the data trait. */ - public LogicalProperties(Supplier<List<Slot>> outputSupplier, + public LogicalProperties(Supplier<List<Slot>> outputSupplier, Supplier<List<Slot>> asteriskOutputSupplier, Supplier<DataTrait> dataTraitSupplier) { this.outputSupplier = Suppliers.memoize( Objects.requireNonNull(outputSupplier, "outputSupplier can not be null") ); this.outputExprIdsSupplier = Suppliers.memoize(() -> { List<Slot> output = this.outputSupplier.get(); - ImmutableList.Builder<Id> exprIdSet + ImmutableList.Builder<Id<?>> exprIdSet = ImmutableList.builderWithExpectedSize(output.size()); for (Slot slot : output) { exprIdSet.add(slot.getExprId()); @@ -65,7 +76,7 @@ public class LogicalProperties { return exprIdSet.build(); }); this.outputSetSupplier = Suppliers.memoize(() -> { - List<Slot> output = outputSupplier.get(); + List<Slot> output = this.outputSupplier.get(); ImmutableSet.Builder<Slot> slots = ImmutableSet.builderWithExpectedSize(output.size()); for (Slot slot : output) { slots.add(slot); @@ -73,7 +84,7 @@ public class LogicalProperties { return slots.build(); }); this.outputMapSupplier = Suppliers.memoize(() -> { - Set<Slot> slots = outputSetSupplier.get(); + Set<Slot> slots = this.outputSetSupplier.get(); ImmutableMap.Builder<Slot, Slot> map = ImmutableMap.builderWithExpectedSize(slots.size()); for (Slot slot : slots) { map.put(slot, slot); @@ -89,6 +100,9 @@ public class LogicalProperties { } return exprIdSet.build(); }); + this.asteriskOutputSupplier = asteriskOutputSupplier == null ? this.outputSupplier : Suppliers.memoize( + Objects.requireNonNull(asteriskOutputSupplier, "asteriskOutputSupplier can not be null") + ); this.dataTraitSupplier = Suppliers.memoize( Objects.requireNonNull(dataTraitSupplier, "Data Trait can not be null") ); @@ -110,12 +124,16 @@ public class LogicalProperties { return outputExprIdSetSupplier.get(); } - public DataTrait getTrait() { - return dataTraitSupplier.get(); + public List<Id<?>> getOutputExprIds() { + return outputExprIdsSupplier.get(); } - public List<Id> getOutputExprIds() { - return outputExprIdsSupplier.get(); + public List<Slot> getAsteriskOutput() { + return asteriskOutputSupplier.get(); + } + + public DataTrait getTrait() { + return dataTraitSupplier.get(); } @Override @@ -126,6 +144,7 @@ public class LogicalProperties { + "\noutputSetSupplier=" + outputSetSupplier.get() + "\noutputMapSupplier=" + outputMapSupplier.get() + "\noutputExprIdSetSupplier=" + outputExprIdSetSupplier.get() + + "\nasteriskOutputSupplier=" + asteriskOutputSupplier.get() + "\nhashCode=" + hashCode + '}'; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindExpression.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindExpression.java index c308a1e7e79..029d44b8ed7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindExpression.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindExpression.java @@ -21,7 +21,6 @@ import org.apache.doris.catalog.Env; import org.apache.doris.catalog.FunctionRegistry; import org.apache.doris.common.Pair; import org.apache.doris.nereids.CascadesContext; -import org.apache.doris.nereids.NereidsPlanner; import org.apache.doris.nereids.SqlCacheContext; import org.apache.doris.nereids.StatementContext; import org.apache.doris.nereids.analyzer.MappingSlot; @@ -88,7 +87,7 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalSink; import org.apache.doris.nereids.trees.plans.logical.LogicalSort; import org.apache.doris.nereids.trees.plans.logical.LogicalSubQueryAlias; import org.apache.doris.nereids.trees.plans.logical.LogicalTVFRelation; -import org.apache.doris.nereids.trees.plans.logical.UsingJoin; +import org.apache.doris.nereids.trees.plans.logical.LogicalUsingJoin; import org.apache.doris.nereids.trees.plans.visitor.InferPlanOutputAlias; import org.apache.doris.nereids.types.BooleanType; import org.apache.doris.nereids.types.StructField; @@ -130,7 +129,7 @@ import java.util.stream.Collectors; */ @SuppressWarnings("OptionalUsedAsFieldOrParameterType") public class BindExpression implements AnalysisRuleFactory { - public static final Logger LOG = LogManager.getLogger(NereidsPlanner.class); + public static final Logger LOG = LogManager.getLogger(BindExpression.class); @Override public List<Rule> buildRules() { @@ -161,7 +160,7 @@ public class BindExpression implements AnalysisRuleFactory { logicalFilter().thenApply(this::bindFilter) ), RuleType.BINDING_USING_JOIN_SLOT.build( - usingJoin().thenApply(this::bindUsingJoin) + logicalUsingJoin().thenApply(this::bindUsingJoin) ), RuleType.BINDING_JOIN_SLOT.build( logicalJoin().thenApply(this::bindJoin) @@ -546,7 +545,7 @@ public class BindExpression implements AnalysisRuleFactory { return new LogicalJoin<>(join.getJoinType(), hashJoinConjuncts.build(), otherJoinConjuncts.build(), - join.getDistributeHint(), join.getMarkJoinSlotReference(), + join.getDistributeHint(), join.getMarkJoinSlotReference(), join.getExceptAsteriskOutputs(), join.children(), null); } @@ -591,16 +590,17 @@ public class BindExpression implements AnalysisRuleFactory { } } - private LogicalJoin<Plan, Plan> bindUsingJoin(MatchingContext<UsingJoin<Plan, Plan>> ctx) { - UsingJoin<Plan, Plan> using = ctx.root; + private LogicalPlan bindUsingJoin(MatchingContext<LogicalUsingJoin<Plan, Plan>> ctx) { + LogicalUsingJoin<Plan, Plan> using = ctx.root; CascadesContext cascadesContext = ctx.cascadesContext; - List<Expression> unboundHashJoinConjunct = using.getHashJoinConjuncts(); + List<Expression> unboundHashJoinConjunct = using.getUsingSlots(); - Scope leftScope = toScope(cascadesContext, ExpressionUtils.distinctSlotByName(using.left().getOutput())); - Scope rightScope = toScope(cascadesContext, ExpressionUtils.distinctSlotByName(using.right().getOutput())); + Scope leftScope = toScope(cascadesContext, using.left().getOutput(), using.left().getAsteriskOutput()); + Scope rightScope = toScope(cascadesContext, using.right().getOutput(), using.right().getAsteriskOutput()); ExpressionRewriteContext rewriteContext = new ExpressionRewriteContext(cascadesContext); Builder<Expression> hashEqExprs = ImmutableList.builderWithExpectedSize(unboundHashJoinConjunct.size()); + List<Slot> rightConjunctsSlots = Lists.newArrayList(); for (Expression usingColumn : unboundHashJoinConjunct) { ExpressionAnalyzer leftExprAnalyzer = new ExpressionAnalyzer( using, leftScope, cascadesContext, true, false); @@ -609,13 +609,14 @@ public class BindExpression implements AnalysisRuleFactory { ExpressionAnalyzer rightExprAnalyzer = new ExpressionAnalyzer( using, rightScope, cascadesContext, true, false); Expression usingRightSlot = rightExprAnalyzer.analyze(usingColumn, rewriteContext); + rightConjunctsSlots.add((Slot) usingRightSlot); hashEqExprs.add(new EqualTo(usingLeftSlot, usingRightSlot)); } return new LogicalJoin<>( using.getJoinType() == JoinType.CROSS_JOIN ? JoinType.INNER_JOIN : using.getJoinType(), - hashEqExprs.build(), using.getOtherJoinConjuncts(), - using.getDistributeHint(), using.getMarkJoinSlotReference(), + hashEqExprs.build(), ImmutableList.of(), + using.getDistributeHint(), Optional.empty(), rightConjunctsSlots, using.children(), null); } @@ -1035,11 +1036,11 @@ public class BindExpression implements AnalysisRuleFactory { private Supplier<Scope> buildAggOutputScopeWithoutAggFun( List<? extends NamedExpression> boundAggOutput, CascadesContext cascadesContext) { return Suppliers.memoize(() -> { - Builder<MappingSlot> nonAggFunOutput = ImmutableList.builderWithExpectedSize(boundAggOutput.size()); + Builder<Slot> nonAggFunOutput = ImmutableList.builderWithExpectedSize(boundAggOutput.size()); for (NamedExpression output : boundAggOutput) { if (!output.containsType(AggregateFunction.class)) { Slot outputSlot = output.toSlot(); - MappingSlot mappingSlot = new MappingSlot(outputSlot, + Slot mappingSlot = new MappingSlot(outputSlot, output instanceof Alias ? output.child(0) : output); nonAggFunOutput.add(mappingSlot); } @@ -1226,7 +1227,7 @@ public class BindExpression implements AnalysisRuleFactory { return expression; } - private Scope toScope(CascadesContext cascadesContext, List<? extends Slot> slots) { + private Scope toScope(CascadesContext cascadesContext, List<Slot> slots) { Optional<Scope> outerScope = cascadesContext.getOuterScope(); if (outerScope.isPresent()) { return new Scope(outerScope, slots); @@ -1235,11 +1236,20 @@ public class BindExpression implements AnalysisRuleFactory { } } + private Scope toScope(CascadesContext cascadesContext, List<Slot> slots, List<Slot> asteriskSlots) { + Optional<Scope> outerScope = cascadesContext.getOuterScope(); + if (outerScope.isPresent()) { + return new Scope(outerScope, slots, asteriskSlots); + } else { + return new Scope(slots, asteriskSlots); + } + } + private SimpleExprAnalyzer buildSimpleExprAnalyzer( Plan currentPlan, CascadesContext cascadesContext, List<Plan> children, boolean enableExactMatch, boolean bindSlotInOuterScope) { - List<Slot> childrenOutputs = PlanUtils.fastGetChildrenOutputs(children); - Scope scope = toScope(cascadesContext, childrenOutputs); + Scope scope = toScope(cascadesContext, PlanUtils.fastGetChildrenOutputs(children), + PlanUtils.fastGetChildrenAsteriskOutputs(children)); return buildSimpleExprAnalyzer(currentPlan, cascadesContext, scope, enableExactMatch, bindSlotInOuterScope); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java index 05d3804df2b..d7f0f637250 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ExpressionAnalyzer.java @@ -345,7 +345,7 @@ public class ExpressionAnalyzer extends SubExprAnalyzer<ExpressionRewriteContext public Expression visitUnboundStar(UnboundStar unboundStar, ExpressionRewriteContext context) { List<String> qualifier = unboundStar.getQualifier(); boolean showHidden = Util.showHiddenColumns(); - List<Slot> slots = getScope().getSlots() + List<Slot> slots = getScope().getAsteriskSlots() .stream() .filter(slot -> !(slot instanceof SlotReference) || (((SlotReference) slot).isVisible()) || showHidden) @@ -920,7 +920,7 @@ public class ExpressionAnalyzer extends SubExprAnalyzer<ExpressionRewriteContext private List<Slot> bindSingleSlotByName(String name, Scope scope) { int namePartSize = 1; Builder<Slot> usedSlots = ImmutableList.builderWithExpectedSize(1); - for (Slot boundSlot : scope.findSlotIgnoreCase(name)) { + for (Slot boundSlot : scope.findSlotIgnoreCase(name, false)) { if (!shouldBindSlotBy(namePartSize, boundSlot)) { continue; } @@ -933,7 +933,7 @@ public class ExpressionAnalyzer extends SubExprAnalyzer<ExpressionRewriteContext private List<Slot> bindSingleSlotByTable(String table, String name, Scope scope) { int namePartSize = 2; Builder<Slot> usedSlots = ImmutableList.builderWithExpectedSize(1); - for (Slot boundSlot : scope.findSlotIgnoreCase(name)) { + for (Slot boundSlot : scope.findSlotIgnoreCase(name, true)) { if (!shouldBindSlotBy(namePartSize, boundSlot)) { continue; } @@ -951,7 +951,7 @@ public class ExpressionAnalyzer extends SubExprAnalyzer<ExpressionRewriteContext private List<Slot> bindSingleSlotByDb(String db, String table, String name, Scope scope) { int namePartSize = 3; Builder<Slot> usedSlots = ImmutableList.builderWithExpectedSize(1); - for (Slot boundSlot : scope.findSlotIgnoreCase(name)) { + for (Slot boundSlot : scope.findSlotIgnoreCase(name, true)) { if (!shouldBindSlotBy(namePartSize, boundSlot)) { continue; } @@ -970,7 +970,7 @@ public class ExpressionAnalyzer extends SubExprAnalyzer<ExpressionRewriteContext private List<Slot> bindSingleSlotByCatalog(String catalog, String db, String table, String name, Scope scope) { int namePartSize = 4; Builder<Slot> usedSlots = ImmutableList.builderWithExpectedSize(1); - for (Slot boundSlot : scope.findSlotIgnoreCase(name)) { + for (Slot boundSlot : scope.findSlotIgnoreCase(name, true)) { if (!shouldBindSlotBy(namePartSize, boundSlot)) { continue; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SubExprAnalyzer.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SubExprAnalyzer.java index 9a70ce24afb..3d6ff95f809 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SubExprAnalyzer.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/SubExprAnalyzer.java @@ -206,7 +206,8 @@ class SubExprAnalyzer<T> extends DefaultExpressionRewriter<T> { cascadesContext, expr.getQueryPlan(), cascadesContext.getCteContext()); // don't use `getScope()` because we only need `getScope().getOuterScope()` and `getScope().getSlots()` // otherwise unexpected errors may occur - Scope subqueryScope = new Scope(getScope().getOuterScope(), getScope().getSlots()); + Scope subqueryScope = new Scope(getScope().getOuterScope(), + getScope().getSlots(), getScope().getAsteriskSlots()); subqueryContext.setOuterScope(subqueryScope); subqueryContext.newAnalyzer().analyze(); return new AnalyzedResult((LogicalPlan) subqueryContext.getRewritePlan(), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java index 5b08bdd2e5b..0436f1c3182 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/AbstractPlan.java @@ -19,7 +19,6 @@ package org.apache.doris.nereids.trees.plans; import org.apache.doris.nereids.analyzer.Unbound; import org.apache.doris.nereids.memo.GroupExpression; -import org.apache.doris.nereids.properties.DataTrait; import org.apache.doris.nereids.properties.LogicalProperties; import org.apache.doris.nereids.properties.UnboundLogicalProperties; import org.apache.doris.nereids.trees.AbstractTreeNode; @@ -200,9 +199,11 @@ public abstract class AbstractPlan extends AbstractTreeNode<Plan> implements Pla if (hasUnboundChild || hasUnboundExpression()) { return UnboundLogicalProperties.INSTANCE; } else { - Supplier<List<Slot>> outputSupplier = Suppliers.memoize(this::computeOutput); - Supplier<DataTrait> fdSupplier = () -> computeDataTrait(); - return new LogicalProperties(outputSupplier, fdSupplier); + if (this instanceof DiffOutputInAsterisk) { + return new LogicalProperties(this::computeOutput, this::computeAsteriskOutput, this::computeDataTrait); + } else { + return new LogicalProperties(this::computeOutput, this::computeDataTrait); + } } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/DiffOutputInAsterisk.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/DiffOutputInAsterisk.java new file mode 100644 index 00000000000..ddce0226e64 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/DiffOutputInAsterisk.java @@ -0,0 +1,39 @@ +// 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.trees.plans; + +import org.apache.doris.nereids.trees.expressions.Slot; + +import java.util.List; + +/** + * trait for plan that output in Asterisk does not contain all slot which could output, such as, UsingJoin. + */ +public interface DiffOutputInAsterisk extends Plan { + @Override + default List<Slot> getAsteriskOutput() { + boolean outputMayDiff = false; + for (Plan child : children()) { + if (child instanceof DiffOutputInAsterisk) { + outputMayDiff = true; + break; + } + } + return outputMayDiff ? getLogicalProperties().getAsteriskOutput() : getLogicalProperties().getOutput(); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/FakePlan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/FakePlan.java index 39c546cdb19..ae17a9719bf 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/FakePlan.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/FakePlan.java @@ -82,7 +82,7 @@ public class FakePlan implements Plan, BlockFuncDepsPropagation { @Override public LogicalProperties getLogicalProperties() { - return new LogicalProperties(ArrayList::new, () -> DataTrait.EMPTY_TRAIT); + return new LogicalProperties(ImmutableList::of, () -> DataTrait.EMPTY_TRAIT); } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java index 402ad046d91..5336cf5478c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/Plan.java @@ -98,6 +98,10 @@ public interface Plan extends TreeNode<Plan> { */ List<Slot> getOutput(); + default List<Slot> getAsteriskOutput() { + return getOutput(); + } + /** * Get output slot set of the plan. */ @@ -159,6 +163,10 @@ public interface Plan extends TreeNode<Plan> { throw new IllegalStateException("Not support compute output for " + getClass().getName()); } + default List<Slot> computeAsteriskOutput() { + throw new IllegalStateException("Not support compute output for " + getClass().getName()); + } + /** * Get the input relation ids set of the plan. * @return The result is collected from all inputs relations diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAssertNumRows.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAssertNumRows.java index ca2a9ff7c7d..f78b41d7bdd 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAssertNumRows.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalAssertNumRows.java @@ -25,6 +25,7 @@ import org.apache.doris.nereids.trees.expressions.AssertNumRowsElement; import org.apache.doris.nereids.trees.expressions.AssertNumRowsElement.Assertion; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.Slot; +import org.apache.doris.nereids.trees.plans.DiffOutputInAsterisk; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.PlanType; import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; @@ -44,7 +45,8 @@ import java.util.stream.Collectors; * If the number of rows is more than the desired num of rows, the query will be cancelled. * The cancelled reason will be reported by Backend and displayed back to the user. */ -public class LogicalAssertNumRows<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_TYPE> { +public class LogicalAssertNumRows<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_TYPE> + implements DiffOutputInAsterisk { private final AssertNumRowsElement assertNumRowsElement; @@ -120,6 +122,11 @@ public class LogicalAssertNumRows<CHILD_TYPE extends Plan> extends LogicalUnary< return child().getOutput().stream().map(o -> o.withNullable(true)).collect(Collectors.toList()); } + @Override + public List<Slot> computeAsteriskOutput() { + return child().getAsteriskOutput().stream().map(o -> o.withNullable(true)).collect(Collectors.toList()); + } + @Override public void computeUnique(Builder builder) { if (assertNumRowsElement.getDesiredNumOfRows() == 1 diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java index efd7e90c136..d502f8c5a2a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalFilter.java @@ -24,6 +24,7 @@ import org.apache.doris.nereids.properties.LogicalProperties; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.expressions.SubqueryExpr; +import org.apache.doris.nereids.trees.plans.DiffOutputInAsterisk; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.PlanType; import org.apache.doris.nereids.trees.plans.algebra.Filter; @@ -47,7 +48,8 @@ import java.util.stream.Stream; /** * Logical filter plan. */ -public class LogicalFilter<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_TYPE> implements Filter { +public class LogicalFilter<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_TYPE> + implements Filter, DiffOutputInAsterisk { private final Set<Expression> conjuncts; @@ -86,6 +88,11 @@ public class LogicalFilter<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_T return child().getOutput(); } + @Override + public List<Slot> computeAsteriskOutput() { + return child().getAsteriskOutput(); + } + @Override public String toString() { return Utils.toSqlString("LogicalFilter[" + id.asInt() + "]", diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalGenerate.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalGenerate.java index 3dc0577779c..6856f4a129d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalGenerate.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalGenerate.java @@ -24,6 +24,7 @@ import org.apache.doris.nereids.properties.LogicalProperties; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.expressions.functions.Function; +import org.apache.doris.nereids.trees.plans.DiffOutputInAsterisk; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.PlanType; import org.apache.doris.nereids.trees.plans.algebra.Generate; @@ -41,7 +42,8 @@ import java.util.Optional; /** * plan for table generator, the statement like: SELECT * FROM tbl LATERAL VIEW EXPLODE(c1) g as (gc1); */ -public class LogicalGenerate<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_TYPE> implements Generate { +public class LogicalGenerate<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_TYPE> + implements Generate, DiffOutputInAsterisk { private final List<Function> generators; private final List<Slot> generatorOutput; @@ -128,6 +130,14 @@ public class LogicalGenerate<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD .build(); } + @Override + public List<Slot> computeAsteriskOutput() { + return ImmutableList.<Slot>builder() + .addAll(child().getAsteriskOutput()) + .addAll(generatorOutput) + .build(); + } + @Override public String toString() { return Utils.toSqlString("LogicalGenerate", diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java index c583360c3d8..fe4f1eed64f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalJoin.java @@ -30,6 +30,7 @@ import org.apache.doris.nereids.trees.expressions.ExprId; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.MarkJoinSlotReference; import org.apache.doris.nereids.trees.expressions.Slot; +import org.apache.doris.nereids.trees.plans.DiffOutputInAsterisk; import org.apache.doris.nereids.trees.plans.DistributeType; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; @@ -60,12 +61,13 @@ import javax.annotation.Nullable; * Logical join plan. */ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends Plan> - extends LogicalBinary<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> implements Join { + extends LogicalBinary<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> implements Join, DiffOutputInAsterisk { private final JoinType joinType; private final List<Expression> otherJoinConjuncts; private final List<Expression> hashJoinConjuncts; private final List<Expression> markJoinConjuncts; + private final List<Slot> exceptAsteriskOutputs; // When the predicate condition contains subqueries and disjunctions, the join will be marked as MarkJoin. private final Optional<MarkJoinSlotReference> markJoinSlotReference; @@ -134,6 +136,15 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends markJoinSlotReference, Optional.empty(), Optional.empty(), children, otherJoinReorderContext); } + public LogicalJoin(JoinType joinType, List<Expression> hashJoinConjuncts, + List<Expression> otherJoinConjuncts, DistributeHint hint, + Optional<MarkJoinSlotReference> markJoinSlotReference, List<Slot> exceptAsteriskOutputs, + List<Plan> children, JoinReorderContext otherJoinReorderContext) { + this(joinType, hashJoinConjuncts, otherJoinConjuncts, ExpressionUtils.EMPTY_CONDITION, hint, + markJoinSlotReference, exceptAsteriskOutputs, + Optional.empty(), Optional.empty(), children, otherJoinReorderContext); + } + public LogicalJoin(JoinType joinType, List<Expression> hashJoinConjuncts, List<Expression> otherJoinConjuncts, List<Expression> markJoinConjuncts, DistributeHint hint, Optional<MarkJoinSlotReference> markJoinSlotReference, List<Plan> children, @@ -148,6 +159,18 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends Optional<GroupExpression> groupExpression, Optional<LogicalProperties> logicalProperties, List<Plan> children, JoinReorderContext joinReorderContext) { + this(joinType, hashJoinConjuncts, otherJoinConjuncts, markJoinConjuncts, hint, + markJoinSlotReference, ImmutableList.of(), + groupExpression, logicalProperties, children, joinReorderContext); + } + + private LogicalJoin(JoinType joinType, List<Expression> hashJoinConjuncts, + List<Expression> otherJoinConjuncts, List<Expression> markJoinConjuncts, + DistributeHint hint, Optional<MarkJoinSlotReference> markJoinSlotReference, + List<Slot> exceptAsteriskOutputs, + Optional<GroupExpression> groupExpression, + Optional<LogicalProperties> logicalProperties, List<Plan> children, + JoinReorderContext joinReorderContext) { // Just use in withXXX method. Don't need check/copyOf() super(PlanType.LOGICAL_JOIN, groupExpression, logicalProperties, children); this.joinType = Objects.requireNonNull(joinType, "joinType can not be null"); @@ -159,6 +182,7 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends this.joinReorderContext.copyFrom(joinReorderContext); } this.markJoinSlotReference = markJoinSlotReference; + this.exceptAsteriskOutputs = exceptAsteriskOutputs; } public LogicalJoin<? extends Plan, ? extends Plan> swap() { @@ -257,6 +281,23 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends .build(); } + @Override + public List<Slot> computeAsteriskOutput() { + List<Slot> output = Lists.newArrayList(JoinUtils.getJoinOutput(joinType, left(), right(), true)); + if (isMarkJoin()) { + output.add(markJoinSlotReference.get()); + } + output.removeAll(exceptAsteriskOutputs); + return output; + } + + @Override + public List<Slot> getAsteriskOutput() { + boolean outputIsDiff = !exceptAsteriskOutputs.isEmpty(); + return outputIsDiff ? getLogicalProperties().getAsteriskOutput() + : DiffOutputInAsterisk.super.getAsteriskOutput(); + } + @Override public String toString() { List<Object> args = Lists.newArrayList( @@ -286,12 +327,14 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends && hashJoinConjuncts.equals(that.hashJoinConjuncts) && otherJoinConjuncts.equals(that.otherJoinConjuncts) && markJoinConjuncts.equals(that.markJoinConjuncts) + && exceptAsteriskOutputs.equals(that.exceptAsteriskOutputs) && Objects.equals(markJoinSlotReference, that.markJoinSlotReference); } @Override public int hashCode() { - return Objects.hash(joinType, hashJoinConjuncts, otherJoinConjuncts, markJoinConjuncts, markJoinSlotReference); + return Objects.hash(joinType, hashJoinConjuncts, otherJoinConjuncts, + markJoinConjuncts, markJoinSlotReference, exceptAsteriskOutputs); } @Override @@ -312,6 +355,10 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends return markJoinSlotReference; } + public List<Slot> getExceptAsteriskOutputs() { + return exceptAsteriskOutputs; + } + public long getBitmap() { return bitmap; } @@ -334,15 +381,15 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends public LogicalJoin<Plan, Plan> withChildren(List<Plan> children) { Preconditions.checkArgument(children.size() == 2); return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, markJoinConjuncts, - hint, markJoinSlotReference, Optional.empty(), Optional.empty(), children, - joinReorderContext); + hint, markJoinSlotReference, exceptAsteriskOutputs, + Optional.empty(), Optional.empty(), children, joinReorderContext); } @Override public LogicalJoin<Plan, Plan> withGroupExpression(Optional<GroupExpression> groupExpression) { return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, markJoinConjuncts, - hint, markJoinSlotReference, groupExpression, Optional.of(getLogicalProperties()), - children, joinReorderContext); + hint, markJoinSlotReference, exceptAsteriskOutputs, + groupExpression, Optional.of(getLogicalProperties()), children, joinReorderContext); } @Override @@ -350,15 +397,15 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends Optional<LogicalProperties> logicalProperties, List<Plan> children) { Preconditions.checkArgument(children.size() == 2); return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, markJoinConjuncts, - hint, markJoinSlotReference, groupExpression, logicalProperties, children, - joinReorderContext); + hint, markJoinSlotReference, exceptAsteriskOutputs, + groupExpression, logicalProperties, children, joinReorderContext); } public LogicalJoin<Plan, Plan> withChildrenNoContext(Plan left, Plan right, JoinReorderContext otherJoinReorderContext) { return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, markJoinConjuncts, - hint, markJoinSlotReference, Optional.empty(), Optional.empty(), - ImmutableList.of(left, right), otherJoinReorderContext); + hint, markJoinSlotReference, exceptAsteriskOutputs, + Optional.empty(), Optional.empty(), ImmutableList.of(left, right), otherJoinReorderContext); } /** @@ -367,61 +414,59 @@ public class LogicalJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends public LogicalJoin<Plan, Plan> withJoinConjuncts(List<Expression> hashJoinConjuncts, List<Expression> otherJoinConjuncts, JoinReorderContext otherJoinReorderContext) { return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, markJoinConjuncts, - hint, markJoinSlotReference, Optional.empty(), Optional.empty(), - children, otherJoinReorderContext); + hint, markJoinSlotReference, exceptAsteriskOutputs, + Optional.empty(), Optional.empty(), children, otherJoinReorderContext); } public LogicalJoin<Plan, Plan> withJoinConjuncts(List<Expression> hashJoinConjuncts, - List<Expression> otherJoinConjuncts, - List<Expression> markJoinConjuncts, - JoinReorderContext otherJoinReorderContext) { + List<Expression> otherJoinConjuncts, List<Expression> markJoinConjuncts, + JoinReorderContext otherJoinReorderContext) { return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, markJoinConjuncts, - hint, markJoinSlotReference, Optional.empty(), Optional.of(getLogicalProperties()), - children, otherJoinReorderContext); + hint, markJoinSlotReference, exceptAsteriskOutputs, + Optional.empty(), Optional.of(getLogicalProperties()), children, otherJoinReorderContext); } public LogicalJoin<Plan, Plan> withHashJoinConjunctsAndChildren( List<Expression> hashJoinConjuncts, Plan left, Plan right, JoinReorderContext otherJoinReorderContext) { Preconditions.checkArgument(children.size() == 2); return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, markJoinConjuncts, - hint, markJoinSlotReference, Optional.empty(), Optional.empty(), - ImmutableList.of(left, right), otherJoinReorderContext); + hint, markJoinSlotReference, exceptAsteriskOutputs, + Optional.empty(), Optional.empty(), ImmutableList.of(left, right), otherJoinReorderContext); } public LogicalJoin<Plan, Plan> withConjunctsChildren(List<Expression> hashJoinConjuncts, List<Expression> otherJoinConjuncts, Plan left, Plan right, JoinReorderContext otherJoinReorderContext) { return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, markJoinConjuncts, - hint, markJoinSlotReference, Optional.empty(), Optional.empty(), - ImmutableList.of(left, right), otherJoinReorderContext); + hint, markJoinSlotReference, exceptAsteriskOutputs, + Optional.empty(), Optional.empty(), ImmutableList.of(left, right), otherJoinReorderContext); } public LogicalJoin<Plan, Plan> withConjunctsChildren(List<Expression> hashJoinConjuncts, - List<Expression> otherJoinConjuncts, - List<Expression> markJoinConjuncts, Plan left, Plan right, - JoinReorderContext otherJoinReorderContext) { + List<Expression> otherJoinConjuncts, List<Expression> markJoinConjuncts, Plan left, Plan right, + JoinReorderContext otherJoinReorderContext) { return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, markJoinConjuncts, - hint, markJoinSlotReference, Optional.empty(), Optional.empty(), - ImmutableList.of(left, right), otherJoinReorderContext); + hint, markJoinSlotReference, exceptAsteriskOutputs, + Optional.empty(), Optional.empty(), ImmutableList.of(left, right), otherJoinReorderContext); } public LogicalJoin<Plan, Plan> withJoinType(JoinType joinType) { return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, markJoinConjuncts, - hint, markJoinSlotReference, groupExpression, Optional.of(getLogicalProperties()), - children, joinReorderContext); + hint, markJoinSlotReference, exceptAsteriskOutputs, + groupExpression, Optional.of(getLogicalProperties()), children, joinReorderContext); } public LogicalJoin<Plan, Plan> withJoinTypeAndContext(JoinType joinType, JoinReorderContext otherJoinReorderContext) { return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, markJoinConjuncts, - hint, markJoinSlotReference, Optional.empty(), Optional.empty(), - children, otherJoinReorderContext); + hint, markJoinSlotReference, exceptAsteriskOutputs, + Optional.empty(), Optional.empty(), children, otherJoinReorderContext); } public LogicalJoin<Plan, Plan> withTypeChildren(JoinType joinType, Plan left, Plan right, - JoinReorderContext otherJoinReorderContext) { + JoinReorderContext otherJoinReorderContext) { return new LogicalJoin<>(joinType, hashJoinConjuncts, otherJoinConjuncts, markJoinConjuncts, - hint, markJoinSlotReference, Optional.empty(), Optional.empty(), - ImmutableList.of(left, right), otherJoinReorderContext); + hint, markJoinSlotReference, exceptAsteriskOutputs, + Optional.empty(), Optional.empty(), ImmutableList.of(left, right), otherJoinReorderContext); } /** diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSelectHint.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSelectHint.java index a33e2194131..10b67a84f4e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSelectHint.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSelectHint.java @@ -23,6 +23,7 @@ import org.apache.doris.nereids.properties.SelectHint; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.plans.BlockFuncDepsPropagation; +import org.apache.doris.nereids.trees.plans.DiffOutputInAsterisk; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.PlanType; import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; @@ -40,7 +41,7 @@ import java.util.stream.Collectors; * e.g. LogicalSelectHint (set_var(query_timeout='1800', exec_mem_limit='2147483648')) */ public class LogicalSelectHint<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_TYPE> - implements BlockFuncDepsPropagation { + implements BlockFuncDepsPropagation, DiffOutputInAsterisk { private final ImmutableList<SelectHint> hints; @@ -113,6 +114,11 @@ public class LogicalSelectHint<CHILD_TYPE extends Plan> extends LogicalUnary<CHI return child().getOutput(); } + @Override + public List<Slot> computeAsteriskOutput() { + return child().getAsteriskOutput(); + } + @Override public String toString() { String hintStr = this.hints diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java index 331ceda3159..adedc0343a8 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSubQueryAlias.java @@ -22,6 +22,7 @@ import org.apache.doris.nereids.properties.DataTrait; import org.apache.doris.nereids.properties.LogicalProperties; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.Slot; +import org.apache.doris.nereids.trees.plans.DiffOutputInAsterisk; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.PlanType; import org.apache.doris.nereids.trees.plans.RelationId; @@ -47,7 +48,8 @@ import java.util.Set; * * @param <CHILD_TYPE> param */ -public class LogicalSubQueryAlias<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_TYPE> { +public class LogicalSubQueryAlias<CHILD_TYPE extends Plan> extends LogicalUnary<CHILD_TYPE> + implements DiffOutputInAsterisk { protected RelationId relationId; private final List<String> qualifier; @@ -79,7 +81,16 @@ public class LogicalSubQueryAlias<CHILD_TYPE extends Plan> extends LogicalUnary< @Override public List<Slot> computeOutput() { - List<Slot> childOutput = child().getOutput(); + return computeOutputInternal(false); + } + + @Override + public List<Slot> computeAsteriskOutput() { + return computeOutputInternal(true); + } + + private List<Slot> computeOutputInternal(boolean asteriskOutput) { + List<Slot> childOutput = asteriskOutput ? child().getAsteriskOutput() : child().getOutput(); List<String> columnAliases = this.columnAliases.orElseGet(ImmutableList::of); ImmutableList.Builder<Slot> currentOutput = ImmutableList.builder(); for (int i = 0; i < childOutput.size(); i++) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUsingJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUsingJoin.java new file mode 100644 index 00000000000..1d2b3c077df --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalUsingJoin.java @@ -0,0 +1,149 @@ +// 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.trees.plans.logical; + +import org.apache.doris.nereids.hint.DistributeHint; +import org.apache.doris.nereids.memo.GroupExpression; +import org.apache.doris.nereids.properties.LogicalProperties; +import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.Slot; +import org.apache.doris.nereids.trees.plans.BlockFuncDepsPropagation; +import org.apache.doris.nereids.trees.plans.DistributeType; +import org.apache.doris.nereids.trees.plans.JoinType; +import org.apache.doris.nereids.trees.plans.Plan; +import org.apache.doris.nereids.trees.plans.PlanType; +import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; +import org.apache.doris.nereids.util.ExpressionUtils; +import org.apache.doris.nereids.util.JoinUtils; +import org.apache.doris.nereids.util.Utils; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +/** + * select col1 from t1 join t2 using(col1); + */ +public class LogicalUsingJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends Plan> + extends LogicalBinary<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> implements BlockFuncDepsPropagation { + + private final JoinType joinType; + private final ImmutableList<Expression> usingSlots; + private final DistributeHint hint; + + public LogicalUsingJoin(JoinType joinType, LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild, + List<Expression> usingSlots, DistributeHint hint) { + this(joinType, leftChild, rightChild, usingSlots, Optional.empty(), Optional.empty(), hint); + } + + /** + * Constructor. + */ + public LogicalUsingJoin(JoinType joinType, LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild, + List<Expression> usingSlots, Optional<GroupExpression> groupExpression, + Optional<LogicalProperties> logicalProperties, DistributeHint hint) { + super(PlanType.LOGICAL_USING_JOIN, groupExpression, logicalProperties, leftChild, rightChild); + this.joinType = joinType; + this.usingSlots = ImmutableList.copyOf(usingSlots); + this.hint = hint; + } + + @Override + public List<Slot> computeOutput() { + return JoinUtils.getJoinOutput(joinType, left(), right()); + } + + @Override + public Plan withGroupExpression(Optional<GroupExpression> groupExpression) { + return new LogicalUsingJoin<>(joinType, child(0), child(1), + usingSlots, groupExpression, Optional.of(getLogicalProperties()), hint); + } + + @Override + public Plan withGroupExprLogicalPropChildren(Optional<GroupExpression> groupExpression, + Optional<LogicalProperties> logicalProperties, List<Plan> children) { + return new LogicalUsingJoin<>(joinType, children.get(0), children.get(1), + usingSlots, groupExpression, logicalProperties, hint); + } + + @Override + public Plan withChildren(List<Plan> children) { + return new LogicalUsingJoin<>(joinType, children.get(0), children.get(1), + usingSlots, groupExpression, Optional.of(getLogicalProperties()), hint); + } + + @Override + public <R, C> R accept(PlanVisitor<R, C> visitor, C context) { + return visitor.visit(this, context); + } + + @Override + public List<? extends Expression> getExpressions() { + return usingSlots; + } + + public JoinType getJoinType() { + return joinType; + } + + public List<Expression> getUsingSlots() { + return usingSlots; + } + + public DistributeHint getDistributeHint() { + return hint; + } + + public List<Expression> getMarkJoinConjuncts() { + return ExpressionUtils.EMPTY_CONDITION; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + LogicalUsingJoin<?, ?> usingJoin = (LogicalUsingJoin<?, ?>) o; + return joinType == usingJoin.joinType + && Objects.equals(usingSlots, usingJoin.usingSlots) + && Objects.equals(hint, usingJoin.hint); + } + + @Override + public int hashCode() { + return Objects.hash(joinType, usingSlots, hint); + } + + @Override + public String toString() { + List<Object> args = Lists.newArrayList( + "type", joinType, + "usingSlots", usingSlots); + if (hint.distributeType != DistributeType.NONE) { + args.add("hint"); + args.add(hint.getExplainString()); + } + return Utils.toSqlString("UsingJoin[" + id.asInt() + "]", args.toArray()); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/UsingJoin.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/UsingJoin.java deleted file mode 100644 index 62cb542e78a..00000000000 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/UsingJoin.java +++ /dev/null @@ -1,217 +0,0 @@ -// 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.trees.plans.logical; - -import org.apache.doris.nereids.hint.DistributeHint; -import org.apache.doris.nereids.memo.GroupExpression; -import org.apache.doris.nereids.properties.LogicalProperties; -import org.apache.doris.nereids.trees.expressions.Expression; -import org.apache.doris.nereids.trees.expressions.MarkJoinSlotReference; -import org.apache.doris.nereids.trees.expressions.Slot; -import org.apache.doris.nereids.trees.plans.BlockFuncDepsPropagation; -import org.apache.doris.nereids.trees.plans.DistributeType; -import org.apache.doris.nereids.trees.plans.JoinType; -import org.apache.doris.nereids.trees.plans.Plan; -import org.apache.doris.nereids.trees.plans.PlanType; -import org.apache.doris.nereids.trees.plans.algebra.Join; -import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; -import org.apache.doris.nereids.util.ExpressionUtils; -import org.apache.doris.nereids.util.Utils; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableList.Builder; -import com.google.common.collect.Lists; - -import java.util.List; -import java.util.Objects; -import java.util.Optional; - -/** - * select col1 from t1 join t2 using(col1); - */ -public class UsingJoin<LEFT_CHILD_TYPE extends Plan, RIGHT_CHILD_TYPE extends Plan> - extends LogicalBinary<LEFT_CHILD_TYPE, RIGHT_CHILD_TYPE> implements Join, BlockFuncDepsPropagation { - - private final JoinType joinType; - private final ImmutableList<Expression> otherJoinConjuncts; - private final ImmutableList<Expression> hashJoinConjuncts; - private final DistributeHint hint; - - public UsingJoin(JoinType joinType, LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild, - List<Expression> expressions, List<Expression> hashJoinConjuncts, - DistributeHint hint) { - this(joinType, leftChild, rightChild, expressions, - hashJoinConjuncts, Optional.empty(), Optional.empty(), hint); - } - - /** - * Constructor. - */ - public UsingJoin(JoinType joinType, LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild, - List<Expression> expressions, List<Expression> hashJoinConjuncts, Optional<GroupExpression> groupExpression, - Optional<LogicalProperties> logicalProperties, - DistributeHint hint) { - super(PlanType.LOGICAL_USING_JOIN, groupExpression, logicalProperties, leftChild, rightChild); - this.joinType = joinType; - this.otherJoinConjuncts = ImmutableList.copyOf(expressions); - this.hashJoinConjuncts = ImmutableList.copyOf(hashJoinConjuncts); - this.hint = hint; - } - - @Override - public List<Slot> computeOutput() { - - List<Slot> newLeftOutput = left().getOutput().stream().map(o -> o.withNullable(true)) - .collect(ImmutableList.toImmutableList()); - - List<Slot> newRightOutput = right().getOutput().stream().map(o -> o.withNullable(true)) - .collect(ImmutableList.toImmutableList()); - - switch (joinType) { - case LEFT_SEMI_JOIN: - case LEFT_ANTI_JOIN: - return ImmutableList.copyOf(left().getOutput()); - case RIGHT_SEMI_JOIN: - case RIGHT_ANTI_JOIN: - return ImmutableList.copyOf(right().getOutput()); - case LEFT_OUTER_JOIN: - return ImmutableList.<Slot>builder() - .addAll(left().getOutput()) - .addAll(newRightOutput) - .build(); - case RIGHT_OUTER_JOIN: - return ImmutableList.<Slot>builder() - .addAll(newLeftOutput) - .addAll(right().getOutput()) - .build(); - case FULL_OUTER_JOIN: - return ImmutableList.<Slot>builder() - .addAll(newLeftOutput) - .addAll(newRightOutput) - .build(); - default: - return ImmutableList.<Slot>builder() - .addAll(left().getOutput()) - .addAll(right().getOutput()) - .build(); - } - } - - @Override - public Plan withGroupExpression(Optional<GroupExpression> groupExpression) { - return new UsingJoin(joinType, child(0), child(1), otherJoinConjuncts, - hashJoinConjuncts, groupExpression, Optional.of(getLogicalProperties()), hint); - } - - @Override - public Plan withGroupExprLogicalPropChildren(Optional<GroupExpression> groupExpression, - Optional<LogicalProperties> logicalProperties, List<Plan> children) { - return new UsingJoin(joinType, children.get(0), children.get(1), otherJoinConjuncts, - hashJoinConjuncts, groupExpression, logicalProperties, hint); - } - - @Override - public Plan withChildren(List<Plan> children) { - return new UsingJoin(joinType, children.get(0), children.get(1), otherJoinConjuncts, - hashJoinConjuncts, groupExpression, Optional.of(getLogicalProperties()), hint); - } - - @Override - public <R, C> R accept(PlanVisitor<R, C> visitor, C context) { - return visitor.visit(this, context); - } - - @Override - public List<? extends Expression> getExpressions() { - return new Builder<Expression>() - .addAll(hashJoinConjuncts) - .addAll(otherJoinConjuncts) - .build(); - } - - public JoinType getJoinType() { - return joinType; - } - - public List<Expression> getOtherJoinConjuncts() { - return otherJoinConjuncts; - } - - public List<Expression> getHashJoinConjuncts() { - return hashJoinConjuncts; - } - - public DistributeHint getDistributeHint() { - return hint; - } - - public boolean isMarkJoin() { - return false; - } - - public Optional<MarkJoinSlotReference> getMarkJoinSlotReference() { - return Optional.empty(); - } - - public List<Expression> getMarkJoinConjuncts() { - return ExpressionUtils.EMPTY_CONDITION; - } - - @Override - public Optional<Expression> getOnClauseCondition() { - return ExpressionUtils.optionalAnd(hashJoinConjuncts, otherJoinConjuncts); - } - - @Override - public boolean hasDistributeHint() { - return hint != null; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - UsingJoin<?, ?> usingJoin = (UsingJoin<?, ?>) o; - return joinType == usingJoin.joinType - && Objects.equals(otherJoinConjuncts, usingJoin.otherJoinConjuncts) - && Objects.equals(hashJoinConjuncts, usingJoin.hashJoinConjuncts) - && Objects.equals(hint, usingJoin.hint); - } - - @Override - public int hashCode() { - return Objects.hash(joinType, otherJoinConjuncts, hashJoinConjuncts, hint); - } - - @Override - public String toString() { - List<Object> args = Lists.newArrayList( - "type", joinType, - "hashJoinConjuncts", hashJoinConjuncts, - "otherJoinConjuncts", otherJoinConjuncts); - if (hint.distributeType != DistributeType.NONE) { - args.add("hint"); - args.add(hint.getExplainString()); - } - return Utils.toSqlString("UsingJoin[" + id.asInt() + "]", args.toArray()); - } -} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalSqlCache.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalSqlCache.java index 2b2c7ac0428..afba3add8d7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalSqlCache.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalSqlCache.java @@ -66,7 +66,7 @@ public class PhysicalSqlCache extends PhysicalLeaf Optional<ResultSet> resultSet, List<InternalService.PCacheValue> cacheValues, String backendAddress, String planBody) { super(PlanType.PHYSICAL_SQL_CACHE, Optional.empty(), - new LogicalProperties(() -> ImmutableList.of(), () -> DataTrait.EMPTY_TRAIT)); + new LogicalProperties(ImmutableList::of, () -> DataTrait.EMPTY_TRAIT)); this.queryId = Objects.requireNonNull(queryId, "queryId can not be null"); this.columnLabels = Objects.requireNonNull(columnLabels, "colNames can not be null"); this.fieldInfos = Objects.requireNonNull(fieldInfos, "fieldInfos can not be null"); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/JoinUtils.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/JoinUtils.java index 770905bf199..863f9f92ab2 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/JoinUtils.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/JoinUtils.java @@ -420,33 +420,49 @@ public class JoinUtils { * @return return the output slots */ public static List<Slot> getJoinOutput(JoinType joinType, Plan left, Plan right) { + return getJoinOutput(joinType, left, right, false); + } + + /** + * calculate the output slot of a join operator according join type and its children + * + * @param joinType the type of join operator + * @param left left child + * @param right right child + * @param asteriskOutput when true, return output for asterisk + * + * @return return the output slots + */ + public static List<Slot> getJoinOutput(JoinType joinType, Plan left, Plan right, boolean asteriskOutput) { + List<Slot> leftOutput = asteriskOutput ? left.getAsteriskOutput() : left.getOutput(); + List<Slot> rightOutput = asteriskOutput ? right.getAsteriskOutput() : right.getOutput(); switch (joinType) { case LEFT_SEMI_JOIN: case LEFT_ANTI_JOIN: case NULL_AWARE_LEFT_ANTI_JOIN: - return ImmutableList.copyOf(left.getOutput()); + return ImmutableList.copyOf(leftOutput); case RIGHT_SEMI_JOIN: case RIGHT_ANTI_JOIN: - return ImmutableList.copyOf(right.getOutput()); + return ImmutableList.copyOf(rightOutput); case LEFT_OUTER_JOIN: return ImmutableList.<Slot>builder() - .addAll(left.getOutput()) - .addAll(applyNullable(right.getOutput(), true)) + .addAll(leftOutput) + .addAll(applyNullable(rightOutput, true)) .build(); case RIGHT_OUTER_JOIN: return ImmutableList.<Slot>builder() - .addAll(applyNullable(left.getOutput(), true)) - .addAll(right.getOutput()) + .addAll(applyNullable(leftOutput, true)) + .addAll(rightOutput) .build(); case FULL_OUTER_JOIN: return ImmutableList.<Slot>builder() - .addAll(applyNullable(left.getOutput(), true)) - .addAll(applyNullable(right.getOutput(), true)) + .addAll(applyNullable(leftOutput, true)) + .addAll(applyNullable(rightOutput, true)) .build(); default: return ImmutableList.<Slot>builder() - .addAll(left.getOutput()) - .addAll(right.getOutput()) + .addAll(leftOutput) + .addAll(rightOutput) .build(); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/PlanUtils.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/PlanUtils.java index 28f7cda427e..7438e46ddc7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/PlanUtils.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/PlanUtils.java @@ -179,6 +179,30 @@ public class PlanUtils { return output.build(); } + /** fastGetChildrenOutput */ + public static List<Slot> fastGetChildrenAsteriskOutputs(List<Plan> children) { + switch (children.size()) { + case 1: return children.get(0).getAsteriskOutput(); + case 0: return ImmutableList.of(); + default: { + } + } + + int outputNum = 0; + // child.output is cached by AbstractPlan.logicalProperties, + // we can compute output num without the overhead of re-compute output + for (Plan child : children) { + List<Slot> output = child.getAsteriskOutput(); + outputNum += output.size(); + } + // generate output list only copy once and without resize the list + Builder<Slot> output = ImmutableList.builderWithExpectedSize(outputNum); + for (Plan child : children) { + output.addAll(child.getAsteriskOutput()); + } + return output.build(); + } + /** fastGetInputSlots */ public static Set<Slot> fastGetInputSlots(List<? extends Expression> expressions) { switch (expressions.size()) { diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/BindSlotReferenceTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/BindSlotReferenceTest.java index 8e790dcf0e7..63fa700f23c 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/BindSlotReferenceTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/BindSlotReferenceTest.java @@ -34,7 +34,7 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan; import org.apache.doris.nereids.trees.plans.logical.LogicalPlan; import org.apache.doris.nereids.trees.plans.logical.LogicalProject; import org.apache.doris.nereids.trees.plans.logical.LogicalSubQueryAlias; -import org.apache.doris.nereids.trees.plans.logical.UsingJoin; +import org.apache.doris.nereids.trees.plans.logical.LogicalUsingJoin; import org.apache.doris.nereids.util.MemoPatternMatchSupported; import org.apache.doris.nereids.util.MemoTestUtils; import org.apache.doris.nereids.util.PlanChecker; @@ -159,15 +159,14 @@ class BindSlotReferenceTest implements MemoPatternMatchSupported { LogicalSubQueryAlias<LogicalOlapScan> sub3 = new LogicalSubQueryAlias<>("t3", scan3); DistributeHint hint = new DistributeHint(DistributeType.NONE); - UsingJoin<LogicalSubQueryAlias<LogicalOlapScan>, LogicalSubQueryAlias<LogicalOlapScan>> - using1 = new UsingJoin<>(JoinType.LEFT_OUTER_JOIN, sub1, - sub2, ImmutableList.of(), ImmutableList.of(new UnboundSlot("id")), hint); - - UsingJoin<UsingJoin<LogicalSubQueryAlias<LogicalOlapScan>, LogicalSubQueryAlias<LogicalOlapScan>>, - LogicalSubQueryAlias<LogicalOlapScan>> using2 - = new UsingJoin<>( - JoinType.LEFT_OUTER_JOIN, using1, sub3, ImmutableList.of(), - ImmutableList.of(new UnboundSlot("id")), hint); + LogicalUsingJoin<LogicalSubQueryAlias<LogicalOlapScan>, LogicalSubQueryAlias<LogicalOlapScan>> + using1 = new LogicalUsingJoin<>(JoinType.LEFT_OUTER_JOIN, sub1, + sub2, ImmutableList.of(new UnboundSlot("id")), hint); + + LogicalUsingJoin<LogicalUsingJoin<LogicalSubQueryAlias<LogicalOlapScan>, LogicalSubQueryAlias<LogicalOlapScan>>, + LogicalSubQueryAlias<LogicalOlapScan>> using2 = new LogicalUsingJoin<>( + JoinType.LEFT_OUTER_JOIN, using1, sub3, + ImmutableList.of(new UnboundSlot("id")), hint); PlanChecker.from(MemoTestUtils.createConnectContext()) .analyze(using2) diff --git a/regression-test/data/nereids_p0/join/test_join2.out b/regression-test/data/nereids_p0/join/test_join2.out index 13b0f74dc79..23b5592ae72 100644 Binary files a/regression-test/data/nereids_p0/join/test_join2.out and b/regression-test/data/nereids_p0/join/test_join2.out differ diff --git a/regression-test/data/nereids_p0/join/test_join3.out b/regression-test/data/nereids_p0/join/test_join3.out index 54eb521e21f..a85be3f68b7 100644 Binary files a/regression-test/data/nereids_p0/join/test_join3.out and b/regression-test/data/nereids_p0/join/test_join3.out differ diff --git a/regression-test/data/nereids_syntax_p0/test_join3.out b/regression-test/data/nereids_syntax_p0/test_join3.out index 54eb521e21f..a85be3f68b7 100644 Binary files a/regression-test/data/nereids_syntax_p0/test_join3.out and b/regression-test/data/nereids_syntax_p0/test_join3.out differ diff --git a/regression-test/data/nereids_syntax_p0/using_join.out b/regression-test/data/nereids_syntax_p0/using_join.out index 577c514b37d..4b034542dc5 100644 Binary files a/regression-test/data/nereids_syntax_p0/using_join.out and b/regression-test/data/nereids_syntax_p0/using_join.out differ diff --git a/regression-test/data/query_p0/join/test_join2.out b/regression-test/data/query_p0/join/test_join2.out index 13b0f74dc79..23b5592ae72 100644 Binary files a/regression-test/data/query_p0/join/test_join2.out and b/regression-test/data/query_p0/join/test_join2.out differ diff --git a/regression-test/data/query_p0/join/test_join3.out b/regression-test/data/query_p0/join/test_join3.out index 54eb521e21f..a85be3f68b7 100644 Binary files a/regression-test/data/query_p0/join/test_join3.out and b/regression-test/data/query_p0/join/test_join3.out differ diff --git a/regression-test/suites/nereids_p0/join/test_join2.groovy b/regression-test/suites/nereids_p0/join/test_join2.groovy index 2e17d5c8db1..abb1744430d 100644 --- a/regression-test/suites/nereids_p0/join/test_join2.groovy +++ b/regression-test/suites/nereids_p0/join/test_join2.groovy @@ -70,14 +70,14 @@ suite("test_join2", "query,p0") { SELECT '' AS "xxx", * FROM ${TBname1} INNER JOIN ${TBname2} USING (i) - ORDER BY 1,2,3,4,5,6; + ORDER BY 1,2,3,4,5; """ qt_join2 """ SELECT '' AS "xxx", * FROM ${TBname1} JOIN ${TBname2} USING (i) - ORDER BY 1,2,3,4,5,6; + ORDER BY 1,2,3,4,5; """ test { @@ -116,52 +116,52 @@ suite("test_join2", "query,p0") { qt_join6 """ SELECT '' AS "xxx", * FROM ${TBname1} LEFT OUTER JOIN ${TBname2} USING (i) - ORDER BY 1,2,3,4,5,6; + ORDER BY 1,2,3,4,5; """ qt_join7 """ SELECT '' AS "xxx", * FROM ${TBname1} LEFT JOIN ${TBname2} USING (i) - ORDER BY 1,2,3,4,5,6; + ORDER BY 1,2,3,4,5; """ qt_join8 """ SELECT '' AS "xxx", * FROM ${TBname1} RIGHT OUTER JOIN ${TBname2} USING (i) - ORDER BY 1,2,3,4,5,6; + ORDER BY 1,2,3,4,5; """ qt_join9 """ SELECT '' AS "xxx", * FROM ${TBname1} RIGHT JOIN ${TBname2} USING (i) - ORDER BY 1,2,3,4,5,6; + ORDER BY 1,2,3,4,5; """ qt_join10 """ SELECT '' AS "xxx", * FROM ${TBname1} FULL OUTER JOIN ${TBname2} USING (i) - ORDER BY 1,2,3,4,5,6; + ORDER BY 1,2,3,4,5; """ qt_join11 """ SELECT '' AS "xxx", * FROM ${TBname1} FULL JOIN ${TBname2} USING (i) - ORDER BY 1,2,3,4,5,6; + ORDER BY 1,2,3,4,5; """ qt_join12 """ SELECT '' AS "xxx", * FROM ${TBname1} LEFT JOIN ${TBname2} USING (i) WHERE (k = 1) - ORDER BY 1,2,3,4,5,6; + ORDER BY 1,2,3,4,5; """ qt_join13 """ SELECT '' AS "xxx", * FROM ${TBname1} LEFT JOIN ${TBname2} USING (i) WHERE (${TBname1}.i = 1) - ORDER BY 1,2,3,4,5,6; + ORDER BY 1,2,3,4,5; """ sql "DROP TABLE IF EXISTS ${TBname1};" diff --git a/regression-test/suites/nereids_syntax_p0/using_join.groovy b/regression-test/suites/nereids_syntax_p0/using_join.groovy index 795dc07b483..bb9d1500f60 100644 --- a/regression-test/suites/nereids_syntax_p0/using_join.groovy +++ b/regression-test/suites/nereids_syntax_p0/using_join.groovy @@ -16,62 +16,140 @@ // under the License. suite("nereids_using_join") { + sql """DROP TABLE IF EXISTS nereids_using_join_t1""" + sql """DROP TABLE IF EXISTS nereids_using_join_t2""" + sql """DROP TABLE IF EXISTS nereids_using_join_t3""" + sql """DROP TABLE IF EXISTS nereids_using_join_t4""" + sql """ - SET enable_fallback_to_original_planner=false + CREATE TABLE `nereids_using_join_t1` ( + `c1` int, + `c2` int, + `c3` int, + `c4` array<int>, + `v1` int + ) + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1" + ); """ sql """ - SET enable_nereids_planner=true + CREATE TABLE `nereids_using_join_t2` ( + `c1` int, + `c2` int, + `v2` int + ) + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1" + ); """ - sql """DROP TABLE IF EXISTS nereids_using_join_t1""" - sql """ - CREATE TABLE `nereids_using_join_t1` ( - `col1` varchar(4) NULL, - `col2` int(11) NULL, - `col3` int(11) NULL - ) ENGINE=OLAP - DUPLICATE KEY(`col1`) - COMMENT 'OLAP' - DISTRIBUTED BY HASH(`col3`) BUCKETS 1 + CREATE TABLE `nereids_using_join_t3` ( + `c1` int, + `v3` int + ) PROPERTIES ( - "replication_allocation" = "tag.location.default: 1" + "replication_allocation" = "tag.location.default: 1" ); """ - sql """DROP TABLE IF EXISTS nereids_using_join_t2""" - sql """ - CREATE TABLE `nereids_using_join_t2` ( - `col1` varchar(4) NULL, - `col2` int(11) NULL, - `col3` int(11) NULL - ) ENGINE=OLAP - DUPLICATE KEY(`col1`) - COMMENT 'OLAP' - DISTRIBUTED BY HASH(`col3`) BUCKETS 1 + CREATE TABLE `nereids_using_join_t4` ( + `c1` int, + `c5` int, + `v4` int + ) PROPERTIES ( - "replication_allocation" = "tag.location.default: 1" + "replication_allocation" = "tag.location.default: 1" ); """ - sql """INSERT INTO nereids_using_join_t1 VALUES('1', 1, 1)""" - sql """INSERT INTO nereids_using_join_t1 VALUES('2', 2, 1)""" - sql """INSERT INTO nereids_using_join_t1 VALUES('3', 3, 1)""" - sql """INSERT INTO nereids_using_join_t1 VALUES('4', 4, 1)""" + sql """INSERT INTO nereids_using_join_t1 VALUES(1, 1, 1, [1, 2, 3, 4], 11)""" + sql """INSERT INTO nereids_using_join_t1 VALUES(2, 3, 4, [5, 6, 7, 8], 12)""" + sql """INSERT INTO nereids_using_join_t2 VALUES(1, 1, 21)""" + sql """INSERT INTO nereids_using_join_t2 VALUES(1, 2, 22)""" + sql """INSERT INTO nereids_using_join_t2 VALUES(1, 3, 23)""" + sql """INSERT INTO nereids_using_join_t3 VALUES(1, 31)""" + sql """INSERT INTO nereids_using_join_t3 VALUES(2, 32)""" + sql """INSERT INTO nereids_using_join_t3 VALUES(3, 33)""" + sql """INSERT INTO nereids_using_join_t3 VALUES(4, 34)""" + sql """INSERT INTO nereids_using_join_t4 VALUES(1, 1, 41)""" + sql """INSERT INTO nereids_using_join_t4 VALUES(1, 2, 42)""" + sql """INSERT INTO nereids_using_join_t4 VALUES(1, 3, 43)""" + sql """INSERT INTO nereids_using_join_t4 VALUES(1, 4, 44)""" + sql """INSERT INTO nereids_using_join_t4 VALUES(1, 5, 45)""" + sql """INSERT INTO nereids_using_join_t4 VALUES(1, 6, 46)""" + sql """INSERT INTO nereids_using_join_t4 VALUES(1, 7, 47)""" + sql """INSERT INTO nereids_using_join_t4 VALUES(1, 8, 48)""" + + order_qt_two_relations """ + select * from nereids_using_join_t1 join nereids_using_join_t2 using (c1); + """ + + order_qt_two_relations_by_two_slot """ + select * from nereids_using_join_t1 join nereids_using_join_t2 using (c1, c2); + """ + + order_qt_two_relations_with_right_slot """ + select *, nereids_using_join_t2.c1 from nereids_using_join_t1 join nereids_using_join_t2 using (c1); + """ + + order_qt_two_relations_with_alias """ + select * from nereids_using_join_t1 a join nereids_using_join_t2 b using (c1); + """ + + order_qt_three_relations """ + select * from nereids_using_join_t1 join nereids_using_join_t3 using (c1) join nereids_using_join_t2 using (c2); + """ + + order_qt_one_plus_two_relations """ + select * from nereids_using_join_t2 join (nereids_using_join_t1 join nereids_using_join_t3 using (c1)) using (c1); + """ + + order_qt_one_plus_two_cross_join """ + select * from nereids_using_join_t1 join (nereids_using_join_t2, nereids_using_join_t3) using (c2); + """ + + order_qt_one_cross_join_with_two """ + select * from nereids_using_join_t1, nereids_using_join_t2 join nereids_using_join_t3 using (c1); + """ + + order_qt_with_lateral_view """ + select * from nereids_using_join_t1 lateral view explode(c4) tmp as c5 join nereids_using_join_t3 using (c1) join nereids_using_join_t2 using (c2) join nereids_using_join_t4 using(c5); + """ - sql """INSERT INTO nereids_using_join_t2 VALUES('1', 1, 1)""" - sql """INSERT INTO nereids_using_join_t2 VALUES('2', 2, 1)""" - sql """INSERT INTO nereids_using_join_t2 VALUES('6', 3, 1)""" - sql """INSERT INTO nereids_using_join_t2 VALUES('7', 4, 1)""" + order_qt_with_aggregate_project """ + select * from (select c3, sum(nereids_using_join_t2.c2) from nereids_using_join_t1 join nereids_using_join_t2 using (c1) group by c3) t + """ + + order_qt_with_aggregate_by_right_slot_project """ + select * from (select nereids_using_join_t2.c1, sum(nereids_using_join_t2.c2) from nereids_using_join_t1 join nereids_using_join_t2 using (c1) group by nereids_using_join_t2.c1) t + """ + + order_qt_with_project_aggregate """ + select c1, sum(c3) from (select * from nereids_using_join_t1 join nereids_using_join_t3 using (c1)) t group by c1 + """ + + order_qt_with_extend_aggregate """ + select c1, c2, c3, sum(c3) from (select * from nereids_using_join_t1 join nereids_using_join_t3 using (c1)) t group by grouping sets ((c1), (c2), (c3)) + """ + + order_qt_with_order_by """ + select * from (select * from nereids_using_join_t1 join nereids_using_join_t3 using (c1) order by c1) t join nereids_using_join_t2 using (c1) order by c1; + """ + + order_qt_with_limit """ + select * from (select * from nereids_using_join_t1 join nereids_using_join_t3 using (c1) limit 10) t join nereids_using_join_t2 using (c1) limit 5; + """ - order_qt_sql """ - SELECT nereids_using_join_t1.col1 FROM nereids_using_join_t1 JOIN nereids_using_join_t2 USING (col1) + order_qt_with_union_all """ + select * from (select * from nereids_using_join_t1 join nereids_using_join_t3 using (c1) union all select * from nereids_using_join_t1 join nereids_using_join_t3 using (c1)) t """ - order_qt_sql """ - SELECT nereids_using_join_t1.col1 FROM nereids_using_join_t1 JOIN nereids_using_join_t2 USING (col1, col2) + order_qt_with_filter """ + select * from nereids_using_join_t1 join nereids_using_join_t2 using (c1) where c1 < 3; """ } \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org