This is an automated email from the ASF dual-hosted git repository. huajianlan 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 74ffdbeebc [feature](Nereids) Support OneRowRelation and EmptyRelation (#12416) 74ffdbeebc is described below commit 74ffdbeebc8089c52791c02d3b2daabe7487b8a0 Author: 924060929 <924060...@qq.com> AuthorDate: Thu Sep 8 12:21:13 2022 +0800 [feature](Nereids) Support OneRowRelation and EmptyRelation (#12416) Support OneRowRelation and EmptyRelation. OneRowRelation: `select 100, 'abc', substring('abc', 1, 2)` EmptyRelation: `select * from tbl limit 0` Note: PhysicalOneRowRelation will translate to UnionNode(constExpr) for BE execution --- .../main/java/org/apache/doris/common/Pair.java | 8 ++ .../org/apache/doris/nereids/NereidsPlanner.java | 2 +- .../algebra/Scan.java => analyzer/Relation.java} | 20 +--- ...undRelation.java => UnboundOneRowRelation.java} | 85 ++++++-------- .../doris/nereids/analyzer/UnboundRelation.java | 8 +- .../glue/translator/PhysicalPlanTranslator.java | 55 ++++++++++ .../glue/translator/PlanTranslatorContext.java | 7 +- .../doris/nereids/jobs/batch/RewriteJob.java | 2 + .../apache/doris/nereids/memo/GroupExpression.java | 11 +- .../java/org/apache/doris/nereids/memo/Memo.java | 20 ++-- .../doris/nereids/parser/LogicalPlanBuilder.java | 23 +++- .../org/apache/doris/nereids/rules/RuleSet.java | 4 + .../org/apache/doris/nereids/rules/RuleType.java | 6 + .../doris/nereids/rules/analysis/BindFunction.java | 17 +++ .../nereids/rules/analysis/BindSlotReference.java | 14 +++ .../rules/analysis/ProjectToGlobalAggregate.java | 16 ++- .../expression/rewrite/ExpressionRewrite.java | 29 +++++ .../expression/rewrite/rules/TypeCoercion.java | 22 ++-- ...gicalEmptyRelationToPhysicalEmptyRelation.java} | 26 ++--- ...calOneRowRelationToPhysicalOneRowRelation.java} | 26 ++--- .../LogicalLimitZeroToLogicalEmptyRelation.java} | 27 ++--- .../doris/nereids/stats/StatsCalculator.java | 57 ++++++++++ .../org/apache/doris/nereids/trees/TreeNode.java | 16 +++ .../nereids/trees/expressions/SlotReference.java | 24 +++- .../trees/expressions/functions/Substring.java | 19 +++- .../nereids/trees/expressions/literal/Literal.java | 9 ++ .../trees/expressions/literal/VarcharLiteral.java | 5 + .../apache/doris/nereids/trees/plans/PlanType.java | 5 + .../algebra/{Scan.java => EmptyRelation.java} | 20 ++-- .../algebra/{Scan.java => OneRowRelation.java} | 18 +-- .../doris/nereids/trees/plans/algebra/Scan.java | 3 +- .../trees/plans/logical/LogicalEmptyRelation.java | 113 +++++++++++++++++++ .../trees/plans/logical/LogicalOneRowRelation.java | 115 +++++++++++++++++++ .../trees/plans/physical/AbstractPhysicalPlan.java | 5 +- .../trees/plans/physical/PhysicalBinary.java | 5 +- .../plans/physical/PhysicalEmptyRelation.java | 122 +++++++++++++++++++++ .../nereids/trees/plans/physical/PhysicalLeaf.java | 3 +- .../plans/physical/PhysicalOneRowRelation.java | 113 +++++++++++++++++++ .../trees/plans/physical/PhysicalUnary.java | 3 +- .../nereids/trees/plans/visitor/PlanVisitor.java | 25 +++++ .../org/apache/doris/nereids/types/DataType.java | 28 ++++- .../org/apache/doris/planner/SetOperationNode.java | 14 +++ .../java/org/apache/doris/planner/UnionNode.java | 4 +- .../apache/doris/nereids/memo/MemoRewriteTest.java | 33 ++---- .../doris/nereids/parser/HavingClauseTest.java | 100 +++++++++-------- .../expression/rewrite/ExpressionRewriteTest.java | 10 +- .../apache/doris/nereids/util/FieldChecker.java | 8 +- .../apache/doris/nereids/util/MemoTestUtils.java | 44 -------- .../suites/nereids_syntax_p0/empty_relation.groovy | 28 ++--- .../nereids_syntax_p0/one_row_relation.groovy | 25 ++--- 50 files changed, 1051 insertions(+), 351 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/Pair.java b/fe/fe-core/src/main/java/org/apache/doris/common/Pair.java index 581e896033..c3ae810582 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/common/Pair.java +++ b/fe/fe-core/src/main/java/org/apache/doris/common/Pair.java @@ -47,6 +47,14 @@ public class Pair<F, S> { return new Pair<>(first, second); } + public F key() { + return first; + } + + public S value() { + return second; + } + /** * A pair is equal if both parts are equal(). */ diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java index e4e872c71f..7bcea8a1e5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java @@ -111,7 +111,7 @@ public class NereidsPlanner extends Planner { // TODO: What is the appropriate time to set physical properties? Maybe before enter. // cascades style optimize phase. - // cost-based optimize and explode plan space + // cost-based optimize and explore plan space optimize(); PhysicalPlan physicalPlan = chooseBestPlan(getRoot(), PhysicalProperties.ANY); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/Relation.java similarity index 62% copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java copy to fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/Relation.java index f0c536cf83..48b30ec450 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/Relation.java @@ -15,24 +15,10 @@ // specific language governing permissions and limitations // under the License. -package org.apache.doris.nereids.trees.plans.algebra; - -import org.apache.doris.catalog.Table; -import org.apache.doris.nereids.trees.expressions.Expression; -import org.apache.doris.nereids.trees.expressions.Slot; - -import java.util.Collections; -import java.util.List; +package org.apache.doris.nereids.analyzer; /** - * Common interface for logical/physical scan. + * Relation base interface */ -public interface Scan { - List<Expression> getExpressions(); - - Table getTable(); - - default List<Slot> getOutput() { - return Collections.emptyList(); - } +public interface Relation { } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundRelation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundOneRowRelation.java similarity index 56% copy from fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundRelation.java copy to fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundOneRowRelation.java index f654bcb089..6ba9b72674 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundRelation.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundOneRowRelation.java @@ -17,83 +17,69 @@ package org.apache.doris.nereids.analyzer; -import org.apache.doris.nereids.analyzer.identifier.TableIdentifier; import org.apache.doris.nereids.exceptions.UnboundException; import org.apache.doris.nereids.memo.GroupExpression; import org.apache.doris.nereids.properties.LogicalProperties; import org.apache.doris.nereids.properties.UnboundLogicalProperties; import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.NamedExpression; import org.apache.doris.nereids.trees.expressions.Slot; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.PlanType; +import org.apache.doris.nereids.trees.plans.algebra.OneRowRelation; import org.apache.doris.nereids.trees.plans.logical.LogicalLeaf; import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; import org.apache.doris.nereids.util.Utils; -import com.google.common.collect.Lists; -import org.apache.commons.lang3.StringUtils; +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; import java.util.List; import java.util.Objects; import java.util.Optional; /** - * Represent a relation plan node that has not been bound. + * A relation that contains only one row consist of some constant expressions. + * e.g. select 100, 'value' */ -public class UnboundRelation extends LogicalLeaf implements Unbound { - private final List<String> nameParts; +public class UnboundOneRowRelation extends LogicalLeaf implements Unbound, OneRowRelation { + private final List<NamedExpression> projects; - public UnboundRelation(List<String> nameParts) { - this(nameParts, Optional.empty(), Optional.empty()); + public UnboundOneRowRelation(List<NamedExpression> projects) { + this(projects, Optional.empty(), Optional.empty()); } - public UnboundRelation(List<String> nameParts, Optional<GroupExpression> groupExpression, + private UnboundOneRowRelation(List<NamedExpression> projects, Optional<GroupExpression> groupExpression, Optional<LogicalProperties> logicalProperties) { - super(PlanType.LOGICAL_UNBOUND_RELATION, groupExpression, logicalProperties); - this.nameParts = nameParts; + super(PlanType.LOGICAL_UNBOUND_ONE_ROW_RELATION, groupExpression, logicalProperties); + Preconditions.checkArgument(projects.stream().noneMatch(p -> p.containsType(Slot.class)), + "OneRowRelation can not contains any slot"); + this.projects = ImmutableList.copyOf(projects); } - public UnboundRelation(TableIdentifier identifier) { - this(identifier, Optional.empty(), Optional.empty()); - } - - /** - * Constructor for UnboundRelation. - * - * @param identifier relation identifier - */ - public UnboundRelation(TableIdentifier identifier, Optional<GroupExpression> groupExpression, - Optional<LogicalProperties> logicalProperties) { - super(PlanType.LOGICAL_UNBOUND_RELATION, groupExpression, logicalProperties); - this.nameParts = Lists.newArrayList(); - if (identifier.getDatabaseName().isPresent()) { - nameParts.add(identifier.getDatabaseName().get()); - } - nameParts.add(identifier.getTableName()); - } - - public List<String> getNameParts() { - return nameParts; + @Override + public <R, C> R accept(PlanVisitor<R, C> visitor, C context) { + return visitor.visitUnboundOneRowRelation(this, context); } - public String getTableName() { - return nameParts.stream().map(Utils::quoteIfNeeded) - .reduce((left, right) -> left + "." + right).orElse(""); + @Override + public List<NamedExpression> getProjects() { + return projects; } @Override - public LogicalProperties computeLogicalProperties() { - return UnboundLogicalProperties.INSTANCE; + public List<Expression> getExpressions() { + throw new UnsupportedOperationException(this.getClass().getSimpleName() + " don't support getExpression()"); } @Override public Plan withGroupExpression(Optional<GroupExpression> groupExpression) { - return new UnboundRelation(nameParts, groupExpression, Optional.of(getLogicalProperties())); + return new UnboundOneRowRelation(projects, groupExpression, Optional.of(logicalPropertiesSupplier.get())); } @Override public Plan withLogicalProperties(Optional<LogicalProperties> logicalProperties) { - return new UnboundRelation(nameParts, Optional.empty(), logicalProperties); + return new UnboundOneRowRelation(projects, Optional.empty(), logicalProperties); } @Override @@ -102,18 +88,15 @@ public class UnboundRelation extends LogicalLeaf implements Unbound { } @Override - public String toString() { - return "UnboundRelation" + "(" + StringUtils.join(nameParts, ".") + ")"; - } - - @Override - public <R, C> R accept(PlanVisitor<R, C> visitor, C context) { - return visitor.visitUnboundRelation(this, context); + public LogicalProperties computeLogicalProperties() { + return UnboundLogicalProperties.INSTANCE; } @Override - public List<Expression> getExpressions() { - throw new UnsupportedOperationException(this.getClass().getSimpleName() + " don't support getExpression()"); + public String toString() { + return Utils.toSqlString("UnboundOneRowRelation", + "projects", projects + ); } @Override @@ -127,12 +110,12 @@ public class UnboundRelation extends LogicalLeaf implements Unbound { if (!super.equals(o)) { return false; } - UnboundRelation that = (UnboundRelation) o; - return Objects.equals(nameParts, that.nameParts); + UnboundOneRowRelation that = (UnboundOneRowRelation) o; + return Objects.equals(projects, that.projects); } @Override public int hashCode() { - return Objects.hash(super.hashCode(), nameParts); + return Objects.hash(projects); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundRelation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundRelation.java index f654bcb089..4fce8df6e4 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundRelation.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundRelation.java @@ -40,7 +40,7 @@ import java.util.Optional; /** * Represent a relation plan node that has not been bound. */ -public class UnboundRelation extends LogicalLeaf implements Unbound { +public class UnboundRelation extends LogicalLeaf implements Relation, Unbound { private final List<String> nameParts; public UnboundRelation(List<String> nameParts) { @@ -103,7 +103,9 @@ public class UnboundRelation extends LogicalLeaf implements Unbound { @Override public String toString() { - return "UnboundRelation" + "(" + StringUtils.join(nameParts, ".") + ")"; + return Utils.toSqlString("UnboundRelation", + "nameParts", StringUtils.join(nameParts, ".") + ); } @Override @@ -133,6 +135,6 @@ public class UnboundRelation extends LogicalLeaf implements Unbound { @Override public int hashCode() { - return Objects.hash(super.hashCode(), nameParts); + return Objects.hash(nameParts); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java index d35bc6dd87..fea1194fba 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java @@ -29,6 +29,7 @@ import org.apache.doris.analysis.SortInfo; import org.apache.doris.analysis.TableName; import org.apache.doris.analysis.TableRef; import org.apache.doris.analysis.TupleDescriptor; +import org.apache.doris.analysis.TupleId; import org.apache.doris.catalog.OlapTable; import org.apache.doris.catalog.Table; import org.apache.doris.common.Pair; @@ -52,11 +53,13 @@ import org.apache.doris.nereids.trees.plans.physical.AbstractPhysicalSort; import org.apache.doris.nereids.trees.plans.physical.PhysicalAggregate; import org.apache.doris.nereids.trees.plans.physical.PhysicalAssertNumRows; import org.apache.doris.nereids.trees.plans.physical.PhysicalDistribute; +import org.apache.doris.nereids.trees.plans.physical.PhysicalEmptyRelation; import org.apache.doris.nereids.trees.plans.physical.PhysicalFilter; import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin; import org.apache.doris.nereids.trees.plans.physical.PhysicalLimit; import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin; import org.apache.doris.nereids.trees.plans.physical.PhysicalOlapScan; +import org.apache.doris.nereids.trees.plans.physical.PhysicalOneRowRelation; import org.apache.doris.nereids.trees.plans.physical.PhysicalPlan; import org.apache.doris.nereids.trees.plans.physical.PhysicalProject; import org.apache.doris.nereids.trees.plans.physical.PhysicalQuickSort; @@ -69,6 +72,7 @@ import org.apache.doris.planner.AggregationNode; import org.apache.doris.planner.AssertNumRowsNode; import org.apache.doris.planner.CrossJoinNode; import org.apache.doris.planner.DataPartition; +import org.apache.doris.planner.EmptySetNode; import org.apache.doris.planner.ExchangeNode; import org.apache.doris.planner.HashJoinNode; import org.apache.doris.planner.HashJoinNode.DistributionMode; @@ -76,6 +80,7 @@ import org.apache.doris.planner.OlapScanNode; import org.apache.doris.planner.PlanFragment; import org.apache.doris.planner.PlanNode; import org.apache.doris.planner.SortNode; +import org.apache.doris.planner.UnionNode; import org.apache.doris.thrift.TPartitionType; import com.google.common.base.Preconditions; @@ -227,6 +232,56 @@ public class PhysicalPlanTranslator extends DefaultPlanVisitor<PlanFragment, Pla return currentFragment; } + @Override + public PlanFragment visitPhysicalEmptyRelation(PhysicalEmptyRelation emptyRelation, PlanTranslatorContext context) { + List<Slot> output = emptyRelation.getOutput(); + TupleDescriptor tupleDescriptor = generateTupleDesc(output, null, context); + for (int i = 0; i < output.size(); i++) { + SlotDescriptor slotDescriptor = tupleDescriptor.getSlots().get(i); + slotDescriptor.setIsNullable(true); // we should set to nullable, or else BE would core + + Slot slot = output.get(i); + SlotRef slotRef = context.findSlotRef(slot.getExprId()); + slotRef.setLabel(slot.getName()); + } + + ArrayList<TupleId> tupleIds = new ArrayList(); + tupleIds.add(tupleDescriptor.getId()); + EmptySetNode emptySetNode = new EmptySetNode(context.nextPlanNodeId(), tupleIds); + + PlanFragment planFragment = new PlanFragment(context.nextFragmentId(), emptySetNode, + DataPartition.UNPARTITIONED); + context.addPlanFragment(planFragment); + return planFragment; + } + + @Override + public PlanFragment visitPhysicalOneRowRelation(PhysicalOneRowRelation oneRowRelation, + PlanTranslatorContext context) { + List<Slot> slots = oneRowRelation.getLogicalProperties().getOutput(); + TupleDescriptor oneRowTuple = generateTupleDesc(slots, null, context); + + List<Expr> legacyExprs = oneRowRelation.getProjects() + .stream() + .map(expr -> ExpressionTranslator.translate(expr, context)) + .collect(Collectors.toList()); + + for (int i = 0; i < legacyExprs.size(); i++) { + SlotDescriptor slotDescriptor = oneRowTuple.getSlots().get(i); + Expr expr = legacyExprs.get(i); + slotDescriptor.setSourceExpr(expr); + slotDescriptor.setIsNullable(true); // we should set to nullable, or else BE would core + } + + UnionNode unionNode = new UnionNode(context.nextPlanNodeId(), oneRowTuple.getId()); + unionNode.addConstExprList(legacyExprs); + unionNode.finalizeForNereids(oneRowTuple, oneRowTuple.getSlots()); + + PlanFragment planFragment = new PlanFragment(context.nextFragmentId(), unionNode, DataPartition.UNPARTITIONED); + context.addPlanFragment(planFragment); + return planFragment; + } + @Override public PlanFragment visitPhysicalOlapScan(PhysicalOlapScan olapScan, PlanTranslatorContext context) { // Create OlapScanNode diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PlanTranslatorContext.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PlanTranslatorContext.java index 7f9c3e2712..24b21d5f0d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PlanTranslatorContext.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PlanTranslatorContext.java @@ -38,6 +38,7 @@ import com.google.common.collect.Maps; import java.util.List; import java.util.Map; +import java.util.Optional; /** * Context of physical plan. @@ -117,10 +118,10 @@ public class PlanTranslatorContext { */ public SlotDescriptor createSlotDesc(TupleDescriptor tupleDesc, SlotReference slotReference) { SlotDescriptor slotDescriptor = this.addSlotDesc(tupleDesc); - Column column = slotReference.getColumn(); + Optional<Column> column = slotReference.getColumn(); // Only the SlotDesc that in the tuple generated for scan node would have corresponding column. - if (column != null) { - slotDescriptor.setColumn(column); + if (column.isPresent()) { + slotDescriptor.setColumn(column.get()); } slotDescriptor.setType(slotReference.getDataType().toCatalogDataType()); slotDescriptor.setIsMaterialized(true); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/RewriteJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/RewriteJob.java index a8d59aeb02..1fe9e3f8b8 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/RewriteJob.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/batch/RewriteJob.java @@ -23,6 +23,7 @@ import org.apache.doris.nereids.rules.expression.rewrite.ExpressionNormalization import org.apache.doris.nereids.rules.rewrite.AggregateDisassemble; import org.apache.doris.nereids.rules.rewrite.logical.ColumnPruning; import org.apache.doris.nereids.rules.rewrite.logical.FindHashConditionForJoin; +import org.apache.doris.nereids.rules.rewrite.logical.LogicalLimitZeroToLogicalEmptyRelation; import org.apache.doris.nereids.rules.rewrite.logical.MergeConsecutiveFilters; import org.apache.doris.nereids.rules.rewrite.logical.MergeConsecutiveLimits; import org.apache.doris.nereids.rules.rewrite.logical.MergeConsecutiveProjects; @@ -67,6 +68,7 @@ public class RewriteJob extends BatchRulesJob { .add(bottomUpBatch(ImmutableList.of(new MergeConsecutiveProjects()))) .add(topDownBatch(ImmutableList.of(new MergeConsecutiveFilters()))) .add(bottomUpBatch(ImmutableList.of(new MergeConsecutiveLimits()))) + .add(bottomUpBatch(ImmutableList.of(new LogicalLimitZeroToLogicalEmptyRelation()))) .add(topDownBatch(ImmutableList.of(new PruneOlapScanPartition()))) .build(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/GroupExpression.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/GroupExpression.java index 22b5723e57..6137647887 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/GroupExpression.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/GroupExpression.java @@ -18,13 +18,11 @@ package org.apache.doris.nereids.memo; import org.apache.doris.common.Pair; -import org.apache.doris.nereids.analyzer.UnboundRelation; +import org.apache.doris.nereids.analyzer.Relation; import org.apache.doris.nereids.properties.PhysicalProperties; import org.apache.doris.nereids.rules.Rule; import org.apache.doris.nereids.rules.RuleType; import org.apache.doris.nereids.trees.plans.Plan; -import org.apache.doris.nereids.trees.plans.logical.LogicalRelation; -import org.apache.doris.nereids.trees.plans.physical.PhysicalRelation; import org.apache.doris.statistics.StatsDeriveResult; import com.google.common.base.Preconditions; @@ -208,10 +206,9 @@ public class GroupExpression { return false; } GroupExpression that = (GroupExpression) o; - // if the plan is UnboundRelation or LogicalRelation or PhysicalRelation, this == that should be true, - // when if one relation appear in plan more than once, - // we cannot distinguish them throw equals function, since equals function cannot use output info. - if (plan instanceof UnboundRelation || plan instanceof LogicalRelation || plan instanceof PhysicalRelation) { + // FIXME: Doris not support temporary materialization, so we should not merge same + // scan relation plan. We should add id for XxxRelation and compare by id. + if (plan instanceof Relation) { return false; } return children.equals(that.children) && plan.equals(that.plan) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java index adb9b31692..f0b6f64691 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/memo/Memo.java @@ -158,19 +158,21 @@ public class Memo { * +---------------------------------------+-----------------------------------+--------------------------------+ * | case 2: | | | * | if targetGroup is null | true | new group expression | - * | and same group expression exist | | | + * | and same group expression not exist | | | * +---------------------------------------+-----------------------------------+--------------------------------+ * | case 3: | | | - * | if targetGroup is null | true | new group expression | + * | if targetGroup is not null | true | new group expression | * | and same group expression not exits | | | * +---------------------------------------+-----------------------------------+--------------------------------+ * | case 4: | | | - * | if targetGroup equal to the exists | true | new group expression | - * | group expression's owner group | | | + * | if targetGroup is not null and not | true | new group expression | + * | equal to the existed group | | | + * | expression's owner group | | | * +---------------------------------------+-----------------------------------+--------------------------------+ * | case 5: | | | - * | if targetGroup not equal to the | false | existed group expression | - * | exists group expression's owner group | | | + * | if targetGroup is null or equal to | false | existed group expression | + * | the existed group expression's owner | | | + * | group | | | * +---------------------------------------+-----------------------------------+--------------------------------+ * </pre> * @@ -190,15 +192,19 @@ public class Memo { return rewriteByExistedPlan(targetGroup, plan); } - // try to create a new group expression List<Group> childrenGroups = rewriteChildrenPlansToGroups(plan, targetGroup); + plan = replaceChildrenToGroupPlan(plan, childrenGroups); + + // try to create a new group expression GroupExpression newGroupExpression = new GroupExpression(plan, childrenGroups); // slow check the groupExpression/plan whether exists in the memo GroupExpression existedExpression = groupExpressions.get(newGroupExpression); if (existedExpression == null) { + // case 2 or case 3 return rewriteByNewGroupExpression(targetGroup, plan, newGroupExpression); } else { + // case 4 or case 5 return rewriteByExistedGroupExpression(targetGroup, plan, existedExpression, newGroupExpression); } } 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 5aa750e34c..3f534c1c27 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 @@ -72,6 +72,7 @@ import org.apache.doris.nereids.DorisParser.WhereClauseContext; import org.apache.doris.nereids.DorisParserBaseVisitor; import org.apache.doris.nereids.analyzer.UnboundAlias; import org.apache.doris.nereids.analyzer.UnboundFunction; +import org.apache.doris.nereids.analyzer.UnboundOneRowRelation; import org.apache.doris.nereids.analyzer.UnboundRelation; import org.apache.doris.nereids.analyzer.UnboundSlot; import org.apache.doris.nereids.analyzer.UnboundStar; @@ -117,7 +118,9 @@ import org.apache.doris.nereids.trees.expressions.literal.IntervalLiteral; import org.apache.doris.nereids.trees.expressions.literal.LargeIntLiteral; import org.apache.doris.nereids.trees.expressions.literal.Literal; import org.apache.doris.nereids.trees.expressions.literal.NullLiteral; -import org.apache.doris.nereids.trees.expressions.literal.StringLiteral; +import org.apache.doris.nereids.trees.expressions.literal.SmallIntLiteral; +import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral; +import org.apache.doris.nereids.trees.expressions.literal.VarcharLiteral; import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.commands.Command; import org.apache.doris.nereids.trees.plans.commands.ExplainCommand; @@ -216,9 +219,8 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> { @Override public LogicalPlan visitRegularQuerySpecification(RegularQuerySpecificationContext ctx) { return ParserUtils.withOrigin(ctx, () -> { - // TODO: support one row relation if (ctx.fromClause() == null) { - throw new ParseException("Unsupported one row relation", ctx); + return withOneRowRelation(ctx.selectClause()); } LogicalPlan relation = visitFromClause(ctx.fromClause()); @@ -588,7 +590,11 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> { @Override public Literal visitIntegerLiteral(IntegerLiteralContext ctx) { BigInteger bigInt = new BigInteger(ctx.getText()); - if (BigInteger.valueOf(bigInt.intValue()).equals(bigInt)) { + if (BigInteger.valueOf(bigInt.byteValue()).equals(bigInt)) { + return new TinyIntLiteral(bigInt.byteValue()); + } else if (BigInteger.valueOf(bigInt.shortValue()).equals(bigInt)) { + return new SmallIntLiteral(bigInt.shortValue()); + } else if (BigInteger.valueOf(bigInt.intValue()).equals(bigInt)) { return new IntegerLiteral(bigInt.intValue()); } else if (BigInteger.valueOf(bigInt.longValue()).equals(bigInt)) { return new BigIntLiteral(bigInt.longValueExact()); @@ -605,7 +611,7 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> { .map(str -> str.substring(1, str.length() - 1)) .reduce((s1, s2) -> s1 + s2) .orElse(""); - return new StringLiteral(s); + return new VarcharLiteral(s); } @Override @@ -749,6 +755,13 @@ public class LogicalPlanBuilder extends DorisParserBaseVisitor<Object> { }); } + private UnboundOneRowRelation withOneRowRelation(SelectClauseContext selectCtx) { + return ParserUtils.withOrigin(selectCtx, () -> { + List<NamedExpression> projects = getNamedExpressions(selectCtx.namedExpressionSeq()); + return new UnboundOneRowRelation(projects); + }); + } + /** * Add a regular (SELECT) query specification to a logical plan. The query specification * is the core of the logical plan, this is where sourcing (FROM clause), projection (SELECT), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java index fb4ec44c40..fb2696788c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java @@ -21,11 +21,13 @@ import org.apache.doris.nereids.rules.exploration.join.JoinCommute; import org.apache.doris.nereids.rules.exploration.join.JoinCommuteProject; import org.apache.doris.nereids.rules.implementation.LogicalAggToPhysicalHashAgg; import org.apache.doris.nereids.rules.implementation.LogicalAssertNumRowsToPhysicalAssertNumRows; +import org.apache.doris.nereids.rules.implementation.LogicalEmptyRelationToPhysicalEmptyRelation; import org.apache.doris.nereids.rules.implementation.LogicalFilterToPhysicalFilter; import org.apache.doris.nereids.rules.implementation.LogicalJoinToHashJoin; import org.apache.doris.nereids.rules.implementation.LogicalJoinToNestedLoopJoin; import org.apache.doris.nereids.rules.implementation.LogicalLimitToPhysicalLimit; import org.apache.doris.nereids.rules.implementation.LogicalOlapScanToPhysicalOlapScan; +import org.apache.doris.nereids.rules.implementation.LogicalOneRowRelationToPhysicalOneRowRelation; import org.apache.doris.nereids.rules.implementation.LogicalProjectToPhysicalProject; import org.apache.doris.nereids.rules.implementation.LogicalSortToPhysicalQuickSort; import org.apache.doris.nereids.rules.implementation.LogicalTopNToPhysicalTopN; @@ -60,6 +62,8 @@ public class RuleSet { .add(new LogicalSortToPhysicalQuickSort()) .add(new LogicalTopNToPhysicalTopN()) .add(new LogicalAssertNumRowsToPhysicalAssertNumRows()) + .add(new LogicalOneRowRelationToPhysicalOneRowRelation()) + .add(new LogicalEmptyRelationToPhysicalEmptyRelation()) .build(); public List<Rule> getExplorationRules() { 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 20c3a9fb79..efcf3adae3 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 @@ -30,6 +30,7 @@ public enum RuleType { // **** make sure BINDING_UNBOUND_LOGICAL_PLAN is the lowest priority in the rewrite rules. **** BINDING_NON_LEAF_LOGICAL_PLAN(RuleTypeClass.REWRITE), + BINDING_ONE_ROW_RELATION_SLOT(RuleTypeClass.REWRITE), BINDING_RELATION(RuleTypeClass.REWRITE), BINDING_PROJECT_SLOT(RuleTypeClass.REWRITE), BINDING_FILTER_SLOT(RuleTypeClass.REWRITE), @@ -37,6 +38,7 @@ public enum RuleType { BINDING_AGGREGATE_SLOT(RuleTypeClass.REWRITE), BINDING_SORT_SLOT(RuleTypeClass.REWRITE), BINDING_LIMIT_SLOT(RuleTypeClass.REWRITE), + BINDING_ONE_ROW_RELATION_FUNCTION(RuleTypeClass.REWRITE), BINDING_PROJECT_FUNCTION(RuleTypeClass.REWRITE), BINDING_AGGREGATE_FUNCTION(RuleTypeClass.REWRITE), BINDING_SUBQUERY_ALIAS_SLOT(RuleTypeClass.REWRITE), @@ -84,6 +86,7 @@ public enum RuleType { COLUMN_PRUNE_SORT_CHILD(RuleTypeClass.REWRITE), COLUMN_PRUNE_JOIN_CHILD(RuleTypeClass.REWRITE), // expression of plan rewrite + REWRITE_ONE_ROW_RELATION_EXPRESSION(RuleTypeClass.REWRITE), REWRITE_PROJECT_EXPRESSION(RuleTypeClass.REWRITE), REWRITE_AGG_EXPRESSION(RuleTypeClass.REWRITE), REWRITE_FILTER_EXPRESSION(RuleTypeClass.REWRITE), @@ -96,6 +99,7 @@ public enum RuleType { REWRITE_SENTINEL(RuleTypeClass.REWRITE), OLAP_SCAN_PARTITION_PRUNE(RuleTypeClass.REWRITE), SWAP_FILTER_AND_PROJECT(RuleTypeClass.REWRITE), + LOGICAL_LIMIT_TO_LOGICAL_EMPTY_RELATION_RULE(RuleTypeClass.REWRITE), // exploration rules TEST_EXPLORATION(RuleTypeClass.EXPLORATION), @@ -105,6 +109,7 @@ public enum RuleType { LOGICAL_JOIN_EXCHANGE(RuleTypeClass.EXPLORATION), // implementation rules + LOGICAL_ONE_ROW_RELATION_TO_PHYSICAL_ONE_ROW_RELATION(RuleTypeClass.IMPLEMENTATION), LOGICAL_AGG_TO_PHYSICAL_HASH_AGG_RULE(RuleTypeClass.IMPLEMENTATION), LOGICAL_JOIN_TO_HASH_JOIN_RULE(RuleTypeClass.IMPLEMENTATION), LOGICAL_JOIN_TO_NESTED_LOOP_JOIN_RULE(RuleTypeClass.IMPLEMENTATION), @@ -112,6 +117,7 @@ public enum RuleType { LOGICAL_FILTER_TO_PHYSICAL_FILTER_RULE(RuleTypeClass.IMPLEMENTATION), LOGICAL_SORT_TO_PHYSICAL_QUICK_SORT_RULE(RuleTypeClass.IMPLEMENTATION), LOGICAL_TOP_N_TO_PHYSICAL_TOP_N_RULE(RuleTypeClass.IMPLEMENTATION), + LOGICAL_EMPTY_RELATION_TO_PHYSICAL_EMPTY_RELATION_RULE(RuleTypeClass.IMPLEMENTATION), LOGICAL_LIMIT_TO_PHYSICAL_LIMIT_RULE(RuleTypeClass.IMPLEMENTATION), LOGICAL_OLAP_SCAN_TO_PHYSICAL_OLAP_SCAN_RULE(RuleTypeClass.IMPLEMENTATION), LOGICAL_ASSERT_NUM_ROWS_TO_PHYSICAL_ASSERT_NUM_ROWS(RuleTypeClass.IMPLEMENTATION), diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindFunction.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindFunction.java index d1a4a4cd2c..7f309d768a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindFunction.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindFunction.java @@ -35,6 +35,7 @@ import org.apache.doris.nereids.trees.expressions.functions.Year; import org.apache.doris.nereids.trees.expressions.visitor.DefaultExpressionRewriter; import org.apache.doris.nereids.trees.plans.logical.LogicalFilter; import org.apache.doris.nereids.trees.plans.logical.LogicalHaving; +import org.apache.doris.nereids.trees.plans.logical.LogicalOneRowRelation; import org.apache.doris.nereids.trees.plans.logical.LogicalProject; import org.apache.doris.nereids.types.DateTimeType; import org.apache.doris.nereids.types.DateType; @@ -52,6 +53,22 @@ public class BindFunction implements AnalysisRuleFactory { @Override public List<Rule> buildRules() { return ImmutableList.of( + RuleType.BINDING_ONE_ROW_RELATION_FUNCTION.build( + logicalOneRowRelation().then(oneRowRelation -> { + List<NamedExpression> projects = oneRowRelation.getProjects(); + List<NamedExpression> boundProjects = bind(projects); + // TODO: + // trick logic: currently XxxRelation in GroupExpression always difference to each other, + // so this rule must check the expression whether is changed to prevent dead loop because + // new LogicalOneRowRelation can hit this rule too. we would remove code until the pr + // (@wangshuo128) mark the id in XxxRelation, then we can compare XxxRelation in + // GroupExpression by id + if (projects.equals(boundProjects)) { + return oneRowRelation; + } + return new LogicalOneRowRelation(boundProjects); + }) + ), RuleType.BINDING_PROJECT_FUNCTION.build( logicalProject().then(project -> { List<NamedExpression> boundExpr = bind(project.getProjects()); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java index 282e119fe5..63380462c6 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindSlotReference.java @@ -19,6 +19,7 @@ package org.apache.doris.nereids.rules.analysis; import org.apache.doris.nereids.CascadesContext; import org.apache.doris.nereids.analyzer.UnboundAlias; +import org.apache.doris.nereids.analyzer.UnboundOneRowRelation; import org.apache.doris.nereids.analyzer.UnboundSlot; import org.apache.doris.nereids.analyzer.UnboundStar; import org.apache.doris.nereids.exceptions.AnalysisException; @@ -44,6 +45,7 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate; import org.apache.doris.nereids.trees.plans.logical.LogicalFilter; import org.apache.doris.nereids.trees.plans.logical.LogicalHaving; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; +import org.apache.doris.nereids.trees.plans.logical.LogicalOneRowRelation; 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.LogicalSort; @@ -153,6 +155,18 @@ public class BindSlotReference implements AnalysisRuleFactory { return new LogicalHaving<>(boundPredicates, having.child()); }) ), + RuleType.BINDING_ONE_ROW_RELATION_SLOT.build( + // we should bind UnboundAlias in the UnboundOneRowRelation + unboundOneRowRelation().thenApply(ctx -> { + UnboundOneRowRelation oneRowRelation = ctx.root; + List<NamedExpression> projects = oneRowRelation.getProjects() + .stream() + .map(project -> bind(project, ImmutableList.of(), oneRowRelation, ctx.cascadesContext)) + .collect(Collectors.toList()); + return new LogicalOneRowRelation(projects); + }) + ), + RuleType.BINDING_NON_LEAF_LOGICAL_PLAN.build( logicalPlan() .when(plan -> plan.canBind() && !(plan instanceof LeafPlan)) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ProjectToGlobalAggregate.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ProjectToGlobalAggregate.java index e999e79761..eb02c719f5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ProjectToGlobalAggregate.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/ProjectToGlobalAggregate.java @@ -25,7 +25,21 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate; import com.google.common.collect.ImmutableList; -/** ProjectToGlobalAggregate. */ +/** + * ProjectToGlobalAggregate. + * + * example sql: + * <pre> + * select sum(value) + * from tbl + * </pre> + * + * origin plan: transformed plan: + * + * LogicalProject(projects=[sum(value)]) LogicalAggregate(groupBy=[], output=[sum(value)]) + * | => | + * LogicalOlapScan(table=tbl) LogicalOlapScan(table=tbl) + */ public class ProjectToGlobalAggregate extends OneAnalysisRuleFactory { @Override public Rule build() { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rewrite/ExpressionRewrite.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rewrite/ExpressionRewrite.java index 75dbd5d415..d808183c24 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rewrite/ExpressionRewrite.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rewrite/ExpressionRewrite.java @@ -26,6 +26,7 @@ import org.apache.doris.nereids.trees.expressions.NamedExpression; import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate; import org.apache.doris.nereids.trees.plans.logical.LogicalFilter; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; +import org.apache.doris.nereids.trees.plans.logical.LogicalOneRowRelation; import org.apache.doris.nereids.trees.plans.logical.LogicalProject; import com.google.common.collect.ImmutableList; @@ -42,6 +43,10 @@ import java.util.stream.Collectors; public class ExpressionRewrite implements RewriteRuleFactory { private final ExpressionRuleExecutor rewriter; + public ExpressionRewrite(ExpressionRewriteRule... rules) { + this.rewriter = new ExpressionRuleExecutor(ImmutableList.copyOf(rules)); + } + public ExpressionRewrite(ExpressionRuleExecutor rewriter) { this.rewriter = Objects.requireNonNull(rewriter, "rewriter is null"); } @@ -49,12 +54,36 @@ public class ExpressionRewrite implements RewriteRuleFactory { @Override public List<Rule> buildRules() { return ImmutableList.of( + new OneRowRelationExpressionRewrite().build(), new ProjectExpressionRewrite().build(), new AggExpressionRewrite().build(), new FilterExpressionRewrite().build(), new JoinExpressionRewrite().build()); } + private class OneRowRelationExpressionRewrite extends OneRewriteRuleFactory { + @Override + public Rule build() { + return logicalOneRowRelation().then(oneRowRelation -> { + List<NamedExpression> projects = oneRowRelation.getProjects(); + List<NamedExpression> newProjects = projects + .stream() + .map(expr -> (NamedExpression) rewriter.rewrite(expr)) + .collect(Collectors.toList()); + // TODO: + // trick logic: currently XxxRelation in GroupExpression always difference to each other, + // so this rule must check the expression whether is changed to prevent dead loop because + // new LogicalOneRowRelation can hit this rule too. we would remove code until the pr + // (@wangshuo128) mark the id in XxxRelation, then we can compare XxxRelation in + // GroupExpression by id + if (projects.equals(newProjects)) { + return oneRowRelation; + } + return new LogicalOneRowRelation(newProjects); + }).toRule(RuleType.REWRITE_ONE_ROW_RELATION_EXPRESSION); + } + } + private class ProjectExpressionRewrite extends OneRewriteRuleFactory { @Override public Rule build() { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rewrite/rules/TypeCoercion.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rewrite/rules/TypeCoercion.java index cc745e4b73..f13d20ec87 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rewrite/rules/TypeCoercion.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/expression/rewrite/rules/TypeCoercion.java @@ -34,7 +34,6 @@ import com.google.common.collect.Lists; import java.util.List; import java.util.Optional; -import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; /** @@ -141,21 +140,16 @@ public class TypeCoercion extends AbstractExpressionRewriteRule { private Expression visitImplicitCastInputTypes(Expression expr, ExpressionRewriteContext ctx) { ImplicitCastInputTypes implicitCastInputTypes = (ImplicitCastInputTypes) expr; List<Expression> newChildren = Lists.newArrayListWithCapacity(expr.arity()); - AtomicInteger changed = new AtomicInteger(0); + boolean changed = false; for (int i = 0; i < implicitCastInputTypes.expectedInputTypes().size(); i++) { - newChildren.add(implicitCast(expr.child(i), implicitCastInputTypes.expectedInputTypes().get(i), ctx) - .map(e -> { - changed.incrementAndGet(); - return e; - }) - .orElse(expr.child(0)) - ); - } - if (changed.get() != 0) { - return expr.withChildren(newChildren); - } else { - return expr; + AbstractDataType expectedType = implicitCastInputTypes.expectedInputTypes().get(i); + Optional<Expression> castResult = implicitCast(expr.child(i), expectedType, ctx); + if (castResult.isPresent()) { + changed = true; + } + newChildren.add(castResult.orElse(expr.child(i))); } + return changed ? expr.withChildren(newChildren) : expr; } /** diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalEmptyRelationToPhysicalEmptyRelation.java similarity index 54% copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java copy to fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalEmptyRelationToPhysicalEmptyRelation.java index f0c536cf83..b48d07a4a7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalEmptyRelationToPhysicalEmptyRelation.java @@ -15,24 +15,20 @@ // specific language governing permissions and limitations // under the License. -package org.apache.doris.nereids.trees.plans.algebra; +package org.apache.doris.nereids.rules.implementation; -import org.apache.doris.catalog.Table; -import org.apache.doris.nereids.trees.expressions.Expression; -import org.apache.doris.nereids.trees.expressions.Slot; - -import java.util.Collections; -import java.util.List; +import org.apache.doris.nereids.rules.Rule; +import org.apache.doris.nereids.rules.RuleType; +import org.apache.doris.nereids.trees.plans.physical.PhysicalEmptyRelation; /** - * Common interface for logical/physical scan. + * Implementation rule that convert logical empty relation to physical empty relation. */ -public interface Scan { - List<Expression> getExpressions(); - - Table getTable(); - - default List<Slot> getOutput() { - return Collections.emptyList(); +public class LogicalEmptyRelationToPhysicalEmptyRelation extends OneImplementationRuleFactory { + @Override + public Rule build() { + return logicalEmptyRelation() + .then(relation -> new PhysicalEmptyRelation(relation.getProjects(), relation.getLogicalProperties())) + .toRule(RuleType.LOGICAL_EMPTY_RELATION_TO_PHYSICAL_EMPTY_RELATION_RULE); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalOneRowRelationToPhysicalOneRowRelation.java similarity index 54% copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java copy to fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalOneRowRelationToPhysicalOneRowRelation.java index f0c536cf83..d81a8797dd 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/implementation/LogicalOneRowRelationToPhysicalOneRowRelation.java @@ -15,24 +15,20 @@ // specific language governing permissions and limitations // under the License. -package org.apache.doris.nereids.trees.plans.algebra; +package org.apache.doris.nereids.rules.implementation; -import org.apache.doris.catalog.Table; -import org.apache.doris.nereids.trees.expressions.Expression; -import org.apache.doris.nereids.trees.expressions.Slot; - -import java.util.Collections; -import java.util.List; +import org.apache.doris.nereids.rules.Rule; +import org.apache.doris.nereids.rules.RuleType; +import org.apache.doris.nereids.trees.plans.physical.PhysicalOneRowRelation; /** - * Common interface for logical/physical scan. + * Implementation rule that convert logical aggregation to physical hash aggregation. */ -public interface Scan { - List<Expression> getExpressions(); - - Table getTable(); - - default List<Slot> getOutput() { - return Collections.emptyList(); +public class LogicalOneRowRelationToPhysicalOneRowRelation extends OneImplementationRuleFactory { + @Override + public Rule build() { + return logicalOneRowRelation() + .then(relation -> new PhysicalOneRowRelation(relation.getProjects(), relation.getLogicalProperties())) + .toRule(RuleType.LOGICAL_ONE_ROW_RELATION_TO_PHYSICAL_ONE_ROW_RELATION); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/LogicalLimitZeroToLogicalEmptyRelation.java similarity index 53% copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java copy to fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/LogicalLimitZeroToLogicalEmptyRelation.java index f0c536cf83..e43808cfed 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/LogicalLimitZeroToLogicalEmptyRelation.java @@ -15,24 +15,25 @@ // specific language governing permissions and limitations // under the License. -package org.apache.doris.nereids.trees.plans.algebra; +package org.apache.doris.nereids.rules.rewrite.logical; -import org.apache.doris.catalog.Table; -import org.apache.doris.nereids.trees.expressions.Expression; -import org.apache.doris.nereids.trees.expressions.Slot; +import org.apache.doris.nereids.rules.Rule; +import org.apache.doris.nereids.rules.RuleType; +import org.apache.doris.nereids.rules.rewrite.OneRewriteRuleFactory; +import org.apache.doris.nereids.trees.plans.logical.LogicalEmptyRelation; -import java.util.Collections; import java.util.List; /** - * Common interface for logical/physical scan. + * e.g. + * LogicalLimit(limit=0) => LogicalEmptyRelation(projects=[limit.output()]) */ -public interface Scan { - List<Expression> getExpressions(); - - Table getTable(); - - default List<Slot> getOutput() { - return Collections.emptyList(); +public class LogicalLimitZeroToLogicalEmptyRelation extends OneRewriteRuleFactory { + @Override + public Rule build() { + return logicalLimit() + .when(limit -> limit.getLimit() == 0) + .then(limit -> new LogicalEmptyRelation((List) limit.getOutput())) + .toRule(RuleType.LOGICAL_LIMIT_TO_LOGICAL_EMPTY_RELATION_RULE); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/StatsCalculator.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/StatsCalculator.java index 8b1fcd29b3..6f16d06f04 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/StatsCalculator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/StatsCalculator.java @@ -21,6 +21,7 @@ import org.apache.doris.catalog.MaterializedIndex; import org.apache.doris.catalog.OlapTable; import org.apache.doris.catalog.Partition; import org.apache.doris.common.AnalysisException; +import org.apache.doris.common.Pair; import org.apache.doris.nereids.memo.GroupExpression; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.NamedExpression; @@ -28,29 +29,35 @@ 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.algebra.Aggregate; +import org.apache.doris.nereids.trees.plans.algebra.EmptyRelation; import org.apache.doris.nereids.trees.plans.algebra.Filter; import org.apache.doris.nereids.trees.plans.algebra.Limit; +import org.apache.doris.nereids.trees.plans.algebra.OneRowRelation; import org.apache.doris.nereids.trees.plans.algebra.Project; import org.apache.doris.nereids.trees.plans.algebra.Scan; import org.apache.doris.nereids.trees.plans.algebra.TopN; import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate; import org.apache.doris.nereids.trees.plans.logical.LogicalAssertNumRows; +import org.apache.doris.nereids.trees.plans.logical.LogicalEmptyRelation; import org.apache.doris.nereids.trees.plans.logical.LogicalFilter; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; import org.apache.doris.nereids.trees.plans.logical.LogicalLimit; import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan; +import org.apache.doris.nereids.trees.plans.logical.LogicalOneRowRelation; import org.apache.doris.nereids.trees.plans.logical.LogicalProject; import org.apache.doris.nereids.trees.plans.logical.LogicalSort; import org.apache.doris.nereids.trees.plans.logical.LogicalTopN; import org.apache.doris.nereids.trees.plans.physical.PhysicalAggregate; import org.apache.doris.nereids.trees.plans.physical.PhysicalAssertNumRows; import org.apache.doris.nereids.trees.plans.physical.PhysicalDistribute; +import org.apache.doris.nereids.trees.plans.physical.PhysicalEmptyRelation; import org.apache.doris.nereids.trees.plans.physical.PhysicalFilter; import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin; import org.apache.doris.nereids.trees.plans.physical.PhysicalLimit; import org.apache.doris.nereids.trees.plans.physical.PhysicalLocalQuickSort; import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin; import org.apache.doris.nereids.trees.plans.physical.PhysicalOlapScan; +import org.apache.doris.nereids.trees.plans.physical.PhysicalOneRowRelation; import org.apache.doris.nereids.trees.plans.physical.PhysicalProject; import org.apache.doris.nereids.trees.plans.physical.PhysicalQuickSort; import org.apache.doris.nereids.trees.plans.physical.PhysicalTopN; @@ -96,6 +103,11 @@ public class StatsCalculator extends DefaultPlanVisitor<StatsDeriveResult, Void> groupExpression.setStatDerived(true); } + @Override + public StatsDeriveResult visitLogicalEmptyRelation(LogicalEmptyRelation emptyRelation, Void context) { + return computeEmptyRelation(emptyRelation); + } + @Override public StatsDeriveResult visitLogicalLimit(LogicalLimit<? extends Plan> limit, Void context) { return computeLimit(limit); @@ -106,6 +118,11 @@ public class StatsCalculator extends DefaultPlanVisitor<StatsDeriveResult, Void> return computeLimit(limit); } + @Override + public StatsDeriveResult visitLogicalOneRowRelation(LogicalOneRowRelation oneRowRelation, Void context) { + return computeOneRowRelation(oneRowRelation); + } + @Override public StatsDeriveResult visitLogicalAggregate(LogicalAggregate<? extends Plan> aggregate, Void context) { return computeAggregate(aggregate); @@ -149,11 +166,21 @@ public class StatsCalculator extends DefaultPlanVisitor<StatsDeriveResult, Void> return groupExpression.getCopyOfChildStats(0); } + @Override + public StatsDeriveResult visitPhysicalEmptyRelation(PhysicalEmptyRelation emptyRelation, Void context) { + return computeEmptyRelation(emptyRelation); + } + @Override public StatsDeriveResult visitPhysicalAggregate(PhysicalAggregate<? extends Plan> agg, Void context) { return computeAggregate(agg); } + @Override + public StatsDeriveResult visitPhysicalOneRowRelation(PhysicalOneRowRelation oneRowRelation, Void context) { + return computeOneRowRelation(oneRowRelation); + } + @Override public StatsDeriveResult visitPhysicalOlapScan(PhysicalOlapScan olapScan, Void context) { return computeScan(olapScan); @@ -320,4 +347,34 @@ public class StatsCalculator extends DefaultPlanVisitor<StatsDeriveResult, Void> statsDeriveResult.setSlotToColumnStats(columnsStats); return statsDeriveResult; } + + private StatsDeriveResult computeOneRowRelation(OneRowRelation oneRowRelation) { + Map<Slot, ColumnStats> columnStatsMap = oneRowRelation.getProjects() + .stream() + .map(project -> { + ColumnStats columnStats = new ColumnStats(); + columnStats.setNdv(1); + // TODO: compute the literal size + return Pair.of(project.toSlot(), columnStats); + }) + .collect(Collectors.toMap(Pair::key, Pair::value)); + int rowCount = 1; + return new StatsDeriveResult(rowCount, columnStatsMap); + } + + private StatsDeriveResult computeEmptyRelation(EmptyRelation emptyRelation) { + Map<Slot, ColumnStats> columnStatsMap = emptyRelation.getProjects() + .stream() + .map(project -> { + ColumnStats columnStats = new ColumnStats(); + columnStats.setNdv(0); + columnStats.setMaxSize(0); + columnStats.setNumNulls(0); + columnStats.setAvgSize(0); + return Pair.of(project.toSlot(), columnStats); + }) + .collect(Collectors.toMap(Pair::key, Pair::value)); + int rowCount = 0; + return new StatsDeriveResult(rowCount, columnStatsMap); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java index ea8158ae22..04381846ab 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/TreeNode.java @@ -84,4 +84,20 @@ public interface TreeNode<NODE_TYPE extends TreeNode<NODE_TYPE>> { }); return (T) result.build(); } + + /** + * iterate top down and test predicate if contains any instance of the classes + * @param types classes array + * @return true if it has any instance of the types + */ + default boolean containsType(Class...types) { + return anyMatch(node -> { + for (Class type : types) { + if (type.isInstance(node)) { + return true; + } + } + return false; + }); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SlotReference.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SlotReference.java index ec62dbe25e..6634933318 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SlotReference.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SlotReference.java @@ -26,17 +26,23 @@ import com.google.common.collect.ImmutableList; import java.util.List; import java.util.Objects; +import java.util.Optional; +import javax.annotation.Nullable; /** * Reference to slot in expression. */ public class SlotReference extends Slot { private final ExprId exprId; + // TODO: we should distinguish the name is alias or column name, and the column name should contains + // `cluster:db`.`table`.`column` private final String name; private final List<String> qualifier; private final DataType dataType; private final boolean nullable; + private final Column column; + public SlotReference(String name, DataType dataType) { this(NamedExpressionUtil.newExprId(), name, dataType, true, ImmutableList.of()); } @@ -49,6 +55,10 @@ public class SlotReference extends Slot { this(NamedExpressionUtil.newExprId(), name, dataType, nullable, qualifier); } + public SlotReference(ExprId exprId, String name, DataType dataType, boolean nullable, List<String> qualifier) { + this(exprId, name, dataType, nullable, qualifier, null); + } + /** * Constructor for SlotReference. * @@ -57,18 +67,22 @@ public class SlotReference extends Slot { * @param dataType slot reference logical data type * @param nullable true if nullable * @param qualifier slot reference qualifier + * @param column the column which this slot come from */ - public SlotReference(ExprId exprId, String name, DataType dataType, boolean nullable, List<String> qualifier) { + public SlotReference(ExprId exprId, String name, DataType dataType, boolean nullable, + List<String> qualifier, @Nullable Column column) { this.exprId = exprId; this.name = name; this.dataType = dataType; this.qualifier = qualifier; this.nullable = nullable; + this.column = column; } public static SlotReference fromColumn(Column column, List<String> qualifier) { DataType dataType = DataType.convertFromCatalogDataType(column.getType()); - return new SlotReference(column.getName(), dataType, column.isAllowNull(), qualifier); + return new SlotReference(NamedExpressionUtil.newExprId(), column.getName(), dataType, + column.isAllowNull(), qualifier, column); } @Override @@ -134,8 +148,8 @@ public class SlotReference extends Slot { return Objects.hash(exprId); } - public Column getColumn() { - return new Column(name, dataType.toCatalogDataType()); + public Optional<Column> getColumn() { + return Optional.ofNullable(column); } @Override @@ -158,7 +172,7 @@ public class SlotReference extends Slot { @Override public Slot withQualifier(List<String> qualifiers) { - return new SlotReference(exprId, name, dataType, nullable, qualifiers); + return new SlotReference(exprId, name, dataType, nullable, qualifiers, column); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/Substring.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/Substring.java index d33a66e6a9..ac90843349 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/Substring.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/Substring.java @@ -23,7 +23,7 @@ import org.apache.doris.nereids.trees.expressions.shape.TernaryExpression; import org.apache.doris.nereids.trees.expressions.typecoercion.ImplicitCastInputTypes; import org.apache.doris.nereids.types.DataType; import org.apache.doris.nereids.types.IntegerType; -import org.apache.doris.nereids.types.StringType; +import org.apache.doris.nereids.types.VarcharType; import org.apache.doris.nereids.types.coercion.AbstractDataType; import org.apache.doris.nereids.types.coercion.TypeCollection; @@ -52,9 +52,24 @@ public class Substring extends BoundFunction implements TernaryExpression, Impli super("substring", str, pos, new IntegerLiteral(Integer.MAX_VALUE)); } + public Expression getTarget() { + return child(0); + } + + public Expression getPosition() { + return child(1); + } + + public Expression getLength() { + return child(2); + } + @Override public DataType getDataType() { - return StringType.INSTANCE; + if (getLength() instanceof IntegerLiteral) { + return VarcharType.createVarcharType(((IntegerLiteral) getLength()).getValue()); + } + return VarcharType.SYSTEM_DEFAULT; } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java index c80d2a30db..4ba8265c9a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java @@ -24,6 +24,7 @@ import org.apache.doris.nereids.trees.expressions.shape.LeafExpression; import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor; import org.apache.doris.nereids.types.DataType; +import java.math.BigInteger; import java.util.Objects; /** @@ -49,8 +50,16 @@ public abstract class Literal extends Expression implements LeafExpression { public static Literal of(Object value) { if (value == null) { return new NullLiteral(); + } else if (value instanceof Byte) { + return new TinyIntLiteral(((Byte) value).byteValue()); + } else if (value instanceof Short) { + return new SmallIntLiteral(((Short) value).shortValue()); } else if (value instanceof Integer) { return new IntegerLiteral((Integer) value); + } else if (value instanceof Long) { + return new BigIntLiteral(((Long) value).longValue()); + } else if (value instanceof BigInteger) { + return new LargeIntLiteral((BigInteger) value); } else if (value instanceof Boolean) { return new BooleanLiteral((Boolean) value); } else if (value instanceof String) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/VarcharLiteral.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/VarcharLiteral.java index 7d43a3cd4d..99e40811d7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/VarcharLiteral.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/VarcharLiteral.java @@ -58,4 +58,9 @@ public class VarcharLiteral extends Literal { public LiteralExpr toLegacyLiteral() { return new StringLiteral(value); } + + @Override + public String toString() { + return "'" + value + "'"; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java index 68aae991db..9ef8a7eae9 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/PlanType.java @@ -25,6 +25,9 @@ public enum PlanType { // logical plan LOGICAL_SUBQUERY_ALIAS, + LOGICAL_UNBOUND_ONE_ROW_RELATION, + LOGICAL_EMPTY_RELATION, + LOGICAL_ONE_ROW_RELATION, LOGICAL_UNBOUND_RELATION, LOGICAL_BOUND_RELATION, LOGICAL_PROJECT, @@ -42,6 +45,8 @@ public enum PlanType { GROUP_PLAN, // physical plan + PHYSICAL_EMPTY_RELATION, + PHYSICAL_ONE_ROW_RELATION, PHYSICAL_OLAP_SCAN, PHYSICAL_PROJECT, PHYSICAL_FILTER, diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/EmptyRelation.java similarity index 68% copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/EmptyRelation.java index f0c536cf83..ed6a6907ad 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/EmptyRelation.java @@ -17,22 +17,16 @@ package org.apache.doris.nereids.trees.plans.algebra; -import org.apache.doris.catalog.Table; -import org.apache.doris.nereids.trees.expressions.Expression; -import org.apache.doris.nereids.trees.expressions.Slot; +import org.apache.doris.nereids.trees.expressions.NamedExpression; -import java.util.Collections; import java.util.List; /** - * Common interface for logical/physical scan. + * Common interface for logical/physical empty relation. + * + * e.g. + * select * from tbl limit 0 */ -public interface Scan { - List<Expression> getExpressions(); - - Table getTable(); - - default List<Slot> getOutput() { - return Collections.emptyList(); - } +public interface EmptyRelation { + List<NamedExpression> getProjects(); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/OneRowRelation.java similarity index 68% copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java copy to fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/OneRowRelation.java index f0c536cf83..2c63d4e856 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/OneRowRelation.java @@ -17,22 +17,14 @@ package org.apache.doris.nereids.trees.plans.algebra; -import org.apache.doris.catalog.Table; -import org.apache.doris.nereids.trees.expressions.Expression; -import org.apache.doris.nereids.trees.expressions.Slot; +import org.apache.doris.nereids.analyzer.Relation; +import org.apache.doris.nereids.trees.expressions.NamedExpression; -import java.util.Collections; import java.util.List; /** - * Common interface for logical/physical scan. + * Common interface for logical/physical OneRowRelation. */ -public interface Scan { - List<Expression> getExpressions(); - - Table getTable(); - - default List<Slot> getOutput() { - return Collections.emptyList(); - } +public interface OneRowRelation extends Relation { + List<NamedExpression> getProjects(); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java index f0c536cf83..37e0b75bd7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java @@ -18,6 +18,7 @@ package org.apache.doris.nereids.trees.plans.algebra; import org.apache.doris.catalog.Table; +import org.apache.doris.nereids.analyzer.Relation; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.Slot; @@ -27,7 +28,7 @@ import java.util.List; /** * Common interface for logical/physical scan. */ -public interface Scan { +public interface Scan extends Relation { List<Expression> getExpressions(); Table getTable(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalEmptyRelation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalEmptyRelation.java new file mode 100644 index 0000000000..0db6d661b3 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalEmptyRelation.java @@ -0,0 +1,113 @@ +// 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.memo.GroupExpression; +import org.apache.doris.nereids.properties.LogicalProperties; +import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.NamedExpression; +import org.apache.doris.nereids.trees.expressions.Slot; +import org.apache.doris.nereids.trees.plans.Plan; +import org.apache.doris.nereids.trees.plans.PlanType; +import org.apache.doris.nereids.trees.plans.algebra.EmptyRelation; +import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; +import org.apache.doris.nereids.util.Utils; + +import com.google.common.collect.ImmutableList; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +/** + * A logical relation that contains empty row. + * e.g. + * select * from tbl limit 0 + */ +public class LogicalEmptyRelation extends LogicalLeaf implements EmptyRelation { + private final List<NamedExpression> projects; + + public LogicalEmptyRelation(List<NamedExpression> projects) { + this(projects, Optional.empty(), Optional.empty()); + } + + public LogicalEmptyRelation(List<NamedExpression> projects, Optional<GroupExpression> groupExpression, + Optional<LogicalProperties> logicalProperties) { + super(PlanType.LOGICAL_ONE_ROW_RELATION, groupExpression, logicalProperties); + this.projects = ImmutableList.copyOf(Objects.requireNonNull(projects, "projects can not be null")); + } + + @Override + public <R, C> R accept(PlanVisitor<R, C> visitor, C context) { + return visitor.visitLogicalEmptyRelation(this, context); + } + + @Override + public List<NamedExpression> getProjects() { + return projects; + } + + @Override + public List<Expression> getExpressions() { + return ImmutableList.of(); + } + + @Override + public Plan withGroupExpression(Optional<GroupExpression> groupExpression) { + return new LogicalEmptyRelation(projects, groupExpression, Optional.of(logicalPropertiesSupplier.get())); + } + + @Override + public Plan withLogicalProperties(Optional<LogicalProperties> logicalProperties) { + return new LogicalEmptyRelation(projects, Optional.empty(), logicalProperties); + } + + @Override + public List<Slot> computeOutput() { + return projects.stream() + .map(NamedExpression::toSlot) + .collect(ImmutableList.toImmutableList()); + } + + @Override + public String toString() { + return Utils.toSqlString("LogicalEmptyRelation", + "projects", projects + ); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + LogicalEmptyRelation that = (LogicalEmptyRelation) o; + return Objects.equals(projects, that.projects); + } + + @Override + public int hashCode() { + return Objects.hash(projects); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOneRowRelation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOneRowRelation.java new file mode 100644 index 0000000000..3486fe7200 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalOneRowRelation.java @@ -0,0 +1,115 @@ +// 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.memo.GroupExpression; +import org.apache.doris.nereids.properties.LogicalProperties; +import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.NamedExpression; +import org.apache.doris.nereids.trees.expressions.Slot; +import org.apache.doris.nereids.trees.plans.Plan; +import org.apache.doris.nereids.trees.plans.PlanType; +import org.apache.doris.nereids.trees.plans.algebra.OneRowRelation; +import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; +import org.apache.doris.nereids.util.Utils; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +/** + * A relation that contains only one row consist of some constant expressions. + * e.g. select 100, 'value' + */ +public class LogicalOneRowRelation extends LogicalLeaf implements OneRowRelation { + private final List<NamedExpression> projects; + + public LogicalOneRowRelation(List<NamedExpression> projects) { + this(projects, Optional.empty(), Optional.empty()); + } + + private LogicalOneRowRelation(List<NamedExpression> projects, Optional<GroupExpression> groupExpression, + Optional<LogicalProperties> logicalProperties) { + super(PlanType.LOGICAL_ONE_ROW_RELATION, groupExpression, logicalProperties); + Preconditions.checkArgument(projects.stream().noneMatch(p -> p.containsType(Slot.class)), + "OneRowRelation can not contains any slot"); + this.projects = ImmutableList.copyOf(Objects.requireNonNull(projects, "projects can not be null")); + } + + @Override + public <R, C> R accept(PlanVisitor<R, C> visitor, C context) { + return visitor.visitLogicalOneRowRelation(this, context); + } + + @Override + public List<NamedExpression> getProjects() { + return projects; + } + + @Override + public List<Expression> getExpressions() { + return (List) projects; + } + + @Override + public Plan withGroupExpression(Optional<GroupExpression> groupExpression) { + return new LogicalOneRowRelation(projects, groupExpression, Optional.of(logicalPropertiesSupplier.get())); + } + + @Override + public Plan withLogicalProperties(Optional<LogicalProperties> logicalProperties) { + return new LogicalOneRowRelation(projects, Optional.empty(), logicalProperties); + } + + @Override + public List<Slot> computeOutput() { + return projects.stream() + .map(NamedExpression::toSlot) + .collect(ImmutableList.toImmutableList()); + } + + @Override + public String toString() { + return Utils.toSqlString("LogicalOneRowRelation", + "projects", projects + ); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + LogicalOneRowRelation that = (LogicalOneRowRelation) o; + return Objects.equals(projects, that.projects); + } + + @Override + public int hashCode() { + return Objects.hash(projects); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/AbstractPhysicalPlan.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/AbstractPhysicalPlan.java index e28d0ecdef..ffb493013d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/AbstractPhysicalPlan.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/AbstractPhysicalPlan.java @@ -25,6 +25,7 @@ import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.PlanType; import java.util.Optional; +import javax.annotation.Nullable; /** * Abstract class for all concrete physical plan. @@ -54,9 +55,9 @@ public abstract class AbstractPhysicalPlan extends AbstractPlan implements Physi } public AbstractPhysicalPlan(PlanType type, Optional<GroupExpression> groupExpression, - LogicalProperties logicalProperties, PhysicalProperties physicalProperties, Plan... children) { + LogicalProperties logicalProperties, @Nullable PhysicalProperties physicalProperties, Plan... children) { super(type, groupExpression, Optional.of(logicalProperties), children); - this.physicalProperties = physicalProperties; + this.physicalProperties = physicalProperties == null ? PhysicalProperties.ANY : physicalProperties; } public PhysicalProperties getPhysicalProperties() { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalBinary.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalBinary.java index 5b5a8602c3..ab62f137c1 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalBinary.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalBinary.java @@ -25,6 +25,7 @@ import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.PlanType; import java.util.Optional; +import javax.annotation.Nullable; /** * Abstract class for all physical plan that have two children. @@ -47,8 +48,8 @@ public abstract class PhysicalBinary< } public PhysicalBinary(PlanType type, Optional<GroupExpression> groupExpression, - LogicalProperties logicalProperties, PhysicalProperties physicalProperties, LEFT_CHILD_TYPE leftChild, - RIGHT_CHILD_TYPE rightChild) { + LogicalProperties logicalProperties, @Nullable PhysicalProperties physicalProperties, + LEFT_CHILD_TYPE leftChild, RIGHT_CHILD_TYPE rightChild) { super(type, groupExpression, logicalProperties, physicalProperties, leftChild, rightChild); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalEmptyRelation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalEmptyRelation.java new file mode 100644 index 0000000000..20c4fc687e --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalEmptyRelation.java @@ -0,0 +1,122 @@ +// 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.physical; + +import org.apache.doris.nereids.memo.GroupExpression; +import org.apache.doris.nereids.properties.LogicalProperties; +import org.apache.doris.nereids.properties.PhysicalProperties; +import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.NamedExpression; +import org.apache.doris.nereids.trees.expressions.Slot; +import org.apache.doris.nereids.trees.plans.Plan; +import org.apache.doris.nereids.trees.plans.PlanType; +import org.apache.doris.nereids.trees.plans.algebra.EmptyRelation; +import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; +import org.apache.doris.nereids.util.Utils; + +import com.google.common.collect.ImmutableList; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +/** + * A physical relation that contains empty row. + * e.g. + * select * from tbl limit 0 + */ +public class PhysicalEmptyRelation extends PhysicalLeaf implements EmptyRelation { + private final List<NamedExpression> projects; + + public PhysicalEmptyRelation(List<NamedExpression> projects, LogicalProperties logicalProperties) { + this(projects, Optional.empty(), logicalProperties, null); + } + + public PhysicalEmptyRelation(List<NamedExpression> projects, Optional<GroupExpression> groupExpression, + LogicalProperties logicalProperties, PhysicalProperties physicalProperties) { + super(PlanType.PHYSICAL_EMPTY_RELATION, groupExpression, logicalProperties, physicalProperties); + this.projects = ImmutableList.copyOf(Objects.requireNonNull(projects, "projects can not be null")); + } + + @Override + public <R, C> R accept(PlanVisitor<R, C> visitor, C context) { + return visitor.visitPhysicalEmptyRelation(this, context); + } + + @Override + public List<Expression> getExpressions() { + return ImmutableList.of(); + } + + @Override + public Plan withGroupExpression(Optional<GroupExpression> groupExpression) { + return new PhysicalEmptyRelation(projects, groupExpression, + logicalPropertiesSupplier.get(), physicalProperties); + } + + @Override + public Plan withLogicalProperties(Optional<LogicalProperties> logicalProperties) { + return new PhysicalEmptyRelation(projects, Optional.empty(), + logicalProperties.get(), physicalProperties); + } + + @Override + public List<Slot> computeOutput() { + return projects.stream() + .map(NamedExpression::toSlot) + .collect(ImmutableList.toImmutableList()); + } + + @Override + public String toString() { + return Utils.toSqlString("PhysicalEmptyRelation", + "projects", projects + ); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + PhysicalEmptyRelation that = (PhysicalEmptyRelation) o; + return Objects.equals(projects, that.projects); + } + + @Override + public int hashCode() { + return Objects.hash(projects); + } + + @Override + public List<NamedExpression> getProjects() { + return projects; + } + + @Override + public PhysicalPlan withPhysicalProperties(PhysicalProperties physicalProperties) { + return new PhysicalEmptyRelation(projects, Optional.empty(), + logicalPropertiesSupplier.get(), physicalProperties); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalLeaf.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalLeaf.java index ee174a970c..8ca608994e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalLeaf.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalLeaf.java @@ -24,6 +24,7 @@ import org.apache.doris.nereids.trees.plans.LeafPlan; import org.apache.doris.nereids.trees.plans.PlanType; import java.util.Optional; +import javax.annotation.Nullable; /** * Abstract class for all physical plan that have no child. @@ -40,7 +41,7 @@ public abstract class PhysicalLeaf extends AbstractPhysicalPlan implements LeafP } public PhysicalLeaf(PlanType type, Optional<GroupExpression> groupExpression, - LogicalProperties logicalProperties, PhysicalProperties physicalProperties) { + LogicalProperties logicalProperties, @Nullable PhysicalProperties physicalProperties) { super(type, groupExpression, logicalProperties, physicalProperties); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOneRowRelation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOneRowRelation.java new file mode 100644 index 0000000000..fc44e8da29 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalOneRowRelation.java @@ -0,0 +1,113 @@ +// 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.physical; + +import org.apache.doris.nereids.memo.GroupExpression; +import org.apache.doris.nereids.properties.LogicalProperties; +import org.apache.doris.nereids.properties.PhysicalProperties; +import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.NamedExpression; +import org.apache.doris.nereids.trees.plans.Plan; +import org.apache.doris.nereids.trees.plans.PlanType; +import org.apache.doris.nereids.trees.plans.algebra.OneRowRelation; +import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; +import org.apache.doris.nereids.util.Utils; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +/** + * A physical relation that contains only one row consist of some constant expressions. + * e.g. select 100, 'value' + */ +public class PhysicalOneRowRelation extends PhysicalLeaf implements OneRowRelation { + private final List<NamedExpression> projects; + + public PhysicalOneRowRelation(List<NamedExpression> projects, LogicalProperties logicalProperties) { + this(projects, Optional.empty(), logicalProperties, null); + } + + private PhysicalOneRowRelation(List<NamedExpression> projects, Optional<GroupExpression> groupExpression, + LogicalProperties logicalProperties, PhysicalProperties physicalProperties) { + super(PlanType.PHYSICAL_ONE_ROW_RELATION, groupExpression, logicalProperties, physicalProperties); + Preconditions.checkArgument(projects.stream().allMatch(Expression::isConstant), + "OneRowRelation must consist of some constant expression"); + this.projects = ImmutableList.copyOf(Objects.requireNonNull(projects, "projects can not be null")); + } + + @Override + public <R, C> R accept(PlanVisitor<R, C> visitor, C context) { + return visitor.visitPhysicalOneRowRelation(this, context); + } + + @Override + public List<NamedExpression> getProjects() { + return projects; + } + + @Override + public List<Expression> getExpressions() { + return (List) projects; + } + + @Override + public Plan withGroupExpression(Optional<GroupExpression> groupExpression) { + return new PhysicalOneRowRelation(projects, groupExpression, + logicalPropertiesSupplier.get(), physicalProperties); + } + + @Override + public Plan withLogicalProperties(Optional<LogicalProperties> logicalProperties) { + return new PhysicalOneRowRelation(projects, Optional.empty(), + logicalProperties.get(), physicalProperties); + } + + @Override + public String toString() { + return Utils.toSqlString("PhysicalOneRowRelation", + "expressions", projects + ); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PhysicalOneRowRelation that = (PhysicalOneRowRelation) o; + return Objects.equals(projects, that.projects); + } + + @Override + public int hashCode() { + return Objects.hash(projects); + } + + @Override + public PhysicalOneRowRelation withPhysicalProperties(PhysicalProperties physicalProperties) { + return new PhysicalOneRowRelation(projects, Optional.empty(), + logicalPropertiesSupplier.get(), physicalProperties); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalUnary.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalUnary.java index a387b7e5a3..5337938df0 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalUnary.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalUnary.java @@ -25,6 +25,7 @@ import org.apache.doris.nereids.trees.plans.PlanType; import org.apache.doris.nereids.trees.plans.UnaryPlan; import java.util.Optional; +import javax.annotation.Nullable; /** * Abstract class for all physical plan that have one child. @@ -43,7 +44,7 @@ public abstract class PhysicalUnary<CHILD_TYPE extends Plan> } public PhysicalUnary(PlanType type, Optional<GroupExpression> groupExpression, - LogicalProperties logicalProperties, PhysicalProperties physicalProperties, CHILD_TYPE child) { + LogicalProperties logicalProperties, @Nullable PhysicalProperties physicalProperties, CHILD_TYPE child) { super(type, groupExpression, logicalProperties, physicalProperties, child); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/PlanVisitor.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/PlanVisitor.java index e50c81d608..e96cdeb564 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/PlanVisitor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/PlanVisitor.java @@ -17,6 +17,7 @@ package org.apache.doris.nereids.trees.plans.visitor; +import org.apache.doris.nereids.analyzer.UnboundOneRowRelation; import org.apache.doris.nereids.analyzer.UnboundRelation; import org.apache.doris.nereids.trees.plans.GroupPlan; import org.apache.doris.nereids.trees.plans.Plan; @@ -25,11 +26,13 @@ import org.apache.doris.nereids.trees.plans.commands.ExplainCommand; import org.apache.doris.nereids.trees.plans.logical.LogicalAggregate; import org.apache.doris.nereids.trees.plans.logical.LogicalApply; import org.apache.doris.nereids.trees.plans.logical.LogicalAssertNumRows; +import org.apache.doris.nereids.trees.plans.logical.LogicalEmptyRelation; import org.apache.doris.nereids.trees.plans.logical.LogicalFilter; import org.apache.doris.nereids.trees.plans.logical.LogicalHaving; import org.apache.doris.nereids.trees.plans.logical.LogicalJoin; import org.apache.doris.nereids.trees.plans.logical.LogicalLimit; import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan; +import org.apache.doris.nereids.trees.plans.logical.LogicalOneRowRelation; import org.apache.doris.nereids.trees.plans.logical.LogicalProject; import org.apache.doris.nereids.trees.plans.logical.LogicalRelation; import org.apache.doris.nereids.trees.plans.logical.LogicalSelectHint; @@ -40,12 +43,14 @@ import org.apache.doris.nereids.trees.plans.physical.AbstractPhysicalSort; import org.apache.doris.nereids.trees.plans.physical.PhysicalAggregate; import org.apache.doris.nereids.trees.plans.physical.PhysicalAssertNumRows; import org.apache.doris.nereids.trees.plans.physical.PhysicalDistribute; +import org.apache.doris.nereids.trees.plans.physical.PhysicalEmptyRelation; import org.apache.doris.nereids.trees.plans.physical.PhysicalFilter; import org.apache.doris.nereids.trees.plans.physical.PhysicalHashJoin; import org.apache.doris.nereids.trees.plans.physical.PhysicalLimit; import org.apache.doris.nereids.trees.plans.physical.PhysicalLocalQuickSort; import org.apache.doris.nereids.trees.plans.physical.PhysicalNestedLoopJoin; import org.apache.doris.nereids.trees.plans.physical.PhysicalOlapScan; +import org.apache.doris.nereids.trees.plans.physical.PhysicalOneRowRelation; import org.apache.doris.nereids.trees.plans.physical.PhysicalProject; import org.apache.doris.nereids.trees.plans.physical.PhysicalQuickSort; import org.apache.doris.nereids.trees.plans.physical.PhysicalRelation; @@ -81,6 +86,18 @@ public abstract class PlanVisitor<R, C> { return visit(alias, context); } + public R visitUnboundOneRowRelation(UnboundOneRowRelation oneRowRelation, C context) { + return visit(oneRowRelation, context); + } + + public R visitLogicalEmptyRelation(LogicalEmptyRelation emptyRelation, C context) { + return visit(emptyRelation, context); + } + + public R visitLogicalOneRowRelation(LogicalOneRowRelation oneRowRelation, C context) { + return visit(oneRowRelation, context); + } + public R visitUnboundRelation(UnboundRelation relation, C context) { return visit(relation, context); } @@ -153,6 +170,14 @@ public abstract class PlanVisitor<R, C> { return visit(scan, context); } + public R visitPhysicalEmptyRelation(PhysicalEmptyRelation emptyRelation, C context) { + return visit(emptyRelation, context); + } + + public R visitPhysicalOneRowRelation(PhysicalOneRowRelation oneRowRelation, C context) { + return visit(oneRowRelation, context); + } + public R visitPhysicalOlapScan(PhysicalOlapScan olapScan, C context) { return visitPhysicalScan(olapScan, context); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DataType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DataType.java index 1b1060f0af..b786cefd58 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DataType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DataType.java @@ -33,12 +33,16 @@ import com.google.common.collect.ImmutableMap; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.function.Supplier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Abstract class for all data type in Nereids. */ public abstract class DataType implements AbstractDataType { + private static final Pattern VARCHAR_PATTERN = Pattern.compile("varchar(\\(\\d+\\))?"); // use class and supplier here to avoid class load deadlock. private static final Map<Class<? extends NumericType>, Supplier<DataType>> PROMOTION_MAP @@ -116,14 +120,21 @@ public abstract class DataType implements AbstractDataType { public static DataType convertFromString(String type) { // TODO: use a better way to resolve types // TODO: support varchar, char, decimal - switch (type.toLowerCase()) { + type = type.toLowerCase(); + switch (type) { case "bool": case "boolean": return BooleanType.INSTANCE; + case "tinyint": + return TinyIntType.INSTANCE; + case "smallint": + return SmallIntType.INSTANCE; case "int": return IntegerType.INSTANCE; case "bigint": return BigIntType.INSTANCE; + case "largeint": + return LargeIntType.INSTANCE; case "double": return DoubleType.INSTANCE; case "string": @@ -133,6 +144,10 @@ public abstract class DataType implements AbstractDataType { case "datetime": return DateTimeType.INSTANCE; default: + Optional<VarcharType> varcharType = matchVarchar(type); + if (varcharType.isPresent()) { + return varcharType.get(); + } throw new AnalysisException("Nereids do not support type: " + type); } } @@ -229,4 +244,15 @@ public abstract class DataType implements AbstractDataType { } public abstract int width(); + + private static Optional<VarcharType> matchVarchar(String type) { + Matcher matcher = VARCHAR_PATTERN.matcher(type); + if (matcher.find()) { + VarcharType varcharType = matcher.groupCount() > 1 + ? VarcharType.createVarcharType(Integer.valueOf(matcher.group(1))) + : VarcharType.SYSTEM_DEFAULT; + return Optional.of(varcharType); + } + return Optional.empty(); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/planner/SetOperationNode.java b/fe/fe-core/src/main/java/org/apache/doris/planner/SetOperationNode.java index bd130a8957..ad6e4ee8fb 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/planner/SetOperationNode.java +++ b/fe/fe-core/src/main/java/org/apache/doris/planner/SetOperationNode.java @@ -445,4 +445,18 @@ public abstract class SetOperationNode extends PlanNode { numInstances = Math.max(1, numInstances); return numInstances; } + + public void finalizeForNereids(TupleDescriptor tupleDescriptor, List<SlotDescriptor> constExprSlots) { + materializedConstExprLists.clear(); + for (List<Expr> exprList : constExprLists) { + Preconditions.checkState(exprList.size() == constExprSlots.size()); + List<Expr> newExprList = Lists.newArrayList(); + for (int i = 0; i < exprList.size(); ++i) { + if (constExprSlots.get(i).isMaterialized()) { + newExprList.add(exprList.get(i)); + } + } + materializedConstExprLists.add(newExprList); + } + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/planner/UnionNode.java b/fe/fe-core/src/main/java/org/apache/doris/planner/UnionNode.java index ef42258d71..40982d07e7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/planner/UnionNode.java +++ b/fe/fe-core/src/main/java/org/apache/doris/planner/UnionNode.java @@ -29,11 +29,11 @@ import org.apache.doris.thrift.TPlanNodeType; import java.util.List; public class UnionNode extends SetOperationNode { - protected UnionNode(PlanNodeId id, TupleId tupleId) { + public UnionNode(PlanNodeId id, TupleId tupleId) { super(id, tupleId, "UNION", StatisticalType.UNION_NODE); } - protected UnionNode(PlanNodeId id, TupleId tupleId, + public UnionNode(PlanNodeId id, TupleId tupleId, List<Expr> setOpResultExprs, boolean isInSubplan) { super(id, tupleId, "UNION", setOpResultExprs, isInSubplan, StatisticalType.UNION_NODE); } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/memo/MemoRewriteTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/memo/MemoRewriteTest.java index 45fb703921..f4ecd3cf45 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/memo/MemoRewriteTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/memo/MemoRewriteTest.java @@ -229,9 +229,9 @@ public class MemoRewriteTest implements PatternMatchSupported { * A -> A(B): will run into dead loop, we can not detect it in the group tree, because B usually not equals * to other object (e.g. UnboundRelation), but can detect the rule's invoke times. * - * limit(student) limit(1) limit(1) - * | -> | -> | -> ... - * any any any + * limit(1) limit(1) limit(1) + * | -> | -> | -> ... + * UnboundRelation(student) UnboundRelation(student) UnboundRelation(student) * * you should split A into some states: * 1. A(not rewrite) @@ -310,8 +310,7 @@ public class MemoRewriteTest implements PatternMatchSupported { logicalLimit().when(limit10::equals).then(limit -> limit) ) .checkGroupNum(2) - .checkFirstRootLogicalPlan(limit10) - .matches( + .matchesFromRoot( logicalLimit( logicalOlapScan().when(student::equals) ).when(limit10::equals) @@ -335,8 +334,7 @@ public class MemoRewriteTest implements PatternMatchSupported { logicalLimit().when(limit10::equals).then(limit -> limit.withChildren(limit.child())) ) .checkGroupNum(2) - .checkFirstRootLogicalPlan(limit10) - .matches( + .matchesFromRoot( logicalLimit( logicalOlapScan().when(student::equals) ).when(limit10::equals) @@ -360,8 +358,7 @@ public class MemoRewriteTest implements PatternMatchSupported { logicalLimit().when(limit10::equals).then(limit -> limit.child()) ) .checkGroupNum(1) - .checkFirstRootLogicalPlan(student) - .matches( + .matchesFromRoot( logicalOlapScan().when(student::equals) ); } @@ -383,8 +380,7 @@ public class MemoRewriteTest implements PatternMatchSupported { logicalLimit(logicalOlapScan()).when(limit10::equals).then(limit -> limit.child()) ) .checkGroupNum(1) - .checkFirstRootLogicalPlan(student) - .matches( + .matchesFromRoot( logicalOlapScan().when(student::equals) ); } @@ -407,8 +403,7 @@ public class MemoRewriteTest implements PatternMatchSupported { logicalLimit(unboundRelation()).then(limit -> student) ) .checkGroupNum(1) - .checkFirstRootLogicalPlan(student) - .matches( + .matchesFromRoot( logicalOlapScan().when(student::equals) ); } @@ -433,8 +428,7 @@ public class MemoRewriteTest implements PatternMatchSupported { logicalLimit(unboundRelation()).then(limit -> limit5) ) .checkGroupNum(2) - .checkFirstRootLogicalPlan(limit5) - .matches( + .matchesFromRoot( logicalLimit( logicalOlapScan().when(student::equals) ).when(limit5::equals) @@ -460,8 +454,7 @@ public class MemoRewriteTest implements PatternMatchSupported { logicalLimit().when(limit10::equals).then(limit -> limit5) ) .checkGroupNum(2) - .checkFirstRootLogicalPlan(limit5) - .matches( + .matchesFromRoot( logicalLimit( logicalOlapScan().when(student::equals) ).when(limit5::equals) @@ -547,8 +540,7 @@ public class MemoRewriteTest implements PatternMatchSupported { logicalLimit(unboundRelation()).then(l -> limit10) ) .checkGroupNum(3) - .checkFirstRootLogicalPlan(limit10) - .matches( + .matchesFromRoot( logicalLimit( logicalLimit( logicalOlapScan().when(scan::equals) @@ -587,8 +579,7 @@ public class MemoRewriteTest implements PatternMatchSupported { ) ) .checkGroupNum(3) - .checkFirstRootLogicalPlan(limit5) - .matches( + .matchesFromRoot( logicalLimit( logicalLimit( unboundRelation().when(student::equals) diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/HavingClauseTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/HavingClauseTest.java index c2120ca019..655c347aa0 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/HavingClauseTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/HavingClauseTest.java @@ -20,6 +20,8 @@ package org.apache.doris.nereids.parser; import org.apache.doris.common.ExceptionChecker; import org.apache.doris.nereids.datasets.tpch.AnalyzeCheckTestBase; import org.apache.doris.nereids.exceptions.AnalysisException; +import org.apache.doris.nereids.rules.expression.rewrite.ExpressionRewrite; +import org.apache.doris.nereids.rules.expression.rewrite.rules.TypeCoercion; import org.apache.doris.nereids.trees.expressions.Add; import org.apache.doris.nereids.trees.expressions.Alias; import org.apache.doris.nereids.trees.expressions.And; @@ -30,8 +32,9 @@ import org.apache.doris.nereids.trees.expressions.SlotReference; import org.apache.doris.nereids.trees.expressions.functions.Count; import org.apache.doris.nereids.trees.expressions.functions.Min; import org.apache.doris.nereids.trees.expressions.functions.Sum; -import org.apache.doris.nereids.trees.expressions.literal.IntegerLiteral; -import org.apache.doris.nereids.types.IntegerType; +import org.apache.doris.nereids.trees.expressions.literal.Literal; +import org.apache.doris.nereids.trees.expressions.literal.TinyIntLiteral; +import org.apache.doris.nereids.types.TinyIntType; import org.apache.doris.nereids.util.FieldChecker; import org.apache.doris.nereids.util.PatternMatchSupported; import org.apache.doris.nereids.util.PlanChecker; @@ -50,9 +53,9 @@ public class HavingClauseTest extends AnalyzeCheckTestBase implements PatternMat connectContext.setDatabase("default_cluster:test_having"); createTables( "CREATE TABLE t1 (\n" - + " pk INT,\n" - + " a1 INT,\n" - + " a2 INT\n" + + " pk TINYINT,\n" + + " a1 TINYINT,\n" + + " a2 TINYINT\n" + ")\n" + "DUPLICATE KEY (pk)\n" + "DISTRIBUTED BY HASH (pk)\n" @@ -60,9 +63,9 @@ public class HavingClauseTest extends AnalyzeCheckTestBase implements PatternMat + " 'replication_num' = '1'\n" + ");", "CREATE TABLE t2 (\n" - + " pk INT,\n" - + " b1 INT,\n" - + " b2 INT\n" + + " pk TINYINT,\n" + + " b1 TINYINT,\n" + + " b2 TINYINT\n" + ")\n" + "DUPLICATE KEY (pk)\n" + "DISTRIBUTED BY HASH (pk)\n" @@ -81,7 +84,7 @@ public class HavingClauseTest extends AnalyzeCheckTestBase implements PatternMat public void testHavingGroupBySlot() throws Exception { String sql = "SELECT a1 FROM t1 GROUP BY a1 HAVING a1 > 0"; SlotReference a1 = new SlotReference( - new ExprId(1), "a1", IntegerType.INSTANCE, true, + new ExprId(1), "a1", TinyIntType.INSTANCE, true, ImmutableList.of("default_cluster:test_having", "t1") ); PlanChecker.from(connectContext).analyze(sql) @@ -90,52 +93,55 @@ public class HavingClauseTest extends AnalyzeCheckTestBase implements PatternMat logicalAggregate( logicalOlapScan() ).when(FieldChecker.check("outputExpressions", Lists.newArrayList(a1))) - ).when(FieldChecker.check("predicates", new GreaterThan(a1, new IntegerLiteral(0))))); + ).when(FieldChecker.check("predicates", new GreaterThan(a1, new TinyIntLiteral((byte) 0))))); NamedExpressionUtil.clear(); sql = "SELECT a1 as value FROM t1 GROUP BY a1 HAVING a1 > 0"; a1 = new SlotReference( - new ExprId(2), "a1", IntegerType.INSTANCE, true, + new ExprId(2), "a1", TinyIntType.INSTANCE, true, ImmutableList.of("default_cluster:test_having", "t1") ); Alias value = new Alias(new ExprId(0), a1, "value"); PlanChecker.from(connectContext).analyze(sql) + .applyBottomUp(new ExpressionRewrite(TypeCoercion.INSTANCE)) .matchesFromRoot( logicalFilter( logicalAggregate( logicalOlapScan() ).when(FieldChecker.check("outputExpressions", Lists.newArrayList(value))) - ).when(FieldChecker.check("predicates", new GreaterThan(value.toSlot(), new IntegerLiteral(0))))); + ).when(FieldChecker.check("predicates", new GreaterThan(value.toSlot(), new TinyIntLiteral((byte) 0))))); NamedExpressionUtil.clear(); sql = "SELECT a1 as value FROM t1 GROUP BY a1 HAVING value > 0"; PlanChecker.from(connectContext).analyze(sql) + .applyBottomUp(new ExpressionRewrite(TypeCoercion.INSTANCE)) .matchesFromRoot( logicalFilter( logicalAggregate( logicalOlapScan() ).when(FieldChecker.check("outputExpressions", Lists.newArrayList(value))) - ).when(FieldChecker.check("predicates", new GreaterThan(value.toSlot(), new IntegerLiteral(0))))); + ).when(FieldChecker.check("predicates", new GreaterThan(value.toSlot(), new TinyIntLiteral((byte) 0))))); NamedExpressionUtil.clear(); sql = "SELECT SUM(a2) FROM t1 GROUP BY a1 HAVING a1 > 0"; a1 = new SlotReference( - new ExprId(1), "a1", IntegerType.INSTANCE, true, + new ExprId(1), "a1", TinyIntType.INSTANCE, true, ImmutableList.of("default_cluster:test_having", "t1") ); SlotReference a2 = new SlotReference( - new ExprId(2), "a2", IntegerType.INSTANCE, true, + new ExprId(2), "a2", TinyIntType.INSTANCE, true, ImmutableList.of("default_cluster:test_having", "t1") ); Alias sumA2 = new Alias(new ExprId(3), new Sum(a2), "SUM(a2)"); PlanChecker.from(connectContext).analyze(sql) + .applyBottomUp(new ExpressionRewrite(TypeCoercion.INSTANCE)) .matchesFromRoot( logicalProject( logicalFilter( logicalAggregate( logicalOlapScan() ).when(FieldChecker.check("outputExpressions", Lists.newArrayList(sumA2, a1))) - ).when(FieldChecker.check("predicates", new GreaterThan(a1, new IntegerLiteral(0)))) + ).when(FieldChecker.check("predicates", new GreaterThan(a1, new TinyIntLiteral((byte) 0)))) ).when(FieldChecker.check("projects", Lists.newArrayList(sumA2.toSlot())))); NamedExpressionUtil.clear(); } @@ -144,11 +150,11 @@ public class HavingClauseTest extends AnalyzeCheckTestBase implements PatternMat public void testHavingAggregateFunction() throws Exception { String sql = "SELECT a1 FROM t1 GROUP BY a1 HAVING SUM(a2) > 0"; SlotReference a1 = new SlotReference( - new ExprId(1), "a1", IntegerType.INSTANCE, true, + new ExprId(1), "a1", TinyIntType.INSTANCE, true, ImmutableList.of("default_cluster:test_having", "t1") ); SlotReference a2 = new SlotReference( - new ExprId(2), "a2", IntegerType.INSTANCE, true, + new ExprId(2), "a2", TinyIntType.INSTANCE, true, ImmutableList.of("default_cluster:test_having", "t1") ); Alias sumA2 = new Alias(new ExprId(3), new Sum(a2), "sum(a2)"); @@ -159,7 +165,7 @@ public class HavingClauseTest extends AnalyzeCheckTestBase implements PatternMat logicalAggregate( logicalOlapScan() ).when(FieldChecker.check("outputExpressions", Lists.newArrayList(a1, sumA2))) - ).when(FieldChecker.check("predicates", new GreaterThan(sumA2.toSlot(), new IntegerLiteral(0)))) + ).when(FieldChecker.check("predicates", new GreaterThan(sumA2.toSlot(), new TinyIntLiteral((byte) 0)))) ).when(FieldChecker.check("projects", Lists.newArrayList(a1.toSlot())))); NamedExpressionUtil.clear(); @@ -171,16 +177,16 @@ public class HavingClauseTest extends AnalyzeCheckTestBase implements PatternMat logicalAggregate( logicalOlapScan() ).when(FieldChecker.check("outputExpressions", Lists.newArrayList(a1, sumA2))) - ).when(FieldChecker.check("predicates", new GreaterThan(sumA2.toSlot(), new IntegerLiteral(0))))); + ).when(FieldChecker.check("predicates", new GreaterThan(sumA2.toSlot(), new TinyIntLiteral((byte) 0))))); NamedExpressionUtil.clear(); sql = "SELECT a1, SUM(a2) as value FROM t1 GROUP BY a1 HAVING SUM(a2) > 0"; a1 = new SlotReference( - new ExprId(2), "a1", IntegerType.INSTANCE, true, + new ExprId(2), "a1", TinyIntType.INSTANCE, true, ImmutableList.of("default_cluster:test_having", "t1") ); a2 = new SlotReference( - new ExprId(3), "a2", IntegerType.INSTANCE, true, + new ExprId(3), "a2", TinyIntType.INSTANCE, true, ImmutableList.of("default_cluster:test_having", "t1") ); Alias value = new Alias(new ExprId(0), new Sum(a2), "value"); @@ -190,7 +196,7 @@ public class HavingClauseTest extends AnalyzeCheckTestBase implements PatternMat logicalAggregate( logicalOlapScan() ).when(FieldChecker.check("outputExpressions", Lists.newArrayList(a1, value))) - ).when(FieldChecker.check("predicates", new GreaterThan(value.toSlot(), new IntegerLiteral(0))))); + ).when(FieldChecker.check("predicates", new GreaterThan(value.toSlot(), new TinyIntLiteral((byte) 0))))); NamedExpressionUtil.clear(); sql = "SELECT a1, SUM(a2) as value FROM t1 GROUP BY a1 HAVING value > 0"; @@ -200,21 +206,21 @@ public class HavingClauseTest extends AnalyzeCheckTestBase implements PatternMat logicalAggregate( logicalOlapScan() ).when(FieldChecker.check("outputExpressions", Lists.newArrayList(a1, value))) - ).when(FieldChecker.check("predicates", new GreaterThan(value.toSlot(), new IntegerLiteral(0))))); + ).when(FieldChecker.check("predicates", new GreaterThan(value.toSlot(), new TinyIntLiteral((byte) 0))))); NamedExpressionUtil.clear(); sql = "SELECT a1, SUM(a2) FROM t1 GROUP BY a1 HAVING MIN(pk) > 0"; a1 = new SlotReference( - new ExprId(1), "a1", IntegerType.INSTANCE, true, + new ExprId(1), "a1", TinyIntType.INSTANCE, true, ImmutableList.of("default_cluster:test_having", "t1") ); a2 = new SlotReference( - new ExprId(2), "a2", IntegerType.INSTANCE, true, + new ExprId(2), "a2", TinyIntType.INSTANCE, true, ImmutableList.of("default_cluster:test_having", "t1") ); sumA2 = new Alias(new ExprId(3), new Sum(a2), "SUM(a2)"); SlotReference pk = new SlotReference( - new ExprId(0), "pk", IntegerType.INSTANCE, true, + new ExprId(0), "pk", TinyIntType.INSTANCE, true, ImmutableList.of("default_cluster:test_having", "t1") ); Alias minPK = new Alias(new ExprId(4), new Min(pk), "min(pk)"); @@ -225,7 +231,7 @@ public class HavingClauseTest extends AnalyzeCheckTestBase implements PatternMat logicalAggregate( logicalOlapScan() ).when(FieldChecker.check("outputExpressions", Lists.newArrayList(a1, sumA2, minPK))) - ).when(FieldChecker.check("predicates", new GreaterThan(minPK.toSlot(), new IntegerLiteral(0)))) + ).when(FieldChecker.check("predicates", new GreaterThan(minPK.toSlot(), new TinyIntLiteral((byte) 0)))) ).when(FieldChecker.check("projects", Lists.newArrayList(a1.toSlot(), sumA2.toSlot())))); NamedExpressionUtil.clear(); @@ -237,11 +243,11 @@ public class HavingClauseTest extends AnalyzeCheckTestBase implements PatternMat logicalAggregate( logicalOlapScan() ).when(FieldChecker.check("outputExpressions", Lists.newArrayList(a1, sumA1A2))) - ).when(FieldChecker.check("predicates", new GreaterThan(sumA1A2.toSlot(), new IntegerLiteral(0))))); + ).when(FieldChecker.check("predicates", new GreaterThan(sumA1A2.toSlot(), new TinyIntLiteral((byte) 0))))); NamedExpressionUtil.clear(); sql = "SELECT a1, SUM(a1 + a2) FROM t1 GROUP BY a1 HAVING SUM(a1 + a2 + 3) > 0"; - Alias sumA1A23 = new Alias(new ExprId(4), new Sum(new Add(new Add(a1, a2), new IntegerLiteral(3))), + Alias sumA1A23 = new Alias(new ExprId(4), new Sum(new Add(new Add(a1, a2), new TinyIntLiteral((byte) 3))), "sum(((a1 + a2) + 3))"); PlanChecker.from(connectContext).analyze(sql) .matchesFromRoot( @@ -250,7 +256,7 @@ public class HavingClauseTest extends AnalyzeCheckTestBase implements PatternMat logicalAggregate( logicalOlapScan() ).when(FieldChecker.check("outputExpressions", Lists.newArrayList(a1, sumA1A2, sumA1A23))) - ).when(FieldChecker.check("predicates", new GreaterThan(sumA1A23.toSlot(), new IntegerLiteral(0)))) + ).when(FieldChecker.check("predicates", new GreaterThan(sumA1A23.toSlot(), new TinyIntLiteral((byte) 0)))) ).when(FieldChecker.check("projects", Lists.newArrayList(a1.toSlot(), sumA1A2.toSlot())))); NamedExpressionUtil.clear(); @@ -263,7 +269,7 @@ public class HavingClauseTest extends AnalyzeCheckTestBase implements PatternMat logicalAggregate( logicalOlapScan() ).when(FieldChecker.check("outputExpressions", Lists.newArrayList(a1, countStar))) - ).when(FieldChecker.check("predicates", new GreaterThan(countStar.toSlot(), new IntegerLiteral(0)))) + ).when(FieldChecker.check("predicates", new GreaterThan(countStar.toSlot(), new TinyIntLiteral((byte) 0)))) ).when(FieldChecker.check("projects", Lists.newArrayList(a1.toSlot())))); NamedExpressionUtil.clear(); } @@ -272,15 +278,15 @@ public class HavingClauseTest extends AnalyzeCheckTestBase implements PatternMat void testJoin() throws Exception { String sql = "SELECT a1, sum(a2) FROM t1, t2 WHERE t1.pk = t2.pk GROUP BY a1 HAVING a1 > SUM(b1)"; SlotReference a1 = new SlotReference( - new ExprId(1), "a1", IntegerType.INSTANCE, true, + new ExprId(1), "a1", TinyIntType.INSTANCE, true, ImmutableList.of("default_cluster:test_having", "t1") ); SlotReference a2 = new SlotReference( - new ExprId(2), "a2", IntegerType.INSTANCE, true, + new ExprId(2), "a2", TinyIntType.INSTANCE, true, ImmutableList.of("default_cluster:test_having", "t1") ); SlotReference b1 = new SlotReference( - new ExprId(4), "b1", IntegerType.INSTANCE, true, + new ExprId(4), "b1", TinyIntType.INSTANCE, true, ImmutableList.of("default_cluster:test_having", "t2") ); Alias sumA2 = new Alias(new ExprId(6), new Sum(a2), "sum(a2)"); @@ -332,22 +338,22 @@ public class HavingClauseTest extends AnalyzeCheckTestBase implements PatternMat + "FROM t1, t2 WHERE t1.pk = t2.pk GROUP BY t1.pk, t1.pk + 1\n" + "HAVING t1.pk > 0 AND COUNT(a1) + 1 > 0 AND SUM(a1 + a2) + 1 > 0 AND v1 + 1 > 0 AND v1 > 0"; SlotReference pk = new SlotReference( - new ExprId(1), "pk", IntegerType.INSTANCE, true, + new ExprId(1), "pk", TinyIntType.INSTANCE, true, ImmutableList.of("default_cluster:test_having", "t1") ); SlotReference a1 = new SlotReference( - new ExprId(2), "a1", IntegerType.INSTANCE, true, + new ExprId(2), "a1", TinyIntType.INSTANCE, true, ImmutableList.of("default_cluster:test_having", "t1") ); SlotReference a2 = new SlotReference( - new ExprId(3), "a1", IntegerType.INSTANCE, true, + new ExprId(3), "a1", TinyIntType.INSTANCE, true, ImmutableList.of("default_cluster:test_having", "t1") ); - Alias pk1 = new Alias(new ExprId(7), new Add(pk, IntegerLiteral.of(1)), "(pk + 1)"); - Alias pk11 = new Alias(new ExprId(8), new Add(new Add(pk, IntegerLiteral.of(1)), IntegerLiteral.of(1)), "((pk + 1) + 1)"); - Alias pk2 = new Alias(new ExprId(9), new Add(pk, IntegerLiteral.of(2)), "(pk + 2)"); + Alias pk1 = new Alias(new ExprId(7), new Add(pk, Literal.of((byte) 1)), "(pk + 1)"); + Alias pk11 = new Alias(new ExprId(8), new Add(new Add(pk, Literal.of((byte) 1)), Literal.of((byte) 1)), "((pk + 1) + 1)"); + Alias pk2 = new Alias(new ExprId(9), new Add(pk, Literal.of((byte) 2)), "(pk + 2)"); Alias sumA1 = new Alias(new ExprId(10), new Sum(a1), "SUM(a1)"); - Alias countA11 = new Alias(new ExprId(11), new Add(new Count(a1), IntegerLiteral.of(1)), "(COUNT(a1) + 1)"); + Alias countA11 = new Alias(new ExprId(11), new Add(new Count(a1), Literal.of((byte) 1)), "(COUNT(a1) + 1)"); Alias sumA1A2 = new Alias(new ExprId(12), new Sum(new Add(a1, a2)), "SUM((a1 + a2))"); Alias v1 = new Alias(new ExprId(0), new Count(a2), "v1"); PlanChecker.from(connectContext).analyze(sql) @@ -368,12 +374,12 @@ public class HavingClauseTest extends AnalyzeCheckTestBase implements PatternMat new And( new And( new And( - new GreaterThan(pk.toSlot(), IntegerLiteral.of(0)), - new GreaterThan(countA11.toSlot(), IntegerLiteral.of(0))), - new GreaterThan(new Add(sumA1A2.toSlot(), IntegerLiteral.of(1)), IntegerLiteral.of(0))), - new GreaterThan(new Add(v1.toSlot(), IntegerLiteral.of(1)), IntegerLiteral.of(0)) + new GreaterThan(pk.toSlot(), Literal.of((byte) 0)), + new GreaterThan(countA11.toSlot(), Literal.of((byte) 0))), + new GreaterThan(new Add(sumA1A2.toSlot(), Literal.of((byte) 1)), Literal.of((byte) 0))), + new GreaterThan(new Add(v1.toSlot(), Literal.of((byte) 1)), Literal.of((byte) 0)) ), - new GreaterThan(v1.toSlot(), IntegerLiteral.of(0)) + new GreaterThan(v1.toSlot(), Literal.of((byte) 0)) ) )) ).when(FieldChecker.check( diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rewrite/ExpressionRewriteTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rewrite/ExpressionRewriteTest.java index 80b70f56ca..2798e05a5b 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rewrite/ExpressionRewriteTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/expression/rewrite/ExpressionRewriteTest.java @@ -176,13 +176,13 @@ public class ExpressionRewriteTest { executor = new ExpressionRuleExecutor(ImmutableList.of(SimplifyCastRule.INSTANCE)); // deduplicate - assertRewrite("CAST(1 AS int)", "1"); - assertRewrite("CAST('str' AS string)", "'str'"); - assertRewrite("CAST(CAST(1 AS int) AS int)", "1"); + assertRewrite("CAST(1 AS tinyint)", "1"); + assertRewrite("CAST('str' AS varchar)", "'str'"); + assertRewrite("CAST(CAST(1 AS tinyint) AS tinyint)", "1"); // deduplicate inside - assertRewrite("CAST(CAST('str' AS string) AS double)", "CAST('str' AS double)"); - assertRewrite("CAST(CAST(1 AS int) AS double)", "CAST(1 AS double)"); + assertRewrite("CAST(CAST('str' AS varchar) AS double)", "CAST('str' AS double)"); + assertRewrite("CAST(CAST(1 AS tinyint) AS double)", "CAST(1 AS double)"); } private void assertRewrite(String expression, String expected) { diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/FieldChecker.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/FieldChecker.java index 01fcc38bd9..f9adf43ed2 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/FieldChecker.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/FieldChecker.java @@ -28,14 +28,14 @@ public class FieldChecker { Field field; try { field = o.getClass().getDeclaredField(fieldName); - } catch (NoSuchFieldException e) { - throw new RuntimeException(e); + } catch (Throwable e) { + throw new RuntimeException("Check " + fieldName + " failed", e); } field.setAccessible(true); try { Assertions.assertEquals(value, field.get(o)); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); + } catch (Throwable e) { + throw new RuntimeException("Check " + fieldName + " failed", e); } return true; }; diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/MemoTestUtils.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/MemoTestUtils.java index 4a2542ba17..faa9bdc10d 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/util/MemoTestUtils.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/util/MemoTestUtils.java @@ -21,9 +21,6 @@ import org.apache.doris.analysis.UserIdentity; import org.apache.doris.catalog.Env; import org.apache.doris.nereids.CascadesContext; import org.apache.doris.nereids.StatementContext; -import org.apache.doris.nereids.memo.Group; -import org.apache.doris.nereids.memo.GroupExpression; -import org.apache.doris.nereids.memo.Memo; import org.apache.doris.nereids.parser.NereidsParser; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalPlan; @@ -114,47 +111,6 @@ public class MemoTestUtils { } } - public static String printGroupTree(Memo memo) { - Group root = memo.getRoot(); - StringBuilder builder = new StringBuilder(); - printGroup(root, 0, true, builder); - return builder.toString(); - } - - private static void printGroup(Group group, int depth, boolean isLastGroup, StringBuilder builder) { - if (!group.getLogicalExpressions().isEmpty()) { - builder.append(getIdentStr(depth + 1)) - .append(group.getPhysicalExpressions().isEmpty() ? "+--" : "|--") - .append("logicalExpressions:\n"); - for (int i = 0; i < group.getLogicalExpressions().size(); i++) { - GroupExpression logicalExpression = group.getLogicalExpressions().get(i); - boolean isLastExpression = i + 1 == group.getLogicalExpressions().size(); - printGroupExpression(logicalExpression, depth + 2, isLastExpression, builder); - } - } - - if (!group.getPhysicalExpressions().isEmpty()) { - builder.append(getIdentStr(depth + 1)).append("+-- physicalExpressions:\n"); - for (int i = 0; i < group.getPhysicalExpressions().size(); i++) { - GroupExpression logicalExpression = group.getPhysicalExpressions().get(i); - boolean isLastExpression = i + 1 == group.getPhysicalExpressions().size(); - printGroupExpression(logicalExpression, depth + 2, isLastExpression, builder); - } - } - } - - private static void printGroupExpression(GroupExpression groupExpression, int indent, - boolean isLastExpression, StringBuilder builder) { - builder.append(getIdentStr(indent)) - .append(isLastExpression ? "+--" : "|--") - .append(groupExpression.getPlan().toString()).append("\n"); - for (int i = 0; i < groupExpression.children().size(); i++) { - Group childGroup = groupExpression.children().get(i); - boolean isLastGroup = i + 1 == groupExpression.children().size(); - printGroup(childGroup, indent + 1, isLastGroup, builder); - } - } - private static String getIdentStr(int indent) { return StringUtils.repeat(" ", indent); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java b/regression-test/suites/nereids_syntax_p0/empty_relation.groovy similarity index 62% copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java copy to regression-test/suites/nereids_syntax_p0/empty_relation.groovy index f0c536cf83..05e1af14ee 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java +++ b/regression-test/suites/nereids_syntax_p0/empty_relation.groovy @@ -15,24 +15,18 @@ // specific language governing permissions and limitations // under the License. -package org.apache.doris.nereids.trees.plans.algebra; +suite("empty_relation") { + // enable nereids and vectorized engine + sql "SET enable_vectorized_engine=true" + sql "SET enable_nereids_planner=true" -import org.apache.doris.catalog.Table; -import org.apache.doris.nereids.trees.expressions.Expression; -import org.apache.doris.nereids.trees.expressions.Slot; - -import java.util.Collections; -import java.util.List; - -/** - * Common interface for logical/physical scan. - */ -public interface Scan { - List<Expression> getExpressions(); - - Table getTable(); + test { + sql "select *, substring(s_name, 1, 2) from supplier limit 0" + result([]) + } - default List<Slot> getOutput() { - return Collections.emptyList(); + explain { + sql "select *, substring(s_name, 1, 2) from supplier limit 0" + contains ":VEMPTYSET" } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java b/regression-test/suites/nereids_syntax_p0/one_row_relation.groovy similarity index 62% copy from fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java copy to regression-test/suites/nereids_syntax_p0/one_row_relation.groovy index f0c536cf83..9a73edf1bb 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/algebra/Scan.java +++ b/regression-test/suites/nereids_syntax_p0/one_row_relation.groovy @@ -15,24 +15,13 @@ // specific language governing permissions and limitations // under the License. -package org.apache.doris.nereids.trees.plans.algebra; +suite("one_row_relation") { + // enable nereids and vectorized engine + sql "SET enable_vectorized_engine=true" + sql "SET enable_nereids_planner=true" -import org.apache.doris.catalog.Table; -import org.apache.doris.nereids.trees.expressions.Expression; -import org.apache.doris.nereids.trees.expressions.Slot; - -import java.util.Collections; -import java.util.List; - -/** - * Common interface for logical/physical scan. - */ -public interface Scan { - List<Expression> getExpressions(); - - Table getTable(); - - default List<Slot> getOutput() { - return Collections.emptyList(); + test { + sql "select 100, 'abc', substring('abc', 1, 2), substring(substring('abcdefg', 4, 3), 1, 2)" + result([[100, "abc", "ab", "de"]]) } } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org