This is an automated email from the ASF dual-hosted git repository. caogaofei pushed a commit to branch ty/TableModelGrammar in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 34bf1aa11bb08c976c62f4104a888712e61e2076 Author: Beyyes <[email protected]> AuthorDate: Mon Apr 15 20:13:56 2024 +0800 add optimizer RemoveRedundantIdentityProjections --- .../plan/planner/plan/node/PlanNode.java | 6 + .../plan/planner/plan/node/PlanVisitor.java | 5 + .../plan/relational/planner/Assignments.java | 5 +- .../plan/relational/planner/LogicalPlanner.java | 7 +- .../plan/relational/planner/PlanBuilder.java | 6 +- .../plan/relational/planner/QueryPlanner.java | 37 ++-- .../plan/relational/planner/RelationPlan.java | 6 +- .../plan/relational/planner/RelationPlanner.java | 188 +++++++-------------- .../plan/relational/planner/node/FilterNode.java | 8 +- .../plan/relational/planner/node/LimitNode.java | 10 +- .../plan/relational/planner/node/OffsetNode.java | 8 +- .../plan/relational/planner/node/OutputNode.java | 20 ++- .../plan/relational/planner/node/ProjectNode.java | 14 +- .../plan/relational/planner/node/SortNode.java | 12 +- .../relational/planner/node/TableScanNode.java | 5 + ...ava => RemoveRedundantIdentityProjections.java} | 60 ++++--- .../planner/optimizations/SimplifyExpressions.java | 4 - .../plan/relational/analyzer/AnalyzerTest.java | 3 +- 18 files changed, 207 insertions(+), 197 deletions(-) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanNode.java index 877db9bf543..b8a9ebf66f6 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanNode.java @@ -22,6 +22,7 @@ package org.apache.iotdb.db.queryengine.plan.planner.plan.node; import org.apache.iotdb.commons.exception.runtime.SerializationRunTimeException; import org.apache.iotdb.consensus.common.request.IConsensusRequest; import org.apache.iotdb.db.queryengine.plan.analyze.TypeProvider; +import org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol; import org.apache.iotdb.tsfile.utils.PublicBAOS; import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils; @@ -206,4 +207,9 @@ public abstract class PlanNode implements IConsensusRequest { public int hashCode() { return Objects.hash(id); } + + // =========================== Used for Relational Model ============================ + public List<Symbol> getOutputSymbols() { + throw new UnsupportedOperationException("This planNode does not support getOutputSymbols()."); + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanVisitor.java index 9e893bbc653..393f46a43ba 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanVisitor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanVisitor.java @@ -518,4 +518,9 @@ public abstract class PlanVisitor<R, C> { public R visitTableScan(TableScanNode node, C context) { return visitPlan(node, context); } + + public R visitProject( + org.apache.iotdb.db.queryengine.plan.relational.planner.node.ProjectNode node, C context) { + return visitPlan(node, context); + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/Assignments.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/Assignments.java index 992ada2a745..a439f41f00b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/Assignments.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/Assignments.java @@ -37,6 +37,9 @@ import static java.util.Arrays.asList; import static java.util.Objects.requireNonNull; public class Assignments { + + private final Map<Symbol, Expression> assignments; + public static Builder builder() { return new Builder(); } @@ -66,8 +69,6 @@ public class Assignments { return builder().put(symbol1, expression1).put(symbol2, expression2).build(); } - private final Map<Symbol, Expression> assignments; - @JsonCreator public Assignments(@JsonProperty("assignments") Map<Symbol, Expression> assignments) { this.assignments = ImmutableMap.copyOf(requireNonNull(assignments, "assignments is null")); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/LogicalPlanner.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/LogicalPlanner.java index f11c0d86f98..5e54848763f 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/LogicalPlanner.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/LogicalPlanner.java @@ -25,6 +25,7 @@ import org.apache.iotdb.db.queryengine.plan.relational.analyzer.RelationType; import org.apache.iotdb.db.queryengine.plan.relational.metadata.Metadata; import org.apache.iotdb.db.queryengine.plan.relational.planner.node.OutputNode; import org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.RelationalPlanOptimizer; +import org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.RemoveRedundantIdentityProjections; import org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations.SimplifyExpressions; import org.apache.iotdb.db.relational.sql.tree.Query; import org.apache.iotdb.db.relational.sql.tree.Statement; @@ -34,7 +35,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import io.airlift.log.Logger; -import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import static java.util.Objects.requireNonNull; @@ -58,8 +59,8 @@ public class LogicalPlanner { this.sessionInfo = requireNonNull(sessionInfo, "session is null"); this.warningCollector = requireNonNull(warningCollector, "warningCollector is null"); - this.relationalPlanOptimizers = new ArrayList<>(); - this.relationalPlanOptimizers.add(new SimplifyExpressions()); + this.relationalPlanOptimizers = + Arrays.asList(new SimplifyExpressions(), new RemoveRedundantIdentityProjections()); } public LogicalQueryPlan plan(Analysis analysis) throws IoTDBException { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanBuilder.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanBuilder.java index 2045233cb37..a34e17dbf85 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanBuilder.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/PlanBuilder.java @@ -29,7 +29,8 @@ import java.util.Map; import static java.util.Objects.requireNonNull; -class PlanBuilder { +public class PlanBuilder { + private final PlanNode root; public PlanBuilder(PlanNode root) { @@ -68,8 +69,7 @@ class PlanBuilder { Assignments.Builder projections = Assignments.builder(); // add an identity projection for underlying plan - // TODO needed? - // projections.putIdentities(root.getOutputSymbols()); + projections.putIdentities(root.getOutputSymbols()); Map<ScopeAware<Expression>, Symbol> mappings = new HashMap<>(); // for (T expression : expressions) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/QueryPlanner.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/QueryPlanner.java index eb23a4a2cbf..768cd3ca4b5 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/QueryPlanner.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/QueryPlanner.java @@ -28,6 +28,7 @@ import org.apache.iotdb.db.relational.sql.tree.Node; import org.apache.iotdb.db.relational.sql.tree.Offset; import org.apache.iotdb.db.relational.sql.tree.OrderBy; import org.apache.iotdb.db.relational.sql.tree.Query; +import org.apache.iotdb.db.relational.sql.tree.QueryBody; import org.apache.iotdb.db.relational.sql.tree.QuerySpecification; import org.apache.iotdb.db.relational.sql.tree.SortItem; import org.apache.iotdb.tsfile.read.common.type.Type; @@ -47,18 +48,17 @@ import static java.util.Objects.requireNonNull; import static org.apache.iotdb.db.queryengine.plan.relational.planner.OrderingTranslator.sortItemToSortOrder; import static org.apache.iotdb.db.queryengine.plan.relational.planner.PlanBuilder.newPlanBuilder; -class QueryPlanner { - private static final int MAX_BIGINT_PRECISION = 19; +public class QueryPlanner { private final Analysis analysis; private final SymbolAllocator symbolAllocator; private final QueryId idAllocator; - // private final Map<NodeRef<LambdaArgumentDeclaration>, Symbol> lambdaDeclarationToSymbolMap; - // private final PlannerContext plannerContext; private final SessionInfo session; - // private final SubqueryPlanner subqueryPlanner; private final Map<NodeRef<Node>, RelationPlan> recursiveSubqueries; - QueryPlanner( + // private final Map<NodeRef<LambdaArgumentDeclaration>, Symbol> lambdaDeclarationToSymbolMap; + // private final SubqueryPlanner subqueryPlanner; + + public QueryPlanner( Analysis analysis, SymbolAllocator symbolAllocator, QueryId idAllocator, @@ -74,12 +74,11 @@ class QueryPlanner { this.symbolAllocator = symbolAllocator; this.idAllocator = idAllocator; this.session = session; - // this.subqueryPlanner = null; this.recursiveSubqueries = recursiveSubqueries; } public RelationPlan plan(Query query) { - PlanBuilder builder = planQueryBody(query); + PlanBuilder builder = planQueryBody(query.getQueryBody()); List<Expression> orderBy = analysis.getOrderByExpressions(query); // builder = subqueryPlanner.handleSubqueries(builder, orderBy, analysis.getSubqueries(query)); @@ -108,20 +107,16 @@ class QueryPlanner { PlanBuilder builder = planFrom(node); builder = filter(builder, analysis.getWhere(node), node); - // builder = aggregate(builder, node); - builder = filter(builder, analysis.getHaving(node), node); - // builder = planWindowFunctions(node, builder, - // ImmutableList.copyOf(analysis.getWindowFunctions(node))); - // builder = planWindowMeasures(node, builder, - // ImmutableList.copyOf(analysis.getWindowMeasures(node))); + + // TODO prcess aggregate, having later List<Analysis.SelectExpression> selectExpressions = analysis.getSelectExpressions(node); List<Expression> expressions = selectExpressions.stream() .map(Analysis.SelectExpression::getExpression) .collect(toImmutableList()); - // builder = subqueryPlanner.handleSubqueries(builder, expressions, - // analysis.getSubqueries(node)); + + // TODO process subQuery later if (hasExpressionsToUnfold(selectExpressions)) { // pre-project the folded expressions to preserve any non-deterministic semantics of functions @@ -160,10 +155,12 @@ class QueryPlanner { } List<Expression> orderBy = analysis.getOrderByExpressions(node); + // TODO this appendProjections may be removed builder = builder.appendProjections(Iterables.concat(orderBy, outputs), symbolAllocator, idAllocator); - // builder = distinct(builder, node, outputs); + // TODO handle distinct + Optional<OrderingScheme> orderingScheme = orderingScheme(builder, node.getOrderBy(), analysis.getOrderByExpressions(node)); builder = sort(builder, orderingScheme); @@ -208,10 +205,10 @@ class QueryPlanner { return outputSymbols.build(); } - private PlanBuilder planQueryBody(Query query) { + private PlanBuilder planQueryBody(QueryBody queryBody) { RelationPlan relationPlan = new RelationPlanner(analysis, symbolAllocator, idAllocator, session, recursiveSubqueries) - .process(query.getQueryBody(), null); + .process(queryBody, null); return newPlanBuilder(relationPlan, analysis, session); } @@ -223,7 +220,7 @@ class QueryPlanner { .process(node.getFrom().get(), null); return newPlanBuilder(relationPlan, analysis, session); } else { - throw new RuntimeException("From clause must not by empty"); + throw new IllegalStateException("From clause must not by empty"); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationPlan.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationPlan.java index 5ece186d194..cdd1bab217f 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationPlan.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationPlan.java @@ -29,15 +29,15 @@ import static java.util.Objects.requireNonNull; * values, etc.), and the mapping to indicate how the fields (by position) in the relation map to * the outputs of the plan. */ -class RelationPlan { +public class RelationPlan { private final PlanNode root; + private final Scope scope; + // for each field in the relation, the corresponding symbol from "root" private final List<Symbol> fieldMappings; - private final Scope scope; - public RelationPlan(PlanNode root, Scope scope, List<Symbol> fieldMappings) { requireNonNull(root, "root is null"); requireNonNull(fieldMappings, "fieldMappings is null"); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationPlanner.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationPlanner.java index 9e180d3dc4c..b42cc50c693 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationPlanner.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/RelationPlanner.java @@ -25,11 +25,17 @@ import org.apache.iotdb.db.queryengine.plan.relational.metadata.TableHandle; import org.apache.iotdb.db.queryengine.plan.relational.planner.node.TableScanNode; import org.apache.iotdb.db.relational.sql.tree.AliasedRelation; import org.apache.iotdb.db.relational.sql.tree.AstVisitor; +import org.apache.iotdb.db.relational.sql.tree.Except; +import org.apache.iotdb.db.relational.sql.tree.Intersect; +import org.apache.iotdb.db.relational.sql.tree.Join; import org.apache.iotdb.db.relational.sql.tree.Node; import org.apache.iotdb.db.relational.sql.tree.Query; import org.apache.iotdb.db.relational.sql.tree.QuerySpecification; import org.apache.iotdb.db.relational.sql.tree.SubqueryExpression; import org.apache.iotdb.db.relational.sql.tree.Table; +import org.apache.iotdb.db.relational.sql.tree.TableSubquery; +import org.apache.iotdb.db.relational.sql.tree.Union; +import org.apache.iotdb.db.relational.sql.tree.Values; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -40,14 +46,14 @@ import java.util.Map; import static java.util.Objects.requireNonNull; -class RelationPlanner extends AstVisitor<RelationPlan, Void> { +public class RelationPlanner extends AstVisitor<RelationPlan, Void> { private final Analysis analysis; private final SymbolAllocator symbolAllocator; private final QueryId idAllocator; private final SessionInfo session; private final Map<NodeRef<Node>, RelationPlan> recursiveSubqueries; - RelationPlanner( + public RelationPlanner( Analysis analysis, SymbolAllocator symbolAllocator, QueryId idAllocator, @@ -67,8 +73,9 @@ class RelationPlanner extends AstVisitor<RelationPlan, Void> { } @Override - protected RelationPlan visitNode(Node node, Void context) { - throw new IllegalStateException("Unsupported node type: " + node.getClass().getName()); + protected RelationPlan visitQuery(Query node, Void context) { + return new QueryPlanner(analysis, symbolAllocator, idAllocator, session, recursiveSubqueries) + .plan(node); } @Override @@ -83,154 +90,81 @@ class RelationPlanner extends AstVisitor<RelationPlan, Void> { expansion.getRoot(), expansion.getScope(), expansion.getFieldMappings()); } - Query namedQuery = analysis.getNamedQuery(node); Scope scope = analysis.getScope(node); + TableHandle tableHandle = analysis.getTableHandle(node); - RelationPlan plan; - if (namedQuery != null) { - throw new RuntimeException("NamedQuery is not supported"); - } else { - TableHandle handle = analysis.getTableHandle(node); + ImmutableList.Builder<Symbol> outputSymbolsBuilder = ImmutableList.builder(); + ImmutableMap.Builder<Symbol, ColumnHandle> columnsBuilder = ImmutableMap.builder(); - ImmutableList.Builder<Symbol> outputSymbolsBuilder = ImmutableList.builder(); - ImmutableMap.Builder<Symbol, ColumnHandle> columns = ImmutableMap.builder(); - - // Collection<Field> fields = analysis.getMaterializedViewStorageTableFields(node); - Collection<Field> fields = scope.getRelationType().getAllFields(); - for (Field field : fields) { - Symbol symbol = symbolAllocator.newSymbol(field); + Collection<Field> fields = scope.getRelationType().getAllFields(); + for (Field field : fields) { + Symbol symbol = symbolAllocator.newSymbol(field); + outputSymbolsBuilder.add(symbol); + columnsBuilder.put(symbol, analysis.getColumn(field)); + } - outputSymbolsBuilder.add(symbol); - columns.put(symbol, analysis.getColumn(field)); - } + List<Symbol> outputSymbols = outputSymbolsBuilder.build(); + PlanNode root = + new TableScanNode( + idAllocator.genPlanNodeId(), tableHandle, outputSymbols, columnsBuilder.buildOrThrow()); - List<Symbol> outputSymbols = outputSymbolsBuilder.build(); - PlanNode root = - new TableScanNode( - idAllocator.genPlanNodeId(), handle, outputSymbols, columns.buildOrThrow()); + return new RelationPlan(root, scope, outputSymbols); - plan = new RelationPlan(root, scope, outputSymbols); - } - - // TODO what's the meaning of RowFilters addColumnMasks? + // Query namedQuery = analysis.getNamedQuery(node); + // Collection<Field> fields = analysis.getMaterializedViewStorageTableFields(node); // plan = addRowFilters(node, plan); // plan = addColumnMasks(node, plan); - - return plan; } - // private RelationPlan addRowFilters(Table node, RelationPlan plan) { - // return addRowFilters(node, plan, Function.identity()); - // } - - // public RelationPlan addRowFilters( - // Table node, RelationPlan plan, Function<Expression, Expression> predicateTransformation) { - // List<Expression> filters = null; - // // analysis.getRowFilters(node); - // - // if (filters.isEmpty()) { - // return plan; - // } - // - // // The fields in the access control scope has the same layout as those for the table scope - // PlanBuilder planBuilder = newPlanBuilder(plan, analysis, session); - // // .withScope(accessControlScope.apply(node), plan.getFieldMappings()); - // - // for (Expression filter : filters) { - // // planBuilder = subqueryPlanner.handleSubqueries(planBuilder, filter, - // // analysis.getSubqueries(filter)); - // - // Expression predicate = coerceIfNecessary(analysis, filter, filter); - // predicate = predicateTransformation.apply(predicate); - // planBuilder = - // planBuilder.withNewRoot( - // new FilterNode(idAllocator.genPlanNodeId(), planBuilder.getRoot(), predicate)); - // } - // - // return new RelationPlan(planBuilder.getRoot(), plan.getScope(), plan.getFieldMappings()); - // } - - // private RelationPlan addColumnMasks(Table table, RelationPlan plan) { - // Map<String, Expression> columnMasks = analysis.getColumnMasks(table); - // - // // A Table can represent a WITH query, which can have anonymous fields. On the other - // hand, - // // it can't have masks. The loop below expects fields to have proper names, so bail out - // // if the masks are missing - // if (columnMasks.isEmpty()) { - // return plan; - // } - // - // // The fields in the access control scope has the same layout as those for the table - // scope - // PlanBuilder planBuilder = newPlanBuilder(plan, analysis, session) - // .withScope(analysis.getAccessControlScope(table), plan.getFieldMappings()); - // - // Assignments.Builder assignments = Assignments.builder(); - // assignments.putIdentities(planBuilder.getRoot().getOutputSymbols()); - // - // List<Symbol> fieldMappings = new ArrayList<>(); - // for (int i = 0; i < plan.getDescriptor().getAllFieldCount(); i++) { - // Field field = plan.getDescriptor().getFieldByIndex(i); - // - // Expression mask = columnMasks.get(field.getName().orElseThrow()); - // Symbol symbol = plan.getFieldMappings().get(i); - // Expression projection = symbol.toSymbolReference(); - // if (mask != null) { - // symbol = symbolAllocator.newSymbol(symbol); - // projection = coerceIfNecessary(analysis, mask, planBuilder.rewrite(mask)); - // } - // - // assignments.put(symbol, projection); - // fieldMappings.add(symbol); - // } - // - // planBuilder = planBuilder - // .withNewRoot(new ProjectNode( - // idAllocator.genPlanNodeId(), - // planBuilder.getRoot(), - // assignments.build())); - // - // return new RelationPlan(planBuilder.getRoot(), plan.getScope(), fieldMappings); - // } + @Override + protected RelationPlan visitQuerySpecification(QuerySpecification node, Void context) { + return new QueryPlanner(analysis, symbolAllocator, idAllocator, session, recursiveSubqueries) + .plan(node); + } @Override - protected RelationPlan visitAliasedRelation(AliasedRelation node, Void context) { - RelationPlan subPlan = process(node.getRelation(), context); + protected RelationPlan visitNode(Node node, Void context) { + throw new IllegalStateException("Unsupported node type: " + node.getClass().getName()); + } - PlanNode root = subPlan.getRoot(); - List<Symbol> mappings = subPlan.getFieldMappings(); + // ================================ Implemented later ===================================== + @Override + protected RelationPlan visitTableSubquery(TableSubquery node, Void context) { + throw new IllegalStateException("TableSubquery is not supported in current version."); + } - if (node.getColumnNames() != null) { - ImmutableList.Builder<Symbol> newMappings = ImmutableList.builder(); + @Override + protected RelationPlan visitValues(Values node, Void context) { + throw new IllegalStateException("Values is not supported in current version."); + } - // Adjust the mappings to expose only the columns visible in the scope of the aliased relation - for (int i = 0; i < subPlan.getDescriptor().getAllFieldCount(); i++) { - if (!subPlan.getDescriptor().getFieldByIndex(i).isHidden()) { - newMappings.add(subPlan.getFieldMappings().get(i)); - } - } + @Override + protected RelationPlan visitSubqueryExpression(SubqueryExpression node, Void context) { + throw new IllegalStateException("SubqueryExpression is not supported in current version."); + } - mappings = newMappings.build(); - } + @Override + protected RelationPlan visitJoin(Join node, Void context) { + throw new IllegalStateException("Join is not supported in current version."); + } - return new RelationPlan(root, analysis.getScope(node), mappings); + @Override + protected RelationPlan visitAliasedRelation(AliasedRelation node, Void context) { + throw new IllegalStateException("AliasedRelation is not supported in current version."); } @Override - protected RelationPlan visitQuery(Query node, Void context) { - return new QueryPlanner(analysis, symbolAllocator, idAllocator, session, recursiveSubqueries) - .plan(node); + protected RelationPlan visitIntersect(Intersect node, Void context) { + throw new IllegalStateException("Intersect is not supported in current version."); } @Override - protected RelationPlan visitQuerySpecification(QuerySpecification node, Void context) { - return new QueryPlanner(analysis, symbolAllocator, idAllocator, session, recursiveSubqueries) - .plan(node); + protected RelationPlan visitUnion(Union node, Void context) { + throw new IllegalStateException("Union is not supported in current version."); } @Override - protected RelationPlan visitSubqueryExpression(SubqueryExpression node, Void context) { - return process(node.getQuery(), context); + protected RelationPlan visitExcept(Except node, Void context) { + throw new IllegalStateException("Except is not supported in current version."); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/FilterNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/FilterNode.java index 3c49baa4880..68289d5a83d 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/FilterNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/FilterNode.java @@ -23,6 +23,7 @@ import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanVisitor; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.SingleChildProcessNode; +import org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol; import org.apache.iotdb.db.relational.sql.tree.Expression; import java.io.DataOutputStream; @@ -45,7 +46,7 @@ public class FilterNode extends SingleChildProcessNode { @Override public PlanNode clone() { - return null; + return new FilterNode(id, child, predicate); } @Override @@ -66,4 +67,9 @@ public class FilterNode extends SingleChildProcessNode { public void setPredicate(Expression predicate) { this.predicate = predicate; } + + @Override + public List<Symbol> getOutputSymbols() { + return child.getOutputSymbols(); + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/LimitNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/LimitNode.java index 41b376e04be..17481074932 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/LimitNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/LimitNode.java @@ -4,6 +4,7 @@ import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.SingleChildProcessNode; import org.apache.iotdb.db.queryengine.plan.relational.planner.OrderingScheme; +import org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol; import java.io.DataOutputStream; import java.io.IOException; @@ -13,7 +14,7 @@ import java.util.Optional; public class LimitNode extends SingleChildProcessNode { private final long count; - // what's the meaning? + // TODO what's the meaning? private final Optional<OrderingScheme> tiesResolvingScheme; // private final boolean partial; // private final List<Symbol> preSortedInputs; @@ -27,7 +28,7 @@ public class LimitNode extends SingleChildProcessNode { @Override public PlanNode clone() { - return null; + return new LimitNode(id, child, count, tiesResolvingScheme); } @Override @@ -40,4 +41,9 @@ public class LimitNode extends SingleChildProcessNode { @Override protected void serializeAttributes(DataOutputStream stream) throws IOException {} + + @Override + public List<Symbol> getOutputSymbols() { + return child.getOutputSymbols(); + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/OffsetNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/OffsetNode.java index c4ea93a27cb..69ac2517e83 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/OffsetNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/OffsetNode.java @@ -3,6 +3,7 @@ package org.apache.iotdb.db.queryengine.plan.relational.planner.node; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.SingleChildProcessNode; +import org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol; import java.io.DataOutputStream; import java.io.IOException; @@ -19,7 +20,7 @@ public class OffsetNode extends SingleChildProcessNode { @Override public PlanNode clone() { - return null; + return new OffsetNode(id, child, count); } @Override @@ -32,4 +33,9 @@ public class OffsetNode extends SingleChildProcessNode { @Override protected void serializeAttributes(DataOutputStream stream) throws IOException {} + + @Override + public List<Symbol> getOutputSymbols() { + return child.getOutputSymbols(); + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/OutputNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/OutputNode.java index cb884b09a56..514a7bce382 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/OutputNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/OutputNode.java @@ -5,6 +5,8 @@ import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.SingleChildProcessNode; import org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol; +import com.google.common.collect.ImmutableList; + import java.io.DataOutputStream; import java.io.IOException; import java.nio.ByteBuffer; @@ -12,22 +14,22 @@ import java.util.List; public class OutputNode extends SingleChildProcessNode { - private final List<String> outputColumnNames; + private final List<String> columnNames; - private final List<Symbol> symbols; + // column name = symbol + private final List<Symbol> outputs; - public OutputNode( - PlanNodeId id, PlanNode child, List<String> outputColumnNames, List<Symbol> symbols) { + public OutputNode(PlanNodeId id, PlanNode child, List<String> columnNames, List<Symbol> outputs) { super(id, child); this.id = id; this.child = child; - this.outputColumnNames = outputColumnNames; - this.symbols = symbols; + this.columnNames = ImmutableList.copyOf(columnNames); + this.outputs = ImmutableList.copyOf(outputs); } @Override public PlanNode clone() { - return null; + return new OutputNode(id, child, columnNames, outputs); } @Override @@ -40,4 +42,8 @@ public class OutputNode extends SingleChildProcessNode { @Override protected void serializeAttributes(DataOutputStream stream) throws IOException {} + + public List<Symbol> getOutputSymbols() { + return outputs; + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/ProjectNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/ProjectNode.java index ff8de50de27..ed65602cf9e 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/ProjectNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/ProjectNode.java @@ -2,8 +2,10 @@ package org.apache.iotdb.db.queryengine.plan.relational.planner.node; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanVisitor; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.SingleChildProcessNode; import org.apache.iotdb.db.queryengine.plan.relational.planner.Assignments; +import org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol; import java.io.DataOutputStream; import java.io.IOException; @@ -18,9 +20,14 @@ public class ProjectNode extends SingleChildProcessNode { this.assignments = assignments; } + @Override + public <R, C> R accept(PlanVisitor<R, C> visitor, C context) { + return visitor.visitProject(this, context); + } + @Override public PlanNode clone() { - return null; + return new ProjectNode(id, child, assignments); } @Override @@ -33,4 +40,9 @@ public class ProjectNode extends SingleChildProcessNode { @Override protected void serializeAttributes(DataOutputStream stream) throws IOException {} + + @Override + public List<Symbol> getOutputSymbols() { + return assignments.getOutputs(); + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/SortNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/SortNode.java index 37358d3d696..2ea9f7081c2 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/SortNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/SortNode.java @@ -4,6 +4,7 @@ import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.SingleChildProcessNode; import org.apache.iotdb.db.queryengine.plan.relational.planner.OrderingScheme; +import org.apache.iotdb.db.queryengine.plan.relational.planner.Symbol; import java.io.DataOutputStream; import java.io.IOException; @@ -14,15 +15,15 @@ public class SortNode extends SingleChildProcessNode { private final OrderingScheme orderingScheme; private final boolean partial; - public SortNode(PlanNodeId id, PlanNode planNode, OrderingScheme scheme, boolean partial) { - super(id, planNode); + public SortNode(PlanNodeId id, PlanNode child, OrderingScheme scheme, boolean partial) { + super(id, child); this.orderingScheme = scheme; this.partial = partial; } @Override public PlanNode clone() { - return null; + return new SortNode(id, child, orderingScheme, partial); } @Override @@ -35,4 +36,9 @@ public class SortNode extends SingleChildProcessNode { @Override protected void serializeAttributes(DataOutputStream stream) throws IOException {} + + @Override + public List<Symbol> getOutputSymbols() { + return child.getOutputSymbols(); + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/TableScanNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/TableScanNode.java index 1b7c2476ba3..68eb557a38b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/TableScanNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/node/TableScanNode.java @@ -62,4 +62,9 @@ public class TableScanNode extends PlanNode { @Override protected void serializeAttributes(DataOutputStream stream) throws IOException {} + + @Override + public List<Symbol> getOutputSymbols() { + return outputSymbols; + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/SimplifyExpressions.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/RemoveRedundantIdentityProjections.java similarity index 52% copy from iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/SimplifyExpressions.java copy to iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/RemoveRedundantIdentityProjections.java index aef419fa123..d7366dfe9df 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/SimplifyExpressions.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/RemoveRedundantIdentityProjections.java @@ -17,42 +17,52 @@ package org.apache.iotdb.db.queryengine.plan.relational.planner.optimizations; import org.apache.iotdb.db.queryengine.common.MPPQueryContext; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanVisitor; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.SingleChildProcessNode; import org.apache.iotdb.db.queryengine.plan.relational.analyzer.Analysis; -import org.apache.iotdb.db.queryengine.plan.relational.planner.node.FilterNode; +import org.apache.iotdb.db.queryengine.plan.relational.planner.node.ProjectNode; import org.apache.iotdb.db.queryengine.plan.relational.planner.node.TableScanNode; -import org.apache.iotdb.db.relational.sql.tree.Expression; -import static org.apache.iotdb.db.queryengine.plan.relational.planner.ir.ExtractCommonPredicatesExpressionRewriter.extractCommonPredicates; -import static org.apache.iotdb.db.queryengine.plan.relational.planner.ir.NormalizeOrExpressionRewriter.normalizeOrExpression; +import java.util.Collections; +import java.util.List; -public class SimplifyExpressions implements RelationalPlanOptimizer { +public class RemoveRedundantIdentityProjections implements RelationalPlanOptimizer { @Override public PlanNode optimize(PlanNode planNode, Analysis analysis, MPPQueryContext context) { - // TODO add query statement pruning return planNode.accept(new Rewriter(), new RewriterContext()); } private static class Rewriter extends PlanVisitor<PlanNode, RewriterContext> { - @Override public PlanNode visitPlan(PlanNode node, RewriterContext context) { - // PlanNode newNode = node.clone(); - if (node.getChildren() == null) { - System.out.println("aa"); - } + PlanNode newNode = node.clone(); for (PlanNode child : node.getChildren()) { - child.accept(this, context); + context.setParent(node); + newNode.addChild(child.accept(this, context)); } - return node; + return newNode; } @Override - public PlanNode visitFilter(FilterNode node, RewriterContext context) { - Expression predicate = normalizeOrExpression(node.getPredicate()); - predicate = extractCommonPredicates(predicate); - node.setPredicate(predicate); - return node; + public PlanNode visitProject(ProjectNode projectNode, RewriterContext context) { + if (projectNode.getOutputSymbols().equals(projectNode.getChild().getOutputSymbols())) { + if (context.getParent() instanceof SingleChildProcessNode) { + ((SingleChildProcessNode) context.getParent()).setChild(projectNode.getChild()); + } else { + List<PlanNode> children = context.getParent().getChildren(); + for (int i = 0; i < children.size(); i++) { + PlanNode child = children.get(i); + if (child.getPlanNodeId().equals(projectNode.getPlanNodeId())) { + Collections.swap(children, i, children.size() - 1); + children.remove(children.size() - 1); + break; + } + } + } + return projectNode.getChild(); + } else { + return projectNode; + } } @Override @@ -61,5 +71,17 @@ public class SimplifyExpressions implements RelationalPlanOptimizer { } } - private static class RewriterContext {} + private static class RewriterContext { + private PlanNode parent; + + public RewriterContext() {} + + public PlanNode getParent() { + return this.parent; + } + + public void setParent(PlanNode parent) { + this.parent = parent; + } + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/SimplifyExpressions.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/SimplifyExpressions.java index aef419fa123..1e5839fe32a 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/SimplifyExpressions.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/SimplifyExpressions.java @@ -37,10 +37,6 @@ public class SimplifyExpressions implements RelationalPlanOptimizer { @Override public PlanNode visitPlan(PlanNode node, RewriterContext context) { - // PlanNode newNode = node.clone(); - if (node.getChildren() == null) { - System.out.println("aa"); - } for (PlanNode child : node.getChildren()) { child.accept(this, context); } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java index c42342c16cd..143bd906fbe 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AnalyzerTest.java @@ -134,9 +134,10 @@ public class AnalyzerTest { @Test public void testSingleTableQuery() throws IoTDBException { + // no sort String sql = "SELECT tag1 as tt, tag2, attr1, s1+1 FROM table1 " - + "WHERE time>1 AND tag1='A' OR s2>3 ORDER BY time DESC OFFSET 10 LIMIT 5"; + + "WHERE time>1 AND tag1='A' OR s2>3 OFFSET 10 LIMIT 5"; Metadata metadata = new TestMatadata(); Analysis actualAnalysis = analyzeSQL(sql, metadata);
