This is an automated email from the ASF dual-hosted git repository. rong pushed a commit to branch iotdb-1022-v2 in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 287c4991b09ed2530f4753d2a00150f6b4010484 Author: SteveYurongSu <[email protected]> AuthorDate: Tue May 11 21:48:21 2021 +0800 new SelectOperator --- .../antlr4/org/apache/iotdb/db/qp/sql/SqlBase.g4 | 30 ++- .../main/java/org/apache/iotdb/db/qp/Planner.java | 26 +- .../org/apache/iotdb/db/qp/logical/Operator.java | 1 - .../db/qp/logical/crud/DeleteDataOperator.java | 17 +- .../iotdb/db/qp/logical/crud/InsertOperator.java | 15 +- .../iotdb/db/qp/logical/crud/QueryOperator.java | 43 +++- .../iotdb/db/qp/logical/crud/SFWOperator.java | 98 -------- .../iotdb/db/qp/logical/crud/SelectOperator.java | 100 ++++---- .../db/qp/logical/sys/CreateIndexOperator.java | 17 +- .../iotdb/db/qp/logical/sys/DropIndexOperator.java | 18 +- .../apache/iotdb/db/qp/physical/crud/UDFPlan.java | 4 +- .../apache/iotdb/db/qp/physical/crud/UDTFPlan.java | 20 +- .../apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java | 276 +++++++++------------ .../iotdb/db/qp/strategy/PhysicalGenerator.java | 51 ++-- .../qp/strategy/optimizer/ConcatPathOptimizer.java | 2 +- .../apache/iotdb/db/query/dataset/UDTFDataSet.java | 2 +- .../iotdb/db/query/expression/Expression.java | 15 +- .../iotdb/db/query/expression/ResultColumn.java | 5 + .../query/expression/binary/BinaryExpression.java | 4 +- .../query/expression/unary/FunctionExpression.java | 43 +++- .../db/query/expression/unary/MinusExpression.java | 2 +- .../expression/unary/NumberLiteralOperand.java | 2 +- .../query/expression/unary/TimeSeriesOperand.java | 2 +- .../db/query/udf/core/context/UDFContext.java | 142 ----------- .../db/query/udf/core/executor/UDTFExecutor.java | 17 +- .../query/udf/service/UDFRegistrationService.java | 6 +- .../org/apache/iotdb/db/service/TSServiceImpl.java | 5 +- .../iotdb/db/qp/logical/IndexLogicalPlanTest.java | 4 +- .../iotdb/db/qp/logical/LogicalPlanSmallTest.java | 2 +- .../query/dataset/UDTFAlignByTimeDataSetTest.java | 45 +++- 30 files changed, 440 insertions(+), 574 deletions(-) diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlBase.g4 b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlBase.g4 index 5d9d1d3..d00b933 100644 --- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlBase.g4 +++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlBase.g4 @@ -107,26 +107,30 @@ statement ; selectClause - : SELECT (LAST | topClause)? complexOperationAsClause (COMMA complexOperationAsClause)* + : SELECT (LAST | topClause)? resultColumn (COMMA resultColumn)* ; -complexOperationAsClause - : complexOperationClause (AS ID)? +resultColumn + : expression (AS ID)? ; -complexOperationClause - : realLiteral +expression + : numberLiteral | suffixPath | functionClause - | '(' complexOperationClause ')' - | ('+' | '-') complexOperationClause - | complexOperationClause ('*' | '/' | '%') complexOperationClause - | complexOperationClause ('+' | '-') complexOperationClause + | LR_BRACKET unary=expression RR_BRACKET + | (PLUS | MINUS) unary=expression + | leftExpression=expression (STAR | DIV | MOD) rightExpression=expression + | leftExpression=expression (PLUS | MINUS) rightExpression=expression + ; + +numberLiteral + : MINUS? realLiteral + | MINUS? INT ; functionClause - : functionName=ID LR_BRACKET complexOperationClause (COMMA complexOperationClause)* - functionAttribute* RR_BRACKET + : functionName=ID LR_BRACKET expression (COMMA expression)* functionAttribute* RR_BRACKET ; functionAttribute @@ -1273,6 +1277,10 @@ MINUS : '-'; PLUS : '+'; +DIV : '/'; + +MOD : M O D | '%'; + DOT : '.'; LR_BRACKET : '('; diff --git a/server/src/main/java/org/apache/iotdb/db/qp/Planner.java b/server/src/main/java/org/apache/iotdb/db/qp/Planner.java index 355b7ef..840b04f 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/Planner.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/Planner.java @@ -30,7 +30,6 @@ import org.apache.iotdb.db.qp.logical.crud.BasicFunctionOperator; import org.apache.iotdb.db.qp.logical.crud.FilterOperator; import org.apache.iotdb.db.qp.logical.crud.FromOperator; import org.apache.iotdb.db.qp.logical.crud.QueryOperator; -import org.apache.iotdb.db.qp.logical.crud.SFWOperator; import org.apache.iotdb.db.qp.logical.crud.SelectOperator; import org.apache.iotdb.db.qp.physical.PhysicalPlan; import org.apache.iotdb.db.qp.strategy.LogicalGenerator; @@ -40,6 +39,8 @@ import org.apache.iotdb.db.qp.strategy.optimizer.DnfFilterOptimizer; import org.apache.iotdb.db.qp.strategy.optimizer.MergeSingleFilterOptimizer; import org.apache.iotdb.db.qp.strategy.optimizer.RemoveNotOptimizer; import org.apache.iotdb.db.query.control.QueryResourceManager; +import org.apache.iotdb.db.query.expression.ResultColumn; +import org.apache.iotdb.db.query.expression.unary.TimeSeriesOperand; import org.apache.iotdb.db.utils.TestOnly; import org.apache.iotdb.service.rpc.thrift.TSRawDataQueryReq; @@ -70,7 +71,7 @@ public class Planner { Operator operator = logicalGenerator.generate(sqlStr, zoneId); int maxDeduplicatedPathNum = QueryResourceManager.getInstance().getMaxDeduplicatedPathNum(fetchSize); - if (operator instanceof SFWOperator && ((SFWOperator) operator).isLastQuery()) { + if (operator instanceof QueryOperator && ((QueryOperator) operator).isLastQuery()) { // Dataset of last query actually has only three columns, so we shouldn't limit the path num // while constructing logical plan // To avoid overflowing because logicalOptimize function may do maxDeduplicatedPathNum + 1, we @@ -100,7 +101,7 @@ public class Planner { PartialPath path = new PartialPath(p); fromOp.addPrefixTablePath(path); } - selectOp.addSelectPath(new PartialPath("")); + selectOp.addResultColumn(new ResultColumn(new TimeSeriesOperand(new PartialPath("")))); queryOp.setSelectOperator(selectOp); queryOp.setFromOperator(fromOp); @@ -133,7 +134,7 @@ public class Planner { // set it to Integer.MAX_VALUE - 1 maxDeduplicatedPathNum = Integer.MAX_VALUE - 1; } - SFWOperator op = (SFWOperator) logicalOptimize(queryOp, maxDeduplicatedPathNum); + QueryOperator op = (QueryOperator) logicalOptimize(queryOp, maxDeduplicatedPathNum); PhysicalGenerator physicalGenerator = new PhysicalGenerator(); return physicalGenerator.transformToPhysicalPlan(op, rawDataQueryReq.fetchSize); @@ -181,30 +182,29 @@ public class Planner { case DROP_TRIGGER: case START_TRIGGER: case STOP_TRIGGER: - return operator; case QUERY: case DELETE: case CREATE_INDEX: case DROP_INDEX: + return operator; case QUERY_INDEX: - SFWOperator root = (SFWOperator) operator; - return optimizeSFWOperator(root, maxDeduplicatedPathNum); + return optimizeQueryOperator((QueryOperator) operator, maxDeduplicatedPathNum); default: throw new LogicalOperatorException(operator.getType().toString(), ""); } } /** - * given an unoptimized select-from-where operator and return an optimized result. + * given an unoptimized query operator and return an optimized result. * - * @param root unoptimized select-from-where operator - * @return optimized select-from-where operator - * @throws LogicalOptimizeException exception in SFW optimizing + * @param root unoptimized query operator + * @return optimized query operator + * @throws LogicalOptimizeException exception in query optimizing */ - private SFWOperator optimizeSFWOperator(SFWOperator root, int maxDeduplicatedPathNum) + private QueryOperator optimizeQueryOperator(QueryOperator root, int maxDeduplicatedPathNum) throws LogicalOperatorException, PathNumOverLimitException { ConcatPathOptimizer concatPathOptimizer = getConcatPathOptimizer(); - root = (SFWOperator) concatPathOptimizer.transform(root, maxDeduplicatedPathNum); + root = (QueryOperator) concatPathOptimizer.transform(root, maxDeduplicatedPathNum); FilterOperator filter = root.getFilterOperator(); if (filter == null) { return root; diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java index e1fb10f..f3ac665 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java @@ -73,7 +73,6 @@ public abstract class Operator { /** If you want to add new OperatorType, you must add it in the last. */ public enum OperatorType { - SFW, FILTER, GROUPBYTIME, SELECT, diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/DeleteDataOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/DeleteDataOperator.java index 3cddb30..e7a0619 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/DeleteDataOperator.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/DeleteDataOperator.java @@ -18,10 +18,16 @@ */ package org.apache.iotdb.db.qp.logical.crud; +import org.apache.iotdb.db.metadata.PartialPath; import org.apache.iotdb.db.qp.logical.Operator; +import java.util.ArrayList; +import java.util.List; + /** this class extends {@code RootOperator} and process delete statement. */ -public class DeleteDataOperator extends SFWOperator { +public class DeleteDataOperator extends Operator { + + private final List<PartialPath> paths; private long startTime; private long endTime; @@ -29,6 +35,15 @@ public class DeleteDataOperator extends SFWOperator { public DeleteDataOperator(int tokenIntType) { super(tokenIntType); operatorType = Operator.OperatorType.DELETE; + paths = new ArrayList<>(); + } + + public List<PartialPath> getPaths() { + return paths; + } + + public void addPath(PartialPath path) { + paths.add(path); } public long getStartTime() { diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/InsertOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/InsertOperator.java index bd410c6..e8c3f42 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/InsertOperator.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/InsertOperator.java @@ -18,8 +18,13 @@ */ package org.apache.iotdb.db.qp.logical.crud; +import org.apache.iotdb.db.metadata.PartialPath; +import org.apache.iotdb.db.qp.logical.Operator; + /** this class extends {@code RootOperator} and process insert statement. */ -public class InsertOperator extends SFWOperator { +public class InsertOperator extends Operator { + + private PartialPath device; private long[] times; private String[] measurementList; @@ -30,6 +35,14 @@ public class InsertOperator extends SFWOperator { operatorType = OperatorType.INSERT; } + public PartialPath getDevice() { + return device; + } + + public void setDevice(PartialPath device) { + this.device = device; + } + public String[] getMeasurementList() { return measurementList; } diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java index 87aa1d9..f80dcbb 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/QueryOperator.java @@ -25,8 +25,11 @@ import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType; import java.util.Map; -/** this class extends {@code RootOperator} and process getIndex statement */ -public class QueryOperator extends SFWOperator { +public class QueryOperator extends Operator { + + private SelectOperator selectOperator; + private FromOperator fromOperator; + private FilterOperator filterOperator; private long startTime; private long endTime; @@ -67,6 +70,30 @@ public class QueryOperator extends SFWOperator { operatorType = Operator.OperatorType.QUERY; } + public SelectOperator getSelectOperator() { + return selectOperator; + } + + public void setSelectOperator(SelectOperator selectOperator) { + this.selectOperator = selectOperator; + } + + public FromOperator getFromOperator() { + return fromOperator; + } + + public void setFromOperator(FromOperator fromOperator) { + this.fromOperator = fromOperator; + } + + public FilterOperator getFilterOperator() { + return filterOperator; + } + + public void setFilterOperator(FilterOperator filterOperator) { + this.filterOperator = filterOperator; + } + public Map<String, Object> getProps() { return props; } @@ -250,4 +277,16 @@ public class QueryOperator extends SFWOperator { public void setAscending(boolean ascending) { this.ascending = ascending; } + + public boolean isLastQuery() { + return selectOperator.isLastQuery(); + } + + public boolean hasAggregationFunction() { + return selectOperator.hasAggregationFunction(); + } + + public boolean hasTimeSeriesGeneratingFunction() { + return selectOperator.hasTimeSeriesGeneratingFunction(); + } } diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SFWOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SFWOperator.java deleted file mode 100644 index 14d510b..0000000 --- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SFWOperator.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.iotdb.db.qp.logical.crud; - -import org.apache.iotdb.db.metadata.PartialPath; -import org.apache.iotdb.db.qp.logical.RootOperator; - -import java.util.List; - -/** - * SFWOperator(select-from-where) includes four subclass: INSERT,DELETE,UPDATE,QUERY. All of these - * four statements has three partition: select clause, from clause and filter clause(where clause). - */ -public abstract class SFWOperator extends RootOperator { - - private SelectOperator selectOperator; - private FromOperator fromOperator; - private FilterOperator filterOperator; - private boolean hasAggregation = false; - private boolean hasUdf = false; - private boolean lastQuery = false; - - public SFWOperator(int tokenIntType) { - super(tokenIntType); - operatorType = OperatorType.SFW; - } - - public FromOperator getFromOperator() { - return fromOperator; - } - - public void setFromOperator(FromOperator from) { - this.fromOperator = from; - } - - public SelectOperator getSelectOperator() { - return selectOperator; - } - - /** set selectOperator, then init hasAggregation according to selectOperator. */ - public void setSelectOperator(SelectOperator sel) { - this.selectOperator = sel; - if (sel.hasAggregation()) { - hasAggregation = true; - } - if (sel.isUdfQuery()) { - hasUdf = true; - } - if (sel.isLastQuery()) { - lastQuery = true; - } - } - - public FilterOperator getFilterOperator() { - return filterOperator; - } - - public void setFilterOperator(FilterOperator filter) { - this.filterOperator = filter; - } - - /** - * get information from SelectOperator and FromOperator and generate all table paths. - * - * @return - a list of seriesPath - */ - public List<PartialPath> getSelectedPaths() { - return selectOperator != null ? selectOperator.getSuffixPaths() : null; - } - - public boolean hasAggregation() { - return hasAggregation; - } - - public boolean hasUdf() { - return hasUdf; - } - - public boolean isLastQuery() { - return lastQuery; - } -} diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SelectOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SelectOperator.java index 5b34ea5..913ef74 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SelectOperator.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/crud/SelectOperator.java @@ -20,7 +20,9 @@ package org.apache.iotdb.db.qp.logical.crud; import org.apache.iotdb.db.metadata.PartialPath; import org.apache.iotdb.db.qp.logical.Operator; -import org.apache.iotdb.db.query.udf.core.context.UDFContext; +import org.apache.iotdb.db.query.expression.ResultColumn; +import org.apache.iotdb.db.query.expression.unary.FunctionExpression; +import org.apache.iotdb.db.query.expression.unary.TimeSeriesOperand; import java.time.ZoneId; import java.util.ArrayList; @@ -30,87 +32,79 @@ import java.util.List; public final class SelectOperator extends Operator { private final ZoneId zoneId; - private List<PartialPath> suffixList; - private List<String> aggregations; - private List<UDFContext> udfList; - private boolean lastQuery; - private boolean udfQuery; - private boolean hasBuiltinAggregation; + private boolean isLastQuery = false; + private boolean hasAggregationFunction = false; + private boolean hasTimeSeriesGeneratingFunction = false; + + private List<ResultColumn> resultColumns = new ArrayList<>(); + + private List<PartialPath> pathsCache; + private List<String> aggregationFunctionsCache; /** init with tokenIntType, default operatorType is <code>OperatorType.SELECT</code>. */ public SelectOperator(int tokenIntType, ZoneId zoneId) { super(tokenIntType); - this.zoneId = zoneId; operatorType = OperatorType.SELECT; - suffixList = new ArrayList<>(); - aggregations = new ArrayList<>(); - udfList = new ArrayList<>(); - lastQuery = false; - udfQuery = false; - hasBuiltinAggregation = false; + this.zoneId = zoneId; } public ZoneId getZoneId() { return zoneId; } - public void addSelectPath(PartialPath suffixPath) { - suffixList.add(suffixPath); - } - - public void addClusterPath(PartialPath suffixPath, String aggregation) { - suffixList.add(suffixPath); - aggregations.add(aggregation); - if (aggregation != null) { - hasBuiltinAggregation = true; - } + public void markAsLastQuery() { + isLastQuery = true; } public boolean isLastQuery() { - return this.lastQuery; - } - - public void setLastQuery() { - lastQuery = true; + return isLastQuery; } - public List<String> getAggregations() { - return this.aggregations; + public boolean hasAggregationFunction() { + return hasAggregationFunction; } - public void setAggregations(List<String> aggregations) { - this.aggregations = aggregations; + public boolean hasTimeSeriesGeneratingFunction() { + return hasTimeSeriesGeneratingFunction; } - public boolean hasAggregation() { - return hasBuiltinAggregation; // todo: hasBuiltinAggregation || hasUDAF + public void addResultColumn(ResultColumn resultColumn) { + resultColumns.add(resultColumn); + if (resultColumn.getExpression().isAggregationFunctionExpression()) { + hasAggregationFunction = true; + } + if (resultColumn.getExpression().isTimeSeriesGeneratingFunctionExpression()) { + hasTimeSeriesGeneratingFunction = true; + } } - public void setSuffixPathList(List<PartialPath> suffixPaths) { - suffixList = suffixPaths; + public void setResultColumns(List<ResultColumn> resultColumns) { + this.resultColumns = resultColumns; } - public List<PartialPath> getSuffixPaths() { - return suffixList; + public List<ResultColumn> getResultColumns() { + return resultColumns; } - public void addUdf(UDFContext udf) { - if (udf != null) { - udfQuery = true; + public List<PartialPath> getPaths() { + if (pathsCache == null) { + pathsCache = new ArrayList<>(); + for (ResultColumn resultColumn : resultColumns) { + pathsCache.add(((TimeSeriesOperand) resultColumn.getExpression()).getPath()); + } } - udfList.add(udf); - } - - public List<UDFContext> getUdfList() { - return udfList; - } - - public boolean isUdfQuery() { - return udfQuery; + return pathsCache; } - public void setUdfList(List<UDFContext> udfList) { - this.udfList = udfList; + public List<String> getAggregationFunctions() { + if (aggregationFunctionsCache == null) { + aggregationFunctionsCache = new ArrayList<>(); + for (ResultColumn resultColumn : resultColumns) { + aggregationFunctionsCache.add( + ((FunctionExpression) resultColumn.getExpression()).getFunctionName()); + } + } + return aggregationFunctionsCache; } } diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/sys/CreateIndexOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/sys/CreateIndexOperator.java index 46f5cad..8934bee 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/logical/sys/CreateIndexOperator.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/sys/CreateIndexOperator.java @@ -19,13 +19,17 @@ package org.apache.iotdb.db.qp.logical.sys; import org.apache.iotdb.db.index.common.IndexType; -import org.apache.iotdb.db.qp.logical.crud.SFWOperator; +import org.apache.iotdb.db.metadata.PartialPath; +import org.apache.iotdb.db.qp.logical.Operator; +import java.util.ArrayList; +import java.util.List; import java.util.Map; /** this operator is to create a certain index on some time series. */ -public class CreateIndexOperator extends SFWOperator { +public class CreateIndexOperator extends Operator { + private final List<PartialPath> paths; private Map<String, String> props; private long time; private IndexType indexType; @@ -33,6 +37,15 @@ public class CreateIndexOperator extends SFWOperator { public CreateIndexOperator(int tokenIntType) { super(tokenIntType); operatorType = OperatorType.CREATE_INDEX; + paths = new ArrayList<>(); + } + + public List<PartialPath> getPaths() { + return paths; + } + + public void addPath(PartialPath path) { + paths.add(path); } public long getTime() { diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/sys/DropIndexOperator.java b/server/src/main/java/org/apache/iotdb/db/qp/logical/sys/DropIndexOperator.java index 1ea6538..e538311 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/logical/sys/DropIndexOperator.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/sys/DropIndexOperator.java @@ -19,16 +19,30 @@ package org.apache.iotdb.db.qp.logical.sys; import org.apache.iotdb.db.index.common.IndexType; -import org.apache.iotdb.db.qp.logical.crud.SFWOperator; +import org.apache.iotdb.db.metadata.PartialPath; +import org.apache.iotdb.db.qp.logical.Operator; + +import java.util.ArrayList; +import java.util.List; /** this operator is to drop a certain index on some time series. */ -public class DropIndexOperator extends SFWOperator { +public class DropIndexOperator extends Operator { + private final List<PartialPath> paths; private IndexType indexType; public DropIndexOperator(int tokenIntType) { super(tokenIntType); operatorType = OperatorType.DROP_INDEX; + paths = new ArrayList<>(); + } + + public List<PartialPath> getPaths() { + return paths; + } + + public void addPath(PartialPath path) { + paths.add(path); } public IndexType getIndexType() { diff --git a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/UDFPlan.java b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/UDFPlan.java index b152a08..f1ed19f 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/UDFPlan.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/UDFPlan.java @@ -20,7 +20,7 @@ package org.apache.iotdb.db.qp.physical.crud; import org.apache.iotdb.db.exception.query.QueryProcessException; -import org.apache.iotdb.db.query.udf.core.context.UDFContext; +import org.apache.iotdb.db.query.expression.ResultColumn; import java.util.List; @@ -37,7 +37,7 @@ public interface UDFPlan { * Build the execution plan of the executors. This method will not create any UDF instances, nor * will it execute user-defined logic. */ - void constructUdfExecutors(List<UDFContext> udfContexts); + void constructUdfExecutors(List<ResultColumn> resultColumns); /** Allocate computing resources, create UDF instances, and call UDF initialization methods. */ void initializeUdfExecutors(long queryId, float collectorMemoryBudgetInMb) diff --git a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/UDTFPlan.java b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/UDTFPlan.java index 78eb25d..6eecb73 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/UDTFPlan.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/UDTFPlan.java @@ -21,7 +21,8 @@ package org.apache.iotdb.db.qp.physical.crud; import org.apache.iotdb.db.exception.query.QueryProcessException; import org.apache.iotdb.db.qp.logical.Operator; -import org.apache.iotdb.db.query.udf.core.context.UDFContext; +import org.apache.iotdb.db.query.expression.ResultColumn; +import org.apache.iotdb.db.query.expression.unary.FunctionExpression; import org.apache.iotdb.db.query.udf.core.executor.UDTFExecutor; import org.apache.iotdb.db.query.udf.service.UDFClassLoaderManager; import org.apache.iotdb.db.query.udf.service.UDFRegistrationService; @@ -52,18 +53,15 @@ public class UDTFPlan extends RawDataQueryPlan implements UDFPlan { } @Override - public void constructUdfExecutors(List<UDFContext> udfContexts) { - for (int i = 0; i < udfContexts.size(); ++i) { - UDFContext context = udfContexts.get(i); - if (context == null) { + public void constructUdfExecutors(List<ResultColumn> resultColumns) { + for (int i = 0; i < resultColumns.size(); ++i) { + FunctionExpression expression = (FunctionExpression) resultColumns.get(i).getExpression(); + if (expression == null) { continue; } - String columnName = context.getColumnName(); - if (!columnName2Executor.containsKey(columnName)) { - UDTFExecutor executor = new UDTFExecutor(context, zoneId); - columnName2Executor.put(columnName, executor); - } + String columnName = expression.toString(); + columnName2Executor.computeIfAbsent(columnName, k -> new UDTFExecutor(expression, zoneId)); originalOutputColumnIndex2Executor.put(i, columnName2Executor.get(columnName)); } } @@ -134,7 +132,7 @@ public class UDTFPlan extends RawDataQueryPlan implements UDFPlan { @Override public String getColumnForDisplay(String columnForReader, int pathIndex) { if (paths.get(pathIndex) == null) { - return this.getExecutorByOriginalOutputColumnIndex(pathIndex).getContext().getColumnName(); + return this.getExecutorByOriginalOutputColumnIndex(pathIndex).getExpression().toString(); } return columnForReader; } diff --git a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java index 3888c74..a5bff6b 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java @@ -78,8 +78,6 @@ import org.apache.iotdb.db.qp.logical.sys.StartTriggerOperator; import org.apache.iotdb.db.qp.logical.sys.StopTriggerOperator; import org.apache.iotdb.db.qp.logical.sys.TracingOperator; import org.apache.iotdb.db.qp.physical.crud.GroupByTimePlan; -import org.apache.iotdb.db.qp.sql.SqlBaseParser.AggregationCallContext; -import org.apache.iotdb.db.qp.sql.SqlBaseParser.AggregationElementContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.AliasClauseContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.AlignByDeviceClauseOrDisableAlignInSpecialLimitContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.AlignByDeviceStatementOrDisableAlignInSpecialClauseContext; @@ -87,11 +85,8 @@ import org.apache.iotdb.db.qp.sql.SqlBaseParser.AlterClauseContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.AlterTimeseriesContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.AlterUserContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.AndExpressionContext; -import org.apache.iotdb.db.qp.sql.SqlBaseParser.AsClauseContext; -import org.apache.iotdb.db.qp.sql.SqlBaseParser.AsElementContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.AttributeClauseContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.AttributeClausesContext; -import org.apache.iotdb.db.qp.sql.SqlBaseParser.BuiltInFunctionCallContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.ClearcacheContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.ConstantContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.CountDevicesContext; @@ -115,14 +110,15 @@ import org.apache.iotdb.db.qp.sql.SqlBaseParser.DropIndexContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.DropRoleContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.DropTriggerContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.DropUserContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ExpressionContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.FillClauseContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.FillStatementContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.FlushContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.FromClauseContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.FullMergeContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.FullPathContext; -import org.apache.iotdb.db.qp.sql.SqlBaseParser.FunctionAsClauseContext; -import org.apache.iotdb.db.qp.sql.SqlBaseParser.FunctionAsElementContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.FunctionAttributeContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.FunctionClauseContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.GrantRoleContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.GrantRoleToUserContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.GrantUserContext; @@ -141,8 +137,6 @@ import org.apache.iotdb.db.qp.sql.SqlBaseParser.InsertMultiValueContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.InsertStatementContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.InsertValuesSpecContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.KillQueryContext; -import org.apache.iotdb.db.qp.sql.SqlBaseParser.LastClauseContext; -import org.apache.iotdb.db.qp.sql.SqlBaseParser.LastElementContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.LimitClauseContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.LimitStatementContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.ListAllRoleOfUserContext; @@ -172,11 +166,13 @@ import org.apache.iotdb.db.qp.sql.SqlBaseParser.PrivilegesContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.PropertyContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.PropertyValueContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.RemoveFileContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.ResultColumnContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.RevokeRoleContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.RevokeRoleFromUserContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.RevokeUserContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.RevokeWatermarkEmbeddingContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.RootOrIdContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.SelectClauseContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.SelectStatementContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.SequenceClauseContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.SetStorageGroupContext; @@ -204,23 +200,30 @@ import org.apache.iotdb.db.qp.sql.SqlBaseParser.StartTriggerContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.StopTriggerContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.StringLiteralContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.SuffixPathContext; -import org.apache.iotdb.db.qp.sql.SqlBaseParser.TableCallContext; -import org.apache.iotdb.db.qp.sql.SqlBaseParser.TableElementContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.TagClauseContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.TimeIntervalContext; +import org.apache.iotdb.db.qp.sql.SqlBaseParser.TopClauseContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.TracingOffContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.TracingOnContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.TriggerAttributeContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.TypeClauseContext; -import org.apache.iotdb.db.qp.sql.SqlBaseParser.UdfAttributeContext; -import org.apache.iotdb.db.qp.sql.SqlBaseParser.UdfCallContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.UnsetTTLStatementContext; import org.apache.iotdb.db.qp.sql.SqlBaseParser.WhereClauseContext; import org.apache.iotdb.db.qp.utils.DatetimeUtils; import org.apache.iotdb.db.query.executor.fill.IFill; import org.apache.iotdb.db.query.executor.fill.LinearFill; import org.apache.iotdb.db.query.executor.fill.PreviousFill; -import org.apache.iotdb.db.query.udf.core.context.UDFContext; +import org.apache.iotdb.db.query.expression.Expression; +import org.apache.iotdb.db.query.expression.ResultColumn; +import org.apache.iotdb.db.query.expression.binary.AdditionExpression; +import org.apache.iotdb.db.query.expression.binary.DivisionExpression; +import org.apache.iotdb.db.query.expression.binary.ModuloExpression; +import org.apache.iotdb.db.query.expression.binary.MultiplicationExpression; +import org.apache.iotdb.db.query.expression.binary.SubtractionExpression; +import org.apache.iotdb.db.query.expression.unary.FunctionExpression; +import org.apache.iotdb.db.query.expression.unary.MinusExpression; +import org.apache.iotdb.db.query.expression.unary.NumberLiteralOperand; +import org.apache.iotdb.db.query.expression.unary.TimeSeriesOperand; import org.apache.iotdb.tsfile.common.conf.TSFileDescriptor; import org.apache.iotdb.tsfile.common.constant.TsFileConstant; import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType; @@ -255,7 +258,7 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { "For delete statement, where clause can only contain atomic expressions like : " + "time > XXX, time <= XXX, or two atomic expressions connected by 'AND'"; private ZoneId zoneId; - QueryOperator queryOp; + private QueryOperator queryOp; private boolean isParsingSlidingStep; public void setZoneId(ZoneId zoneId) { @@ -310,9 +313,7 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { @Override public Operator visitInsertStatement(InsertStatementContext ctx) { InsertOperator insertOp = new InsertOperator(SQLConstant.TOK_INSERT); - SelectOperator selectOp = new SelectOperator(SQLConstant.TOK_SELECT, zoneId); - selectOp.addSelectPath(parsePrefixPath(ctx.prefixPath())); - insertOp.setSelectOperator(selectOp); + insertOp.setDevice(parsePrefixPath(ctx.prefixPath())); parseInsertColumnSpec(ctx.insertColumnsSpec(), insertOp); parseInsertValuesSpec(ctx.insertValuesSpec(), insertOp); return insertOp; @@ -321,17 +322,13 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { @Override public Operator visitDeleteStatement(DeleteStatementContext ctx) { DeleteDataOperator deleteDataOp = new DeleteDataOperator(SQLConstant.TOK_DELETE); - SelectOperator selectOp = new SelectOperator(SQLConstant.TOK_SELECT, zoneId); List<PrefixPathContext> prefixPaths = ctx.prefixPath(); for (PrefixPathContext prefixPath : prefixPaths) { - PartialPath path = parsePrefixPath(prefixPath); - selectOp.addSelectPath(path); + deleteDataOp.addPath(parsePrefixPath(prefixPath)); } - deleteDataOp.setSelectOperator(selectOp); if (ctx.whereClause() != null) { FilterOperator whereOp = (FilterOperator) visit(ctx.whereClause()); - deleteDataOp.setFilterOperator(whereOp.getChildren().get(0)); - Pair<Long, Long> timeInterval = parseDeleteTimeInterval(deleteDataOp); + Pair<Long, Long> timeInterval = parseDeleteTimeInterval(whereOp.getChildren().get(0)); deleteDataOp.setStartTime(timeInterval.left); deleteDataOp.setEndTime(timeInterval.right); } else { @@ -366,31 +363,21 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { @Override public Operator visitCreateIndex(CreateIndexContext ctx) { CreateIndexOperator createIndexOp = new CreateIndexOperator(SQLConstant.TOK_CREATE_INDEX); - SelectOperator selectOp = new SelectOperator(SQLConstant.TOK_SELECT, zoneId); List<PrefixPathContext> prefixPaths = Collections.singletonList(ctx.prefixPath()); for (PrefixPathContext prefixPath : prefixPaths) { - PartialPath path = parsePrefixPath(prefixPath); - selectOp.addSelectPath(path); + createIndexOp.addPath(parsePrefixPath(prefixPath)); } - createIndexOp.setSelectOperator(selectOp); parseIndexWithClause(ctx.indexWithClause(), createIndexOp); - FilterOperator whereOp; if (ctx.whereClause() != null) { - whereOp = (FilterOperator) visit(ctx.whereClause()); - createIndexOp.setFilterOperator(whereOp.getChildren().get(0)); - long indexTime = parseCreateIndexFilter(createIndexOp); + FilterOperator whereOp = (FilterOperator) visit(ctx.whereClause()); + long indexTime = parseCreateIndexFilter(whereOp.getChildren().get(0)); createIndexOp.setTime(indexTime); } return createIndexOp; } - /** - * for create index command, time should only have an end time. - * - * @param operator create index plan - */ - private long parseCreateIndexFilter(CreateIndexOperator operator) { - FilterOperator filterOperator = operator.getFilterOperator(); + /** for create index command, time should only have an end time. */ + private long parseCreateIndexFilter(FilterOperator filterOperator) { if (filterOperator.getTokenIntType() != SQLConstant.GREATERTHAN && filterOperator.getTokenIntType() != SQLConstant.GREATERTHANOREQUALTO) { throw new SQLParserException( @@ -428,13 +415,10 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { @Override public Operator visitDropIndex(DropIndexContext ctx) { DropIndexOperator dropIndexOperator = new DropIndexOperator(SQLConstant.TOK_DROP_INDEX); - SelectOperator selectOp = new SelectOperator(SQLConstant.TOK_SELECT, zoneId); List<PrefixPathContext> prefixPaths = Collections.singletonList(ctx.prefixPath()); for (PrefixPathContext prefixPath : prefixPaths) { - PartialPath path = parsePrefixPath(prefixPath); - selectOp.addSelectPath(path); + dropIndexOperator.addPath(parsePrefixPath(prefixPath)); } - dropIndexOperator.setSelectOperator(selectOp); try { dropIndexOperator.setIndexType(IndexType.getIndexType(ctx.indexName.getText())); } catch (UnsupportedIndexTypeException e) { @@ -1007,24 +991,12 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { @Override public Operator visitSelectStatement(SelectStatementContext ctx) { queryOp = new QueryOperator(SQLConstant.TOK_QUERY); - SelectOperator selectOp = (SelectOperator) visit(ctx.selectElements()); - queryOp.setSelectOperator(selectOp); - FromOperator fromOp = (FromOperator) visit(ctx.fromClause()); - queryOp.setFromOperator(fromOp); - if (ctx.topClause() != null) { - Map<String, Object> props = new HashMap<>(); - int top = Integer.parseInt(ctx.topClause().INT().getText()); - if (top < 0) { - throw new SQLParserException("TOP <N>: N should be greater than 0."); - } - props.put(TOP_K, top); - queryOp.setProps(props); - } + queryOp.setSelectOperator((SelectOperator) visit(ctx.selectClause())); + queryOp.setFromOperator((FromOperator) visit(ctx.fromClause())); if (ctx.whereClause() != null) { Operator operator = visit(ctx.whereClause()); if (operator instanceof FilterOperator) { - FilterOperator whereOp = (FilterOperator) operator; - queryOp.setFilterOperator(whereOp.getChildren().get(0)); + queryOp.setFilterOperator(((FilterOperator) operator).getChildren().get(0)); } } if (ctx.specialClause() != null) { @@ -1034,91 +1006,98 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { } @Override - public Operator visitAggregationElement(AggregationElementContext ctx) { + public Operator visitSelectClause(SelectClauseContext ctx) { SelectOperator selectOp = new SelectOperator(SQLConstant.TOK_SELECT, zoneId); - for (AggregationCallContext aggregationCallContext : ctx.aggregationCall()) { - BuiltInFunctionCallContext builtInFunctionCallContext = - aggregationCallContext.builtInFunctionCall(); - UdfCallContext udfCallContext = aggregationCallContext.udfCall(); - if (builtInFunctionCallContext != null) { - selectOp.addClusterPath( - parseSuffixPath(builtInFunctionCallContext.suffixPath()), - builtInFunctionCallContext.functionName().getText()); - selectOp.addUdf(null); - } else if (udfCallContext != null) { - selectOp.addClusterPath(null, null); - parseUdfCall(udfCallContext, selectOp); - } + if (ctx.topClause() != null) { + // TODO: parse info of top clause into selectOp + visitTopClause(ctx.topClause()); + } else if (ctx.LAST() != null) { + selectOp.markAsLastQuery(); } - return selectOp; - } - - public void parseUdfCall(UdfCallContext udfCall, SelectOperator selectOp) { - String udfName = udfCall.udfName.getText(); - UDFContext udf = new UDFContext(udfName); - - for (SuffixPathContext suffixPathContext : udfCall.udfSuffixPaths().suffixPath()) { - udf.addPath(parseSuffixPath(suffixPathContext)); - } - for (UdfAttributeContext udfAttributeContext : udfCall.udfAttribute()) { - udf.addAttribute( - removeStringQuote(udfAttributeContext.udfAttributeKey.getText()), - removeStringQuote(udfAttributeContext.udfAttributeValue.getText())); + for (ResultColumnContext resultColumnContext : ctx.resultColumn()) { + selectOp.addResultColumn(parseResultColumn(resultColumnContext)); } - selectOp.addUdf(udf); + return selectOp; } @Override - public Operator visitLastElement(LastElementContext ctx) { - SelectOperator selectOp = new SelectOperator(SQLConstant.TOK_SELECT, zoneId); - selectOp.setLastQuery(); - LastClauseContext lastClauseContext = ctx.lastClause(); - if (lastClauseContext.asClause().size() != 0) { - parseAsClause(lastClauseContext.asClause(), selectOp); - } else { - List<SuffixPathContext> suffixPaths = lastClauseContext.suffixPath(); - for (SuffixPathContext suffixPath : suffixPaths) { - PartialPath path = parseSuffixPath(suffixPath); - selectOp.addSelectPath(path); - } + public Operator visitTopClause(TopClauseContext ctx) { + Map<String, Object> props = new HashMap<>(); + int top = Integer.parseInt(ctx.INT().getText()); + if (top < 0) { + throw new SQLParserException("TOP <N>: N should be greater than 0."); } - return selectOp; + props.put(TOP_K, top); + queryOp.setProps(props); + return queryOp; } - @Override - public Operator visitAsElement(AsElementContext ctx) { - SelectOperator selectOp = new SelectOperator(SQLConstant.TOK_SELECT, zoneId); - parseAsClause(ctx.asClause(), selectOp); - return selectOp; + private ResultColumn parseResultColumn(ResultColumnContext resultColumnContext) { + return new ResultColumn( + parseExpression(resultColumnContext.expression()), + resultColumnContext.AS() == null ? null : resultColumnContext.ID().getText()); } - @Override - public Operator visitFunctionAsElement(FunctionAsElementContext ctx) { - SelectOperator selectOp = new SelectOperator(SQLConstant.TOK_SELECT, zoneId); - List<FunctionAsClauseContext> functionAsClauseContexts = ctx.functionAsClause(); - for (FunctionAsClauseContext functionAsClauseContext : functionAsClauseContexts) { - BuiltInFunctionCallContext functionCallContext = - functionAsClauseContext.builtInFunctionCall(); - PartialPath path = parseSuffixPath(functionCallContext.suffixPath()); - if (functionAsClauseContext.ID() != null) { - path.setTsAlias(functionAsClauseContext.ID().toString()); - } - selectOp.addClusterPath(path, functionCallContext.functionName().getText()); + @SuppressWarnings("squid:S3776") + private Expression parseExpression(ExpressionContext context) { + // unary + if (context.numberLiteral() != null) { + return new NumberLiteralOperand(Double.parseDouble(context.numberLiteral().getText())); } - return selectOp; + if (context.suffixPath() != null) { + return new TimeSeriesOperand(parseSuffixPath(context.suffixPath())); + } + if (context.functionClause() != null) { + return parseFunctionExpression(context.functionClause()); + } + if (context.unary != null) { + return context.MINUS() != null + ? new MinusExpression(parseExpression(context.expression(0))) + : parseExpression(context.expression(0)); + } + + // binary + Expression leftExpression = parseExpression(context.leftExpression); + Expression rightExpression = parseExpression(context.rightExpression); + if (context.STAR() != null) { + return new MultiplicationExpression(leftExpression, rightExpression); + } + if (context.DIV() != null) { + return new DivisionExpression(leftExpression, rightExpression); + } + if (context.MOD() != null) { + return new ModuloExpression(leftExpression, rightExpression); + } + if (context.PLUS() != null) { + return new AdditionExpression(leftExpression, rightExpression); + } + if (context.MINUS() != null) { + return new SubtractionExpression(leftExpression, rightExpression); + } + + throw new UnsupportedOperationException(); } - public void parseAsClause(List<AsClauseContext> asClauseContexts, SelectOperator selectOp) { - for (AsClauseContext asClauseContext : asClauseContexts) { - PartialPath path = parseSuffixPath(asClauseContext.suffixPath()); - if (asClauseContext.ID() != null) { - path.setTsAlias(asClauseContext.ID().toString()); - } - selectOp.addSelectPath(path); + private Expression parseFunctionExpression(FunctionClauseContext functionClause) { + FunctionExpression functionExpression = + new FunctionExpression(functionClause.functionName.getText()); + + // expressions + for (ExpressionContext expression : functionClause.expression()) { + functionExpression.addExpression(parseExpression(expression)); + } + + // attributes + for (FunctionAttributeContext functionAttribute : functionClause.functionAttribute()) { + functionExpression.addAttribute( + removeStringQuote(functionAttribute.functionAttributeKey.getText()), + removeStringQuote(functionAttribute.functionAttributeValue.getText())); } + + return functionExpression; } @Override @@ -1242,30 +1221,6 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { } @Override - public Operator visitTableElement(TableElementContext ctx) { - SelectOperator selectOp = new SelectOperator(SQLConstant.TOK_SELECT, zoneId); - - for (TableCallContext tableCallContext : ctx.tableCall()) { - SuffixPathContext suffixPathContext = tableCallContext.suffixPath(); - UdfCallContext udfCallContext = tableCallContext.udfCall(); - if (suffixPathContext != null) { - selectOp.addSelectPath(parseSuffixPath(suffixPathContext)); - selectOp.addUdf(null); - } else if (udfCallContext != null) { - selectOp.addSelectPath(null); - parseUdfCall(udfCallContext, selectOp); - } else { - selectOp.addSelectPath( - new PartialPath( - new String[] {tableCallContext.SINGLE_QUOTE_STRING_LITERAL().getText()})); - selectOp.addUdf(null); - } - } - - return selectOp; - } - - @Override public Operator visitFromClause(FromClauseContext ctx) { FromOperator fromOp = new FromOperator(SQLConstant.TOK_FROM); List<PrefixPathContext> prefixFromPaths = ctx.prefixPath(); @@ -1286,10 +1241,11 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { } if (ctx.LIKE() != null) { // whole matching case - if (queryOp.getSelectedPaths().size() != 1) { + if (queryOp.getSelectOperator().getResultColumns().size() != 1) { throw new SQLParserException("Index query statement allows only one select path"); } - if (!path.equals(queryOp.getSelectedPaths().get(0))) { + if (!path.equals( + queryOp.getSelectOperator().getResultColumns().get(0).getExpression().toString())) { throw new SQLParserException( "In the index query statement, " + "the path in select element and the index predicate should be same"); @@ -1314,9 +1270,7 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { } else { props = new HashMap<>(); } - List<PartialPath> suffixPaths = new ArrayList<>(); - suffixPaths.add(path); - queryOp.getSelectOperator().setSuffixPathList(suffixPaths); + queryOp.getSelectOperator().addResultColumn(new ResultColumn(new TimeSeriesOperand(path))); props.put(PATTERN, compositePattern); props.put(THRESHOLD, thresholds); queryOp.setIndexType(IndexType.ELB_INDEX); @@ -1336,7 +1290,7 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { } public void parseGroupByLevelClause(GroupByLevelClauseContext ctx, QueryOperator queryOp) { - if (!queryOp.hasAggregation()) { + if (!queryOp.hasAggregationFunction()) { throw new SQLParserException(GroupByTimePlan.LACK_FUNC_ERROR_MESSAGE); } queryOp.setGroupByLevel(true); @@ -1430,7 +1384,7 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { } private void parseGroupByTimeClause(GroupByTimeClauseContext ctx, QueryOperator queryOp) { - if (!queryOp.hasAggregation()) { + if (!queryOp.hasAggregationFunction()) { throw new SQLParserException(GroupByTimePlan.LACK_FUNC_ERROR_MESSAGE); } queryOp.setGroupByTime(true); @@ -1458,7 +1412,7 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { } private void parseGroupByFillClause(GroupByFillClauseContext ctx, QueryOperator queryOp) { - if (!queryOp.hasAggregation()) { + if (!queryOp.hasAggregationFunction()) { throw new SQLParserException(GroupByTimePlan.LACK_FUNC_ERROR_MESSAGE); } queryOp.setGroupByTime(true); @@ -1636,13 +1590,7 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> { return privileges.toArray(new String[0]); } - /** - * for delete command, time should only have an end time. - * - * @param operator delete logical plan - */ - private Pair<Long, Long> parseDeleteTimeInterval(DeleteDataOperator operator) { - FilterOperator filterOperator = operator.getFilterOperator(); + private Pair<Long, Long> parseDeleteTimeInterval(FilterOperator filterOperator) { if (!filterOperator.isLeaf() && filterOperator.getTokenIntType() != SQLConstant.KW_AND) { throw new SQLParserException(DELETE_RANGE_ERROR_MSG); } diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java b/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java index fdb331b..71dc3da 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/PhysicalGenerator.java @@ -122,7 +122,7 @@ import org.apache.iotdb.db.qp.physical.sys.ShowTriggersPlan; import org.apache.iotdb.db.qp.physical.sys.StartTriggerPlan; import org.apache.iotdb.db.qp.physical.sys.StopTriggerPlan; import org.apache.iotdb.db.qp.physical.sys.TracingPlan; -import org.apache.iotdb.db.query.udf.core.context.UDFContext; +import org.apache.iotdb.db.query.expression.unary.FunctionExpression; import org.apache.iotdb.db.service.IoTDB; import org.apache.iotdb.db.utils.SchemaUtils; import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType; @@ -152,7 +152,6 @@ public class PhysicalGenerator { @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity warning private PhysicalPlan doTransformation(Operator operator, int fetchSize) throws QueryProcessException { - List<PartialPath> paths; switch (operator.getType()) { case AUTHOR: AuthorOperator author = (AuthorOperator) operator; @@ -211,13 +210,13 @@ public class PhysicalGenerator { case CREATE_INDEX: CreateIndexOperator createIndexOp = (CreateIndexOperator) operator; return new CreateIndexPlan( - createIndexOp.getSelectedPaths(), + createIndexOp.getPaths(), createIndexOp.getProps(), createIndexOp.getTime(), createIndexOp.getIndexType()); case DROP_INDEX: DropIndexOperator dropIndexOp = (DropIndexOperator) operator; - return new DropIndexPlan(dropIndexOp.getSelectedPaths(), dropIndexOp.getIndexType()); + return new DropIndexPlan(dropIndexOp.getPaths(), dropIndexOp.getIndexType()); case ALTER_TIMESERIES: AlterTimeSeriesOperator alterTimeSeriesOperator = (AlterTimeSeriesOperator) operator; return new AlterTimeSeriesPlan( @@ -229,11 +228,9 @@ public class PhysicalGenerator { alterTimeSeriesOperator.getAttributesMap()); case DELETE: DeleteDataOperator delete = (DeleteDataOperator) operator; - paths = delete.getSelectedPaths(); - return new DeletePlan(delete.getStartTime(), delete.getEndTime(), paths); + return new DeletePlan(delete.getStartTime(), delete.getEndTime(), delete.getPaths()); case INSERT: InsertOperator insert = (InsertOperator) operator; - paths = insert.getSelectedPaths(); int measurementsNum = 0; for (String measurement : insert.getMeasurementList()) { if (measurement.startsWith("(") && measurement.endsWith(")")) { @@ -250,7 +247,7 @@ public class PhysicalGenerator { } if (measurementsNum == insert.getValueList().length) { return new InsertRowPlan( - paths.get(0), + insert.getDevice(), insert.getTimes()[0], insert.getMeasurementList(), insert.getValueList()); @@ -259,7 +256,7 @@ public class PhysicalGenerator { for (int i = 0; i < insert.getTimes().length; i++) { insertRowsPlan.addOneInsertRowPlan( new InsertRowPlan( - paths.get(0), + insert.getDevice(), insert.getTimes()[i], insert.getMeasurementList(), Arrays.copyOfRange( @@ -458,17 +455,17 @@ public class PhysicalGenerator { return SchemaUtils.getSeriesTypesByPaths(paths); } - interface Transfrom { + interface Transform { QueryPlan transform(QueryOperator queryOperator) throws QueryProcessException; } /** agg physical plan transform */ - public static class AggPhysicalPlanRule implements Transfrom { + public static class AggPhysicalPlanRule implements Transform { @Override public QueryPlan transform(QueryOperator queryOperator) throws QueryProcessException { QueryPlan queryPlan; - if (queryOperator.hasUdf()) { + if (queryOperator.hasTimeSeriesGeneratingFunction()) { throw new QueryProcessException( "User-defined and built-in hybrid aggregation is not supported."); } @@ -480,7 +477,7 @@ public class PhysicalGenerator { queryPlan = new AggregationPlan(); } ((AggregationPlan) queryPlan) - .setAggregations(queryOperator.getSelectOperator().getAggregations()); + .setAggregations(queryOperator.getSelectOperator().getAggregationFunctions()); if (queryOperator.isGroupByTime()) { GroupByTimePlan groupByTimePlan = (GroupByTimePlan) queryPlan; @@ -519,11 +516,11 @@ public class PhysicalGenerator { } /** fill physical plan transfrom */ - public static class FillPhysicalPlanRule implements Transfrom { + public static class FillPhysicalPlanRule implements Transform { @Override public QueryPlan transform(QueryOperator queryOperator) throws QueryProcessException { - if (queryOperator.hasUdf()) { + if (queryOperator.hasTimeSeriesGeneratingFunction()) { throw new QueryProcessException("Fill functions are not supported in UDF queries."); } FillQueryPlan queryPlan = new FillQueryPlan(); @@ -542,7 +539,7 @@ public class PhysicalGenerator { private PhysicalPlan transformQuery(QueryOperator queryOperator) throws QueryProcessException { QueryPlan queryPlan = null; - if (queryOperator.hasAggregation()) { + if (queryOperator.hasAggregationFunction()) { queryPlan = new AggPhysicalPlanRule().transform(queryOperator); } else if (queryOperator.isFill()) { queryPlan = new FillPhysicalPlanRule().transform(queryOperator); @@ -550,9 +547,10 @@ public class PhysicalGenerator { queryPlan = new LastQueryPlan(); } else if (queryOperator.getIndexType() != null) { queryPlan = new QueryIndexPlan(); - } else if (queryOperator.hasUdf()) { + } else if (queryOperator.hasTimeSeriesGeneratingFunction()) { queryPlan = new UDTFPlan(queryOperator.getSelectOperator().getZoneId()); - ((UDTFPlan) queryPlan).constructUdfExecutors(queryOperator.getSelectOperator().getUdfList()); + ((UDTFPlan) queryPlan) + .constructUdfExecutors(queryOperator.getSelectOperator().getResultColumns()); } else { queryPlan = new RawDataQueryPlan(); } @@ -560,7 +558,7 @@ public class PhysicalGenerator { if (queryOperator.isAlignByDevice()) { queryPlan = getAlignQueryPlan(queryOperator, queryPlan); } else { - queryPlan.setPaths(queryOperator.getSelectedPaths()); + queryPlan.setPaths(queryOperator.getSelectOperator().getPaths()); // Last query result set will not be affected by alignment if (queryPlan instanceof LastQueryPlan && !queryOperator.isAlignByTime()) { throw new QueryProcessException("Disable align cannot be applied to LAST query."); @@ -626,8 +624,8 @@ public class PhysicalGenerator { List<PartialPath> prefixPaths = queryOperator.getFromOperator().getPrefixPaths(); // remove stars in fromPaths and get deviceId with deduplication List<PartialPath> devices = this.removeStarsInDeviceWithUnique(prefixPaths); - List<PartialPath> suffixPaths = queryOperator.getSelectOperator().getSuffixPaths(); - List<String> originAggregations = queryOperator.getSelectOperator().getAggregations(); + List<PartialPath> suffixPaths = queryOperator.getSelectOperator().getPaths(); + List<String> originAggregations = queryOperator.getSelectOperator().getAggregationFunctions(); // to record result measurement columns List<String> measurements = new ArrayList<>(); @@ -886,9 +884,10 @@ public class PhysicalGenerator { if (path != null) { // non-udf indexedPaths.add(new Pair<>(paths.get(i), i)); } else { // udf - UDFContext context = - ((UDTFPlan) queryPlan).getExecutorByOriginalOutputColumnIndex(i).getContext(); - for (PartialPath udfPath : context.getPaths()) { + FunctionExpression functionExpression = + (FunctionExpression) + ((UDTFPlan) queryPlan).getExecutorByOriginalOutputColumnIndex(i).getExpression(); + for (PartialPath udfPath : functionExpression.getPaths()) { indexedPaths.add(new Pair<>(udfPath, i)); } } @@ -984,12 +983,12 @@ public class PhysicalGenerator { private static boolean verifyAllAggregationDataTypesEqual(QueryOperator queryOperator) throws MetadataException { - List<String> aggregations = queryOperator.getSelectOperator().getAggregations(); + List<String> aggregations = queryOperator.getSelectOperator().getAggregationFunctions(); if (aggregations.isEmpty()) { return true; } - List<PartialPath> paths = queryOperator.getSelectedPaths(); + List<PartialPath> paths = queryOperator.getSelectOperator().getPaths(); List<TSDataType> dataTypes = SchemaUtils.getSeriesTypesByPaths(paths); String aggType = aggregations.get(0); switch (aggType) { diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java index 0991328..ff75491 100644 --- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java +++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ConcatPathOptimizer.java @@ -105,7 +105,7 @@ public class ConcatPathOptimizer implements ILogicalOptimizer { ((QueryOperator) operator).getIndexType() == null); } else { isAlignByDevice = true; - if (((QueryOperator) operator).hasUdf()) { + if (((QueryOperator) operator).hasTimeSeriesGeneratingFunction()) { throw new LogicalOptimizeException( "ALIGN BY DEVICE clause is not supported in UDF queries."); } diff --git a/server/src/main/java/org/apache/iotdb/db/query/dataset/UDTFDataSet.java b/server/src/main/java/org/apache/iotdb/db/query/dataset/UDTFDataSet.java index 5761ef2..19d81c6 100644 --- a/server/src/main/java/org/apache/iotdb/db/query/dataset/UDTFDataSet.java +++ b/server/src/main/java/org/apache/iotdb/db/query/dataset/UDTFDataSet.java @@ -163,7 +163,7 @@ public abstract class UDTFDataSet extends QueryDataSet { } private int[] calculateReaderIndexes(UDTFExecutor executor) { - List<PartialPath> paths = executor.getContext().getPaths(); + List<PartialPath> paths = executor.getExpression().getPaths(); int[] readerIndexes = new int[paths.size()]; for (int i = 0; i < readerIndexes.length; ++i) { readerIndexes[i] = udtfPlan.getReaderIndex(paths.get(i).getFullPath()); diff --git a/server/src/main/java/org/apache/iotdb/db/query/expression/Expression.java b/server/src/main/java/org/apache/iotdb/db/query/expression/Expression.java index e4d06d2..dc2700e 100644 --- a/server/src/main/java/org/apache/iotdb/db/query/expression/Expression.java +++ b/server/src/main/java/org/apache/iotdb/db/query/expression/Expression.java @@ -22,7 +22,18 @@ package org.apache.iotdb.db.query.expression; import org.apache.iotdb.db.exception.metadata.MetadataException; import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType; -public interface Expression { +public abstract class Expression { - TSDataType dataType() throws MetadataException; + protected boolean isAggregationFunctionExpression = false; + protected boolean isTimeSeriesGeneratingFunctionExpression = false; + + public boolean isAggregationFunctionExpression() { + return isAggregationFunctionExpression; + } + + public boolean isTimeSeriesGeneratingFunctionExpression() { + return isTimeSeriesGeneratingFunctionExpression; + } + + public abstract TSDataType dataType() throws MetadataException; } diff --git a/server/src/main/java/org/apache/iotdb/db/query/expression/ResultColumn.java b/server/src/main/java/org/apache/iotdb/db/query/expression/ResultColumn.java index e62350e..482d3b5 100644 --- a/server/src/main/java/org/apache/iotdb/db/query/expression/ResultColumn.java +++ b/server/src/main/java/org/apache/iotdb/db/query/expression/ResultColumn.java @@ -29,6 +29,11 @@ public class ResultColumn { this.alias = alias; } + public ResultColumn(Expression expression) { + this.expression = expression; + alias = null; + } + public Expression getExpression() { return expression; } diff --git a/server/src/main/java/org/apache/iotdb/db/query/expression/binary/BinaryExpression.java b/server/src/main/java/org/apache/iotdb/db/query/expression/binary/BinaryExpression.java index 1106eac..741e3f5 100644 --- a/server/src/main/java/org/apache/iotdb/db/query/expression/binary/BinaryExpression.java +++ b/server/src/main/java/org/apache/iotdb/db/query/expression/binary/BinaryExpression.java @@ -22,9 +22,9 @@ package org.apache.iotdb.db.query.expression.binary; import org.apache.iotdb.db.query.expression.Expression; import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType; -public abstract class BinaryExpression implements Expression { +public abstract class BinaryExpression extends Expression { - public BinaryExpression(Expression leftExpression, Expression rightExpression) { + protected BinaryExpression(Expression leftExpression, Expression rightExpression) { this.leftExpression = leftExpression; this.rightExpression = rightExpression; } diff --git a/server/src/main/java/org/apache/iotdb/db/query/expression/unary/FunctionExpression.java b/server/src/main/java/org/apache/iotdb/db/query/expression/unary/FunctionExpression.java index af6186c..ab3bf3e 100644 --- a/server/src/main/java/org/apache/iotdb/db/query/expression/unary/FunctionExpression.java +++ b/server/src/main/java/org/apache/iotdb/db/query/expression/unary/FunctionExpression.java @@ -20,6 +20,8 @@ package org.apache.iotdb.db.query.expression.unary; import org.apache.iotdb.db.exception.metadata.MetadataException; +import org.apache.iotdb.db.metadata.PartialPath; +import org.apache.iotdb.db.qp.constant.SQLConstant; import org.apache.iotdb.db.query.expression.Expression; import org.apache.iotdb.tsfile.exception.NotImplementedException; import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType; @@ -31,13 +33,14 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; -public class FunctionExpression implements Expression { +public class FunctionExpression extends Expression { private final String functionName; private final Map<String, String> functionAttributes; private List<Expression> expressions; private List<TSDataType> dataTypes; + private List<PartialPath> paths; private String expressionString; private String parametersString; @@ -46,13 +49,23 @@ public class FunctionExpression implements Expression { this.functionName = functionName; functionAttributes = new LinkedHashMap<>(); expressions = new ArrayList<>(); + setFunctionExpressionType(); } - public FunctionExpression(String functionName, Map<String, String> functionAttributes, - List<Expression> expressions) { + public FunctionExpression( + String functionName, Map<String, String> functionAttributes, List<Expression> expressions) { this.functionName = functionName; this.functionAttributes = functionAttributes; this.expressions = expressions; + setFunctionExpressionType(); + } + + private void setFunctionExpressionType() { + if (SQLConstant.getNativeFunctionNames().contains(functionName.toLowerCase())) { + isAggregationFunctionExpression = true; + } else { + isTimeSeriesGeneratingFunctionExpression = true; + } } public void addAttribute(String key, String value) { @@ -95,23 +108,35 @@ public class FunctionExpression implements Expression { return dataTypes; } + // TODO: remove this method + public List<PartialPath> getPaths() { + if (paths == null) { + paths = new ArrayList<>(); + for (Expression expression : expressions) { + paths.add(((TimeSeriesOperand) expression).getPath()); + } + } + return paths; + } + @Override public String toString() { if (expressionString == null) { - expressionString = functionName + "(" + parametersString() + ")"; + expressionString = functionName + "(" + getParametersString() + ")"; } return expressionString; } /** - * Generates the parameter part of the udf column name. + * Generates the parameter part of the function column name. * * <p>Example: - * Full column name -> udf(root.sg.d.s1, sin(root.sg.d.s1), 'key1'='value1', 'key2'='value2') - * <p> - * The parameter part -> root.sg.d.s1, sin(root.sg.d.s1), 'key1'='value1', 'key2'='value2' + * + * <p>Full column name -> udf(root.sg.d.s1, sin(root.sg.d.s1), 'key1'='value1', 'key2'='value2') + * + * <p>The parameter part -> root.sg.d.s1, sin(root.sg.d.s1), 'key1'='value1', 'key2'='value2' */ - private String parametersString() { + public String getParametersString() { if (parametersString == null) { StringBuilder builder = new StringBuilder(); if (!expressions.isEmpty()) { diff --git a/server/src/main/java/org/apache/iotdb/db/query/expression/unary/MinusExpression.java b/server/src/main/java/org/apache/iotdb/db/query/expression/unary/MinusExpression.java index 965e3c0..6a3145b 100644 --- a/server/src/main/java/org/apache/iotdb/db/query/expression/unary/MinusExpression.java +++ b/server/src/main/java/org/apache/iotdb/db/query/expression/unary/MinusExpression.java @@ -23,7 +23,7 @@ import org.apache.iotdb.db.exception.metadata.MetadataException; import org.apache.iotdb.db.query.expression.Expression; import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType; -public class MinusExpression implements Expression { +public class MinusExpression extends Expression { protected Expression expression; diff --git a/server/src/main/java/org/apache/iotdb/db/query/expression/unary/NumberLiteralOperand.java b/server/src/main/java/org/apache/iotdb/db/query/expression/unary/NumberLiteralOperand.java index 8405947..7eaf306 100644 --- a/server/src/main/java/org/apache/iotdb/db/query/expression/unary/NumberLiteralOperand.java +++ b/server/src/main/java/org/apache/iotdb/db/query/expression/unary/NumberLiteralOperand.java @@ -22,7 +22,7 @@ package org.apache.iotdb.db.query.expression.unary; import org.apache.iotdb.db.query.expression.Expression; import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType; -public class NumberLiteralOperand implements Expression { +public class NumberLiteralOperand extends Expression { protected double literal; diff --git a/server/src/main/java/org/apache/iotdb/db/query/expression/unary/TimeSeriesOperand.java b/server/src/main/java/org/apache/iotdb/db/query/expression/unary/TimeSeriesOperand.java index c72a4b2..bc4e635 100644 --- a/server/src/main/java/org/apache/iotdb/db/query/expression/unary/TimeSeriesOperand.java +++ b/server/src/main/java/org/apache/iotdb/db/query/expression/unary/TimeSeriesOperand.java @@ -25,7 +25,7 @@ import org.apache.iotdb.db.query.expression.Expression; import org.apache.iotdb.db.service.IoTDB; import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType; -public class TimeSeriesOperand implements Expression { +public class TimeSeriesOperand extends Expression { protected PartialPath path; protected TSDataType dataType; diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/core/context/UDFContext.java b/server/src/main/java/org/apache/iotdb/db/query/udf/core/context/UDFContext.java deleted file mode 100644 index 00e294e..0000000 --- a/server/src/main/java/org/apache/iotdb/db/query/udf/core/context/UDFContext.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.iotdb.db.query.udf.core.context; - -import org.apache.iotdb.db.exception.metadata.MetadataException; -import org.apache.iotdb.db.metadata.PartialPath; -import org.apache.iotdb.db.service.IoTDB; -import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -public class UDFContext { - - private final String name; - private final Map<String, String> attributes; - - private List<PartialPath> paths; - private List<TSDataType> dataTypes; - - private String columnParameterPart; - private String column; - - public UDFContext(String name) { - this.name = name; - attributes = new LinkedHashMap<>(); - paths = new ArrayList<>(); - } - - public UDFContext(String name, Map<String, String> attributes, List<PartialPath> paths) { - this.name = name; - this.attributes = attributes; - this.paths = paths; - } - - public void addAttribute(String key, String value) { - attributes.put(key, value); - } - - public void addPath(PartialPath path) { - paths.add(path); - } - - public void setPaths(List<PartialPath> paths) { - this.paths = paths; - } - - public String getName() { - return name; - } - - public Map<String, String> getAttributes() { - return attributes; - } - - public List<PartialPath> getPaths() { - return paths; - } - - public List<TSDataType> getDataTypes() throws MetadataException { - if (dataTypes == null) { - dataTypes = new ArrayList<>(); - for (PartialPath path : paths) { - dataTypes.add(IoTDB.metaManager.getSeriesType(path)); - } - } - return dataTypes; - } - - /** Generates the column name of the udf query. */ - public String getColumnName() { - if (column == null) { - column = name + "(" + getColumnNameParameterPart() + ")"; - } - return column; - } - - /** - * Generates the parameter part of the udf column name. - * - * <p>Example: <br> - * Full column name -> udf(root.sg.d.s1, root.sg.d.s1, 'key1'='value1', 'key2'='value2') <br> - * The parameter part -> root.sg.d.s1, root.sg.d.s1, 'key1'='value1', 'key2'='value2' - */ - private String getColumnNameParameterPart() { - if (columnParameterPart == null) { - StringBuilder builder = new StringBuilder(); - if (!paths.isEmpty()) { - builder.append(paths.get(0).getFullPath()); - for (int i = 1; i < paths.size(); ++i) { - builder.append(", ").append(paths.get(i).getFullPath()); - } - } - if (!attributes.isEmpty()) { - if (!paths.isEmpty()) { - builder.append(", "); - } - Iterator<Entry<String, String>> iterator = attributes.entrySet().iterator(); - Entry<String, String> entry = iterator.next(); - builder - .append("\"") - .append(entry.getKey()) - .append("\"=\"") - .append(entry.getValue()) - .append("\""); - while (iterator.hasNext()) { - entry = iterator.next(); - builder - .append(", ") - .append("\"") - .append(entry.getKey()) - .append("\"=\"") - .append(entry.getValue()) - .append("\""); - } - } - columnParameterPart = builder.toString(); - } - return columnParameterPart; - } -} diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/core/executor/UDTFExecutor.java b/server/src/main/java/org/apache/iotdb/db/query/udf/core/executor/UDTFExecutor.java index 9d69582..59b0a2d 100644 --- a/server/src/main/java/org/apache/iotdb/db/query/udf/core/executor/UDTFExecutor.java +++ b/server/src/main/java/org/apache/iotdb/db/query/udf/core/executor/UDTFExecutor.java @@ -20,13 +20,13 @@ package org.apache.iotdb.db.query.udf.core.executor; import org.apache.iotdb.db.exception.query.QueryProcessException; +import org.apache.iotdb.db.query.expression.unary.FunctionExpression; import org.apache.iotdb.db.query.udf.api.UDTF; import org.apache.iotdb.db.query.udf.api.access.Row; import org.apache.iotdb.db.query.udf.api.access.RowWindow; import org.apache.iotdb.db.query.udf.api.customizer.config.UDTFConfigurations; import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameterValidator; import org.apache.iotdb.db.query.udf.api.customizer.parameter.UDFParameters; -import org.apache.iotdb.db.query.udf.core.context.UDFContext; import org.apache.iotdb.db.query.udf.datastructure.tv.ElasticSerializableTVList; import org.apache.iotdb.db.query.udf.service.UDFRegistrationService; @@ -34,21 +34,22 @@ import java.time.ZoneId; public class UDTFExecutor { - protected final UDFContext context; + protected final FunctionExpression expression; protected final UDTFConfigurations configurations; protected UDTF udtf; protected ElasticSerializableTVList collector; - public UDTFExecutor(UDFContext context, ZoneId zoneId) { - this.context = context; + public UDTFExecutor(FunctionExpression expression, ZoneId zoneId) { + this.expression = expression; configurations = new UDTFConfigurations(zoneId); } public void beforeStart(long queryId, float collectorMemoryBudgetInMB) throws QueryProcessException { - udtf = (UDTF) UDFRegistrationService.getInstance().reflect(context); + udtf = (UDTF) UDFRegistrationService.getInstance().reflect(expression); - UDFParameters parameters = new UDFParameters(context.getPaths(), context.getAttributes()); + UDFParameters parameters = + new UDFParameters(expression.getPaths(), expression.getFunctionAttributes()); try { udtf.validate(new UDFParameterValidator(parameters)); @@ -103,8 +104,8 @@ public class UDTFExecutor { + e); } - public UDFContext getContext() { - return context; + public FunctionExpression getExpression() { + return expression; } public UDTFConfigurations getConfigurations() { diff --git a/server/src/main/java/org/apache/iotdb/db/query/udf/service/UDFRegistrationService.java b/server/src/main/java/org/apache/iotdb/db/query/udf/service/UDFRegistrationService.java index 88ceaba..bc680c5 100644 --- a/server/src/main/java/org/apache/iotdb/db/query/udf/service/UDFRegistrationService.java +++ b/server/src/main/java/org/apache/iotdb/db/query/udf/service/UDFRegistrationService.java @@ -25,9 +25,9 @@ import org.apache.iotdb.db.exception.StartupException; import org.apache.iotdb.db.exception.UDFRegistrationException; import org.apache.iotdb.db.exception.query.QueryProcessException; import org.apache.iotdb.db.qp.constant.SQLConstant; +import org.apache.iotdb.db.query.expression.unary.FunctionExpression; import org.apache.iotdb.db.query.udf.api.UDF; import org.apache.iotdb.db.query.udf.builtin.BuiltinFunction; -import org.apache.iotdb.db.query.udf.core.context.UDFContext; import org.apache.iotdb.db.service.IService; import org.apache.iotdb.db.service.ServiceType; import org.apache.iotdb.db.utils.TestOnly; @@ -249,8 +249,8 @@ public class UDFRegistrationService implements IService { } } - public UDF reflect(UDFContext context) throws QueryProcessException { - String functionName = context.getName().toUpperCase(); + public UDF reflect(FunctionExpression expression) throws QueryProcessException { + String functionName = expression.getFunctionName().toUpperCase(); UDFRegistrationInformation information = registrationInformation.get(functionName); if (information == null) { String errorMessage = diff --git a/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java b/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java index f7b619a..0637aa2 100644 --- a/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java +++ b/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java @@ -1042,10 +1042,7 @@ public class TSServiceImpl implements TSIService.Iface, ServerContext { respColumns.add( paths.get(i) != null ? paths.get(i).getFullPath() - : udtfPlan - .getExecutorByOriginalOutputColumnIndex(i) - .getContext() - .getColumnName()); + : udtfPlan.getExecutorByOriginalOutputColumnIndex(i).getExpression().toString()); seriesTypes.add( paths.get(i) != null ? udtfPlan.getDataTypes().get(i) diff --git a/server/src/test/java/org/apache/iotdb/db/qp/logical/IndexLogicalPlanTest.java b/server/src/test/java/org/apache/iotdb/db/qp/logical/IndexLogicalPlanTest.java index 1e09934..05e7d0a 100644 --- a/server/src/test/java/org/apache/iotdb/db/qp/logical/IndexLogicalPlanTest.java +++ b/server/src/test/java/org/apache/iotdb/db/qp/logical/IndexLogicalPlanTest.java @@ -116,7 +116,7 @@ public class IndexLogicalPlanTest { Assert.assertEquals(QueryOperator.class, op.getClass()); QueryOperator queryOperator = (QueryOperator) op; Assert.assertEquals(OperatorType.QUERY, queryOperator.getType()); - Assert.assertEquals("Glu", queryOperator.getSelectedPaths().get(0).getFullPath()); + Assert.assertEquals("Glu", queryOperator.getExpressions().get(0).getFullPath()); Assert.assertEquals( "root.Ery.*", queryOperator.getFromOperator().getPrefixPaths().get(0).getFullPath()); Assert.assertEquals(IndexType.RTREE_PAA, queryOperator.getIndexType()); @@ -138,7 +138,7 @@ public class IndexLogicalPlanTest { Assert.assertEquals(QueryOperator.class, op.getClass()); QueryOperator queryOperator = (QueryOperator) op; Assert.assertEquals(OperatorType.QUERY, queryOperator.getType()); - Assert.assertEquals("Speed", queryOperator.getSelectedPaths().get(0).getFullPath()); + Assert.assertEquals("Speed", queryOperator.getExpressions().get(0).getFullPath()); Assert.assertEquals( "root.Wind.AZQ02", queryOperator.getFromOperator().getPrefixPaths().get(0).getFullPath()); Assert.assertEquals(IndexType.ELB_INDEX, queryOperator.getIndexType()); diff --git a/server/src/test/java/org/apache/iotdb/db/qp/logical/LogicalPlanSmallTest.java b/server/src/test/java/org/apache/iotdb/db/qp/logical/LogicalPlanSmallTest.java index e384edd..218bf7d 100644 --- a/server/src/test/java/org/apache/iotdb/db/qp/logical/LogicalPlanSmallTest.java +++ b/server/src/test/java/org/apache/iotdb/db/qp/logical/LogicalPlanSmallTest.java @@ -247,7 +247,7 @@ public class LogicalPlanSmallTest { Assert.assertEquals(QueryOperator.class, operator.getClass()); ArrayList<PartialPath> paths = new ArrayList<>(); paths.add(new PartialPath("*")); - Assert.assertEquals(paths, ((QueryOperator) operator).getSelectedPaths()); + Assert.assertEquals(paths, ((QueryOperator) operator).getExpressions()); } @Test diff --git a/server/src/test/java/org/apache/iotdb/db/query/dataset/UDTFAlignByTimeDataSetTest.java b/server/src/test/java/org/apache/iotdb/db/query/dataset/UDTFAlignByTimeDataSetTest.java index f879746..f8b8c50 100644 --- a/server/src/test/java/org/apache/iotdb/db/query/dataset/UDTFAlignByTimeDataSetTest.java +++ b/server/src/test/java/org/apache/iotdb/db/query/dataset/UDTFAlignByTimeDataSetTest.java @@ -171,7 +171,10 @@ public class UDTFAlignByTimeDataSetTest { Path path = queryPlan.getPaths().get(i); String columnName = path == null - ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getContext().getColumnName() + ? queryPlan + .getExecutorByOriginalOutputColumnIndex(i) + .getExpression() + .getColumnName() : path.getFullPath(); originalIndex2FieldIndex.add(path2Index.get(columnName)); } @@ -233,7 +236,10 @@ public class UDTFAlignByTimeDataSetTest { Path path = queryPlan.getPaths().get(i); String columnName = path == null - ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getContext().getColumnName() + ? queryPlan + .getExecutorByOriginalOutputColumnIndex(i) + .getExpression() + .getColumnName() : path.getFullPath(); originalIndex2FieldIndex.add(path2Index.get(columnName)); } @@ -280,7 +286,10 @@ public class UDTFAlignByTimeDataSetTest { Path path = queryPlan.getPaths().get(i); String columnName = path == null - ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getContext().getColumnName() + ? queryPlan + .getExecutorByOriginalOutputColumnIndex(i) + .getExpression() + .getColumnName() : path.getFullPath(); originalIndex2FieldIndex.add(path2Index.get(columnName)); } @@ -339,7 +348,10 @@ public class UDTFAlignByTimeDataSetTest { Path path = queryPlan.getPaths().get(i); String columnName = path == null - ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getContext().getColumnName() + ? queryPlan + .getExecutorByOriginalOutputColumnIndex(i) + .getExpression() + .getColumnName() : path.getFullPath(); originalIndex2FieldIndex.add(path2Index.get(columnName)); } @@ -412,7 +424,10 @@ public class UDTFAlignByTimeDataSetTest { Path path = queryPlan.getPaths().get(i); String columnName = path == null - ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getContext().getColumnName() + ? queryPlan + .getExecutorByOriginalOutputColumnIndex(i) + .getExpression() + .getColumnName() : path.getFullPath(); originalIndex2FieldIndex.add(path2Index.get(columnName)); } @@ -468,7 +483,10 @@ public class UDTFAlignByTimeDataSetTest { Path path = queryPlan.getPaths().get(i); String columnName = path == null - ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getContext().getColumnName() + ? queryPlan + .getExecutorByOriginalOutputColumnIndex(i) + .getExpression() + .getColumnName() : path.getFullPath(); originalIndex2FieldIndex.add(path2Index.get(columnName)); } @@ -533,7 +551,10 @@ public class UDTFAlignByTimeDataSetTest { Path path = queryPlan.getPaths().get(i); String columnName = path == null - ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getContext().getColumnName() + ? queryPlan + .getExecutorByOriginalOutputColumnIndex(i) + .getExpression() + .getColumnName() : path.getFullPath(); originalIndex2FieldIndex.add(path2Index.get(columnName)); } @@ -604,7 +625,10 @@ public class UDTFAlignByTimeDataSetTest { Path path = queryPlan.getPaths().get(i); String columnName = path == null - ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getContext().getColumnName() + ? queryPlan + .getExecutorByOriginalOutputColumnIndex(i) + .getExpression() + .getColumnName() : path.getFullPath(); originalIndex2FieldIndex.add(path2Index.get(columnName)); } @@ -657,7 +681,10 @@ public class UDTFAlignByTimeDataSetTest { Path path = queryPlan.getPaths().get(i); String columnName = path == null - ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getContext().getColumnName() + ? queryPlan + .getExecutorByOriginalOutputColumnIndex(i) + .getExpression() + .getColumnName() : path.getFullPath(); originalIndex2FieldIndex.add(path2Index.get(columnName)); }
