You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by li...@apache.org on 2021/05/25 10:23:28 UTC
[iotdb] branch master updated: [IOTDB-1022] ANTLR Grammar & Logical
Operator for Arithmetic Operations and Nested Operations in SELECT Clauses
(#3236)
This is an automated email from the ASF dual-hosted git repository.
liudw pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new dae1f15 [IOTDB-1022] ANTLR Grammar & Logical Operator for Arithmetic Operations and Nested Operations in SELECT Clauses (#3236)
dae1f15 is described below
commit dae1f152ac19771b221f66cffe2e0b77d505c436
Author: Steve Yurong Su <st...@outlook.com>
AuthorDate: Tue May 25 05:22:58 2021 -0500
[IOTDB-1022] ANTLR Grammar & Logical Operator for Arithmetic Operations and Nested Operations in SELECT Clauses (#3236)
---
.../antlr4/org/apache/iotdb/db/qp/sql/SqlBase.g4 | 131 ++-----
.../cluster/query/ClusterPhysicalGenerator.java | 8 +-
.../apache/iotdb/cluster/query/ClusterPlanner.java | 43 ++-
.../query/ClusterPhysicalGeneratorTest.java | 10 +-
.../org/apache/iotdb/db/metadata/MManager.java | 3 -
.../org/apache/iotdb/db/metadata/PartialPath.java | 14 -
.../main/java/org/apache/iotdb/db/qp/Planner.java | 186 ++--------
.../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 | 44 ++-
.../iotdb/db/qp/logical/crud/SFWOperator.java | 98 -----
.../iotdb/db/qp/logical/crud/SelectOperator.java | 118 +++---
.../db/qp/logical/sys/CreateIndexOperator.java | 17 +-
.../iotdb/db/qp/logical/sys/DropIndexOperator.java | 18 +-
.../iotdb/db/qp/physical/crud/AggregationPlan.java | 6 +-
.../db/qp/physical/crud/AlignByDevicePlan.java | 6 +
.../iotdb/db/qp/physical/crud/LastQueryPlan.java | 30 +-
.../iotdb/db/qp/physical/crud/QueryPlan.java | 24 +-
.../db/qp/physical/crud/RawDataQueryPlan.java | 67 ++++
.../apache/iotdb/db/qp/physical/crud/UDFPlan.java | 4 +-
.../apache/iotdb/db/qp/physical/crud/UDTFPlan.java | 83 ++++-
.../apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java | 276 ++++++--------
.../iotdb/db/qp/strategy/LogicalChecker.java | 108 ++++++
.../iotdb/db/qp/strategy/LogicalGenerator.java | 63 +++-
.../iotdb/db/qp/strategy/PhysicalGenerator.java | 195 +++-------
.../qp/strategy/optimizer/ConcatPathOptimizer.java | 406 ++++-----------------
.../qp/strategy/optimizer/ILogicalOptimizer.java | 2 +-
.../qp/strategy/optimizer/RemoveNotOptimizer.java | 7 +-
.../apache/iotdb/db/qp/utils/WildcardsRemover.java | 160 ++++++++
.../apache/iotdb/db/query/dataset/UDTFDataSet.java | 2 +-
.../iotdb/db/query/executor/LastQueryExecutor.java | 12 +-
.../iotdb/db/query/expression/Expression.java | 31 +-
.../iotdb/db/query/expression/ResultColumn.java | 139 +++++++
.../expression/binary/AdditionExpression.java} | 21 +-
.../query/expression/binary/BinaryExpression.java | 118 ++++++
.../expression/binary/DivisionExpression.java} | 21 +-
.../expression/binary/ModuloExpression.java} | 21 +-
.../binary/MultiplicationExpression.java | 19 +-
.../expression/binary/SubtractionExpression.java} | 21 +-
.../query/expression/unary/FunctionExpression.java | 232 ++++++++++++
.../db/query/expression/unary/MinusExpression.java | 78 ++++
.../query/expression/unary/TimeSeriesOperand.java | 82 +++++
.../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 | 43 +--
.../iotdb/db/integration/IoTDBUDFManagementIT.java | 10 +-
.../db/integration/IoTDBUDTFHybridQueryIT.java | 3 +-
.../iotdb/db/qp/logical/IndexLogicalPlanTest.java | 48 ++-
.../iotdb/db/qp/logical/LogicalPlanSmallTest.java | 88 ++---
.../query/dataset/UDTFAlignByTimeDataSetTest.java | 18 +-
.../zeppelin/iotdb/IoTDBInterpreterTest.java | 27 +-
53 files changed, 1874 insertions(+), 1485 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 c7507ec..5ce6135 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
@@ -103,71 +103,30 @@ statement
| START TRIGGER triggerName=ID #startTrigger
| STOP TRIGGER triggerName=ID #stopTrigger
| SHOW TRIGGERS #showTriggers
- | SELECT topClause? selectElements
- fromClause
- whereClause?
- specialClause? #selectStatement
+ | selectClause fromClause whereClause? specialClause? #selectStatement
;
-selectElements
- : aggregationCall (COMMA aggregationCall)* #aggregationElement
- | tableCall (COMMA tableCall)* #tableElement
- | lastClause #lastElement
- | asClause (COMMA asClause)* #asElement
- | functionAsClause (COMMA functionAsClause)* #functionAsElement
- ;
-
-aggregationCall
- : builtInFunctionCall
- | udfCall
- ;
-
-tableCall
- : suffixPath
- | udfCall
- | SINGLE_QUOTE_STRING_LITERAL
- ;
-
-udfCall
- : udfName=ID LR_BRACKET udfSuffixPaths udfAttribute* RR_BRACKET
- ;
-
-udfSuffixPaths
- : suffixPath (COMMA suffixPath)*
- ;
-
-udfAttribute
- : COMMA udfAttributeKey=stringLiteral OPERATOR_EQ udfAttributeValue=stringLiteral
- ;
-
-builtInFunctionCall
- : functionName LR_BRACKET suffixPath RR_BRACKET
- ;
-
-functionName
- : MIN_TIME
- | MAX_TIME
- | MIN_VALUE
- | MAX_VALUE
- | COUNT
- | AVG
- | FIRST_VALUE
- | SUM
- | LAST_VALUE
- ;
+selectClause
+ : SELECT (LAST | topClause)? resultColumn (COMMA resultColumn)*
+ ;
-functionAsClause
- : builtInFunctionCall (AS ID)?
- ;
+resultColumn
+ : expression (AS ID)?
+ ;
-lastClause
- : LAST suffixPath (COMMA suffixPath)*
- | LAST asClause (COMMA asClause)*
- ;
+expression
+ : LR_BRACKET unary=expression RR_BRACKET
+ | (PLUS | MINUS) unary=expression
+ | leftExpression=expression (STAR | DIV | MOD) rightExpression=expression
+ | leftExpression=expression (PLUS | MINUS) rightExpression=expression
+ | functionName=suffixPath LR_BRACKET expression (COMMA expression)* functionAttribute* RR_BRACKET
+ | suffixPath
+ | literal=SINGLE_QUOTE_STRING_LITERAL
+ ;
-asClause
- : suffixPath (AS ID)?
- ;
+functionAttribute
+ : COMMA functionAttributeKey=stringLiteral OPERATOR_EQ functionAttributeValue=stringLiteral
+ ;
alias
: LR_BRACKET ID RR_BRACKET
@@ -523,14 +482,6 @@ nodeName
| COUNT
| NODES
| LEVEL
- | MIN_TIME
- | MAX_TIME
- | MIN_VALUE
- | MAX_VALUE
- | AVG
- | FIRST_VALUE
- | SUM
- | LAST_VALUE
| LAST
| DISABLE
| ALIGN
@@ -634,14 +585,6 @@ nodeNameWithoutStar
| COUNT
| NODES
| LEVEL
- | MIN_TIME
- | MAX_TIME
- | MIN_VALUE
- | MAX_VALUE
- | AVG
- | FIRST_VALUE
- | SUM
- | LAST_VALUE
| LAST
| DISABLE
| ALIGN
@@ -1101,38 +1044,6 @@ LEVEL
: L E V E L
;
-MIN_TIME
- : M I N UNDERLINE T I M E
- ;
-
-MAX_TIME
- : M A X UNDERLINE T I M E
- ;
-
-MIN_VALUE
- : M I N UNDERLINE V A L U E
- ;
-
-MAX_VALUE
- : M A X UNDERLINE V A L U E
- ;
-
-AVG
- : A V G
- ;
-
-FIRST_VALUE
- : F I R S T UNDERLINE V A L U E
- ;
-
-SUM
- : S U M
- ;
-
-LAST_VALUE
- : L A S T UNDERLINE V A L U E
- ;
-
LAST
: L A S T
;
@@ -1370,6 +1281,10 @@ MINUS : '-';
PLUS : '+';
+DIV : '/';
+
+MOD : '%';
+
DOT : '.';
LR_BRACKET : '(';
diff --git a/cluster/src/main/java/org/apache/iotdb/cluster/query/ClusterPhysicalGenerator.java b/cluster/src/main/java/org/apache/iotdb/cluster/query/ClusterPhysicalGenerator.java
index c074d92..9e5e740 100644
--- a/cluster/src/main/java/org/apache/iotdb/cluster/query/ClusterPhysicalGenerator.java
+++ b/cluster/src/main/java/org/apache/iotdb/cluster/query/ClusterPhysicalGenerator.java
@@ -26,7 +26,7 @@ import org.apache.iotdb.db.exception.metadata.MetadataException;
import org.apache.iotdb.db.exception.query.QueryProcessException;
import org.apache.iotdb.db.metadata.PartialPath;
import org.apache.iotdb.db.qp.logical.Operator;
-import org.apache.iotdb.db.qp.logical.crud.SFWOperator;
+import org.apache.iotdb.db.qp.logical.crud.QueryOperator;
import org.apache.iotdb.db.qp.logical.sys.LoadConfigurationOperator.LoadConfigurationOperatorType;
import org.apache.iotdb.db.qp.physical.PhysicalPlan;
import org.apache.iotdb.db.qp.physical.sys.LoadConfigurationPlan;
@@ -64,12 +64,12 @@ public class ClusterPhysicalGenerator extends PhysicalGenerator {
}
@Override
- protected List<TSDataType> getSeriesTypes(List<PartialPath> paths) throws MetadataException {
+ public List<TSDataType> getSeriesTypes(List<PartialPath> paths) throws MetadataException {
return getCMManager().getSeriesTypesByPaths(paths, null).left;
}
@Override
- protected Pair<List<PartialPath>, Map<String, Integer>> getSeriesSchema(List<PartialPath> paths)
+ public Pair<List<PartialPath>, Map<String, Integer>> getSeriesSchema(List<PartialPath> paths)
throws MetadataException {
return getCMManager().getSeriesSchemas(paths);
}
@@ -88,7 +88,7 @@ public class ClusterPhysicalGenerator extends PhysicalGenerator {
public PhysicalPlan transformToPhysicalPlan(Operator operator, int fetchSize)
throws QueryProcessException {
// update storage groups before parsing query plans
- if (operator instanceof SFWOperator) {
+ if (operator instanceof QueryOperator) {
try {
getCMManager().syncMetaLeader();
} catch (MetadataException e) {
diff --git a/cluster/src/main/java/org/apache/iotdb/cluster/query/ClusterPlanner.java b/cluster/src/main/java/org/apache/iotdb/cluster/query/ClusterPlanner.java
index ecbfb74..a2469ac 100644
--- a/cluster/src/main/java/org/apache/iotdb/cluster/query/ClusterPlanner.java
+++ b/cluster/src/main/java/org/apache/iotdb/cluster/query/ClusterPlanner.java
@@ -19,14 +19,14 @@
package org.apache.iotdb.cluster.query;
+import org.apache.iotdb.db.exception.metadata.IllegalPathException;
import org.apache.iotdb.db.exception.query.QueryProcessException;
import org.apache.iotdb.db.qp.Planner;
import org.apache.iotdb.db.qp.logical.Operator;
-import org.apache.iotdb.db.qp.logical.crud.SFWOperator;
import org.apache.iotdb.db.qp.physical.PhysicalPlan;
-import org.apache.iotdb.db.qp.strategy.PhysicalGenerator;
-import org.apache.iotdb.db.qp.strategy.optimizer.ConcatPathOptimizer;
-import org.apache.iotdb.db.query.control.QueryResourceManager;
+import org.apache.iotdb.db.qp.strategy.LogicalChecker;
+import org.apache.iotdb.db.qp.strategy.LogicalGenerator;
+import org.apache.iotdb.service.rpc.thrift.TSRawDataQueryReq;
import java.time.ZoneId;
@@ -36,23 +36,28 @@ public class ClusterPlanner extends Planner {
@Override
public PhysicalPlan parseSQLToPhysicalPlan(String sqlStr, ZoneId zoneId, int fetchSize)
throws QueryProcessException {
- Operator operator = logicalGenerator.generate(sqlStr, zoneId);
- int maxDeduplicatedPathNum =
- QueryResourceManager.getInstance().getMaxDeduplicatedPathNum(fetchSize);
- if (operator instanceof SFWOperator && ((SFWOperator) 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
- // set it to Integer.MAX_VALUE - 1
- maxDeduplicatedPathNum = Integer.MAX_VALUE - 1;
- }
- operator = logicalOptimize(operator, maxDeduplicatedPathNum);
- PhysicalGenerator physicalGenerator = new ClusterPhysicalGenerator();
- return physicalGenerator.transformToPhysicalPlan(operator, fetchSize);
+ // from SQL to logical operator
+ Operator operator = LogicalGenerator.generate(sqlStr, zoneId);
+ // check if there are logical errors
+ LogicalChecker.check(operator);
+ // optimize the logical operator
+ operator = logicalOptimize(operator, fetchSize);
+ // from logical operator to physical plan
+ return new ClusterPhysicalGenerator().transformToPhysicalPlan(operator, fetchSize);
}
@Override
- protected ConcatPathOptimizer getConcatPathOptimizer() {
- return new ClusterConcatPathOptimizer();
+ public PhysicalPlan rawDataQueryReqToPhysicalPlan(
+ TSRawDataQueryReq rawDataQueryReq, ZoneId zoneId)
+ throws IllegalPathException, QueryProcessException {
+ // from TSRawDataQueryReq to logical operator
+ Operator operator = LogicalGenerator.generate(rawDataQueryReq, zoneId);
+ // check if there are logical errors
+ LogicalChecker.check(operator);
+ // optimize the logical operator
+ operator = logicalOptimize(operator, rawDataQueryReq.fetchSize);
+ // from logical operator to physical plan
+ return new ClusterPhysicalGenerator()
+ .transformToPhysicalPlan(operator, rawDataQueryReq.fetchSize);
}
}
diff --git a/cluster/src/test/java/org/apache/iotdb/cluster/query/ClusterPhysicalGeneratorTest.java b/cluster/src/test/java/org/apache/iotdb/cluster/query/ClusterPhysicalGeneratorTest.java
index b6dc1f6..f1d7d57 100644
--- a/cluster/src/test/java/org/apache/iotdb/cluster/query/ClusterPhysicalGeneratorTest.java
+++ b/cluster/src/test/java/org/apache/iotdb/cluster/query/ClusterPhysicalGeneratorTest.java
@@ -28,11 +28,15 @@ 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.SelectOperator;
import org.apache.iotdb.db.qp.physical.crud.RawDataQueryPlan;
+import org.apache.iotdb.db.query.expression.ResultColumn;
+import org.apache.iotdb.db.query.expression.unary.TimeSeriesOperand;
import org.junit.Before;
import org.junit.Test;
import java.time.ZoneId;
+import java.util.ArrayList;
+import java.util.List;
import static org.junit.Assert.assertEquals;
@@ -53,7 +57,11 @@ public class ClusterPhysicalGeneratorTest extends BaseQueryTest {
SelectOperator selectOperator =
new SelectOperator(SQLConstant.TOK_SELECT, ZoneId.systemDefault());
- selectOperator.setSuffixPathList(pathList);
+ List<ResultColumn> resultColumns = new ArrayList<>();
+ for (PartialPath partialPath : pathList) {
+ resultColumns.add(new ResultColumn(new TimeSeriesOperand(partialPath)));
+ }
+ selectOperator.setResultColumns(resultColumns);
FromOperator fromOperator = new FromOperator(SQLConstant.TOK_FROM);
fromOperator.addPrefixTablePath(new PartialPath(TestUtils.getTestSg(0)));
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java b/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java
index 53fc126..098d40f 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java
@@ -1285,9 +1285,6 @@ public class MManager {
if (partialPath.isMeasurementAliasExists()) {
indexMap.put(partialPath.getFullPathWithAlias(), index);
}
- if (partialPath.isTsAliasExists()) {
- indexMap.put(partialPath.getTsAlias(), index);
- }
i++;
}
}
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/PartialPath.java b/server/src/main/java/org/apache/iotdb/db/metadata/PartialPath.java
index 54e4362..d95221b 100755
--- a/server/src/main/java/org/apache/iotdb/db/metadata/PartialPath.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/PartialPath.java
@@ -43,8 +43,6 @@ public class PartialPath extends Path implements Comparable<Path> {
protected String[] nodes;
// alias of measurement, null pointer cannot be serialized in thrift so empty string is instead
protected String measurementAlias = "";
- // alias of time series used in SELECT AS
- protected String tsAlias = "";
/**
* Construct the PartialPath using a String, will split the given String into String[] E.g., path
@@ -237,18 +235,6 @@ public class PartialPath extends Path implements Comparable<Path> {
return measurementAlias != null && !measurementAlias.isEmpty();
}
- public String getTsAlias() {
- return tsAlias;
- }
-
- public void setTsAlias(String tsAlias) {
- this.tsAlias = tsAlias;
- }
-
- public boolean isTsAliasExists() {
- return tsAlias != null && !tsAlias.isEmpty();
- }
-
@Override
public String getFullPathWithAlias() {
return getDevice() + IoTDBConstant.PATH_SEPARATOR + measurementAlias;
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..db4722a 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
@@ -23,120 +23,56 @@ import org.apache.iotdb.db.exception.query.LogicalOperatorException;
import org.apache.iotdb.db.exception.query.LogicalOptimizeException;
import org.apache.iotdb.db.exception.query.PathNumOverLimitException;
import org.apache.iotdb.db.exception.query.QueryProcessException;
-import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.qp.constant.SQLConstant;
import org.apache.iotdb.db.qp.logical.Operator;
-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.LogicalChecker;
import org.apache.iotdb.db.qp.strategy.LogicalGenerator;
import org.apache.iotdb.db.qp.strategy.PhysicalGenerator;
import org.apache.iotdb.db.qp.strategy.optimizer.ConcatPathOptimizer;
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.utils.TestOnly;
import org.apache.iotdb.service.rpc.thrift.TSRawDataQueryReq;
import java.time.ZoneId;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import static org.apache.iotdb.db.conf.IoTDBConstant.TIME;
+import static org.apache.iotdb.db.qp.logical.Operator.OperatorType.QUERY;
+import static org.apache.iotdb.db.qp.logical.Operator.OperatorType.QUERY_INDEX;
/** provide a integration method for other user. */
public class Planner {
- protected LogicalGenerator logicalGenerator;
-
public Planner() {
- this.logicalGenerator = new LogicalGenerator();
- }
-
- @TestOnly
- public PhysicalPlan parseSQLToPhysicalPlan(String sqlStr) throws QueryProcessException {
- return parseSQLToPhysicalPlan(sqlStr, ZoneId.systemDefault(), 1024);
+ // do nothing
}
/** @param fetchSize this parameter only take effect when it is a query plan */
public PhysicalPlan parseSQLToPhysicalPlan(String sqlStr, ZoneId zoneId, int fetchSize)
throws QueryProcessException {
- Operator operator = logicalGenerator.generate(sqlStr, zoneId);
- int maxDeduplicatedPathNum =
- QueryResourceManager.getInstance().getMaxDeduplicatedPathNum(fetchSize);
- if (operator instanceof SFWOperator && ((SFWOperator) 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
- // set it to Integer.MAX_VALUE - 1
- maxDeduplicatedPathNum = Integer.MAX_VALUE - 1;
- }
- operator = logicalOptimize(operator, maxDeduplicatedPathNum);
- PhysicalGenerator physicalGenerator = new PhysicalGenerator();
- return physicalGenerator.transformToPhysicalPlan(operator, fetchSize);
+ // from SQL to logical operator
+ Operator operator = LogicalGenerator.generate(sqlStr, zoneId);
+ // check if there are logical errors
+ LogicalChecker.check(operator);
+ // optimize the logical operator
+ operator = logicalOptimize(operator, fetchSize);
+ // from logical operator to physical plan
+ return new PhysicalGenerator().transformToPhysicalPlan(operator, fetchSize);
}
- /** convert raw data query to physical plan directly */
public PhysicalPlan rawDataQueryReqToPhysicalPlan(
TSRawDataQueryReq rawDataQueryReq, ZoneId zoneId)
- throws QueryProcessException, IllegalPathException {
- List<String> paths = rawDataQueryReq.getPaths();
- long startTime = rawDataQueryReq.getStartTime();
- long endTime = rawDataQueryReq.getEndTime();
-
- // construct query operator and set its global time filter
- QueryOperator queryOp = new QueryOperator(SQLConstant.TOK_QUERY);
- FromOperator fromOp = new FromOperator(SQLConstant.TOK_FROM);
- SelectOperator selectOp = new SelectOperator(SQLConstant.TOK_SELECT, zoneId);
-
- // iterate the path list and add it to from operator
- for (String p : paths) {
- PartialPath path = new PartialPath(p);
- fromOp.addPrefixTablePath(path);
- }
- selectOp.addSelectPath(new PartialPath(""));
-
- queryOp.setSelectOperator(selectOp);
- queryOp.setFromOperator(fromOp);
-
- // set time filter operator
- FilterOperator filterOp = new FilterOperator(SQLConstant.KW_AND);
- PartialPath timePath = new PartialPath(TIME);
- filterOp.setSinglePath(timePath);
- Set<PartialPath> pathSet = new HashSet<>();
- pathSet.add(timePath);
- filterOp.setIsSingle(true);
- filterOp.setPathSet(pathSet);
-
- BasicFunctionOperator left =
- new BasicFunctionOperator(
- SQLConstant.GREATERTHANOREQUALTO, timePath, Long.toString(startTime));
- BasicFunctionOperator right =
- new BasicFunctionOperator(SQLConstant.LESSTHAN, timePath, Long.toString(endTime));
- filterOp.addChildOperator(left);
- filterOp.addChildOperator(right);
-
- queryOp.setFilterOperator(filterOp);
-
- int maxDeduplicatedPathNum =
- QueryResourceManager.getInstance().getMaxDeduplicatedPathNum(rawDataQueryReq.fetchSize);
- if (queryOp.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
- // set it to Integer.MAX_VALUE - 1
- maxDeduplicatedPathNum = Integer.MAX_VALUE - 1;
- }
- SFWOperator op = (SFWOperator) logicalOptimize(queryOp, maxDeduplicatedPathNum);
-
- PhysicalGenerator physicalGenerator = new PhysicalGenerator();
- return physicalGenerator.transformToPhysicalPlan(op, rawDataQueryReq.fetchSize);
+ throws IllegalPathException, QueryProcessException {
+ // from TSRawDataQueryReq to logical operator
+ Operator operator = LogicalGenerator.generate(rawDataQueryReq, zoneId);
+ // check if there are logical errors
+ LogicalChecker.check(operator);
+ // optimize the logical operator
+ operator = logicalOptimize(operator, rawDataQueryReq.fetchSize);
+ // from logical operator to physical plan
+ return new PhysicalGenerator().transformToPhysicalPlan(operator, rawDataQueryReq.fetchSize);
}
/**
@@ -146,82 +82,38 @@ public class Planner {
* @return optimized logical operator
* @throws LogicalOptimizeException exception in logical optimizing
*/
- protected Operator logicalOptimize(Operator operator, int maxDeduplicatedPathNum)
+ protected Operator logicalOptimize(Operator operator, int fetchSize)
throws LogicalOperatorException, PathNumOverLimitException {
- switch (operator.getType()) {
- case AUTHOR:
- case METADATA:
- case SET_STORAGE_GROUP:
- case DELETE_STORAGE_GROUP:
- case CREATE_TIMESERIES:
- case DELETE_TIMESERIES:
- case ALTER_TIMESERIES:
- case LOADDATA:
- case INSERT:
- case GRANT_WATERMARK_EMBEDDING:
- case REVOKE_WATERMARK_EMBEDDING:
- case TTL:
- case LOAD_CONFIGURATION:
- case SHOW:
- case LOAD_FILES:
- case REMOVE_FILE:
- case MOVE_FILE:
- case FLUSH:
- case MERGE:
- case TRACING:
- case CLEAR_CACHE:
- case NULL:
- case SHOW_MERGE_STATUS:
- case DELETE_PARTITION:
- case CREATE_SCHEMA_SNAPSHOT:
- case KILL:
- case CREATE_FUNCTION:
- case DROP_FUNCTION:
- case CREATE_TRIGGER:
- case DROP_TRIGGER:
- case START_TRIGGER:
- case STOP_TRIGGER:
- return operator;
- case QUERY:
- case DELETE:
- case CREATE_INDEX:
- case DROP_INDEX:
- case QUERY_INDEX:
- SFWOperator root = (SFWOperator) operator;
- return optimizeSFWOperator(root, maxDeduplicatedPathNum);
- default:
- throw new LogicalOperatorException(operator.getType().toString(), "");
- }
+ return operator.getType().equals(QUERY) || operator.getType().equals(QUERY_INDEX)
+ ? optimizeQueryOperator((QueryOperator) operator, fetchSize)
+ : operator;
}
/**
- * 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 fetchSize)
throws LogicalOperatorException, PathNumOverLimitException {
- ConcatPathOptimizer concatPathOptimizer = getConcatPathOptimizer();
- root = (SFWOperator) concatPathOptimizer.transform(root, maxDeduplicatedPathNum);
+ root = (QueryOperator) new ConcatPathOptimizer().transform(root, fetchSize);
+
FilterOperator filter = root.getFilterOperator();
if (filter == null) {
return root;
}
- Set<PartialPath> pathSet = filter.getPathSet();
- RemoveNotOptimizer removeNot = new RemoveNotOptimizer();
- filter = removeNot.optimize(filter);
- DnfFilterOptimizer dnf = new DnfFilterOptimizer();
- filter = dnf.optimize(filter);
- MergeSingleFilterOptimizer merge = new MergeSingleFilterOptimizer();
- filter = merge.optimize(filter);
+ filter = new RemoveNotOptimizer().optimize(filter);
+ filter = new DnfFilterOptimizer().optimize(filter);
+ filter = new MergeSingleFilterOptimizer().optimize(filter);
root.setFilterOperator(filter);
- filter.setPathSet(pathSet);
+
return root;
}
- protected ConcatPathOptimizer getConcatPathOptimizer() {
- return new ConcatPathOptimizer();
+ @TestOnly
+ public PhysicalPlan parseSQLToPhysicalPlan(String sqlStr) throws QueryProcessException {
+ return parseSQLToPhysicalPlan(sqlStr, ZoneId.systemDefault(), 1024);
}
}
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 c640470..7e3055b 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
@@ -20,13 +20,17 @@ package org.apache.iotdb.db.qp.logical.crud;
import org.apache.iotdb.db.index.common.IndexType;
import org.apache.iotdb.db.qp.logical.Operator;
+import org.apache.iotdb.db.qp.logical.RootOperator;
import org.apache.iotdb.db.query.executor.fill.IFill;
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 RootOperator {
+
+ private SelectOperator selectOperator;
+ private FromOperator fromOperator;
+ private FilterOperator filterOperator;
private long startTime;
private long endTime;
@@ -73,6 +77,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;
}
@@ -257,6 +285,18 @@ public class QueryOperator extends SFWOperator {
this.ascending = ascending;
}
+ public boolean isLastQuery() {
+ return selectOperator.isLastQuery();
+ }
+
+ public boolean hasAggregationFunction() {
+ return selectOperator.hasAggregationFunction();
+ }
+
+ public boolean hasTimeSeriesGeneratingFunction() {
+ return selectOperator.hasTimeSeriesGeneratingFunction();
+ }
+
public boolean isWithoutAnyNull() {
return withoutAnyNull;
}
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..4c260b9 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,10 @@ 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.Expression;
+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 +33,98 @@ 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;
+ return isLastQuery;
}
- public void setLastQuery() {
- lastQuery = true;
+ public boolean hasAggregationFunction() {
+ return hasAggregationFunction;
}
- public List<String> getAggregations() {
- return this.aggregations;
+ public boolean hasTimeSeriesGeneratingFunction() {
+ return hasTimeSeriesGeneratingFunction;
}
- public void setAggregations(List<String> aggregations) {
- this.aggregations = aggregations;
+ public void addResultColumn(ResultColumn resultColumn) {
+ resultColumns.add(resultColumn);
+ if (resultColumn.getExpression().isAggregationFunctionExpression()) {
+ hasAggregationFunction = true;
+ }
+ if (resultColumn.getExpression().isTimeSeriesGeneratingFunctionExpression()) {
+ hasTimeSeriesGeneratingFunction = true;
+ }
}
- public boolean hasAggregation() {
- return hasBuiltinAggregation; // todo: hasBuiltinAggregation || hasUDAF
- }
+ public void setResultColumns(List<ResultColumn> resultColumns) {
+ this.resultColumns = resultColumns;
- public void setSuffixPathList(List<PartialPath> suffixPaths) {
- suffixList = suffixPaths;
+ pathsCache = null;
+ aggregationFunctionsCache = null;
}
- 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) {
+ Expression expression = resultColumn.getExpression();
+ if (expression instanceof TimeSeriesOperand) {
+ pathsCache.add(((TimeSeriesOperand) expression).getPath());
+ } else if (expression instanceof FunctionExpression
+ && expression.isAggregationFunctionExpression()) {
+ pathsCache.add(
+ ((TimeSeriesOperand) ((FunctionExpression) expression).getExpressions().get(0))
+ .getPath());
+ } else {
+ pathsCache.add(null);
+ }
+ }
}
- udfList.add(udf);
- }
-
- public List<UDFContext> getUdfList() {
- return udfList;
+ return pathsCache;
}
- public boolean isUdfQuery() {
- return udfQuery;
- }
-
- public void setUdfList(List<UDFContext> udfList) {
- this.udfList = udfList;
+ public List<String> getAggregationFunctions() {
+ if (!hasAggregationFunction()) {
+ return null;
+ }
+ if (aggregationFunctionsCache == null) {
+ aggregationFunctionsCache = new ArrayList<>();
+ for (ResultColumn resultColumn : resultColumns) {
+ Expression expression = resultColumn.getExpression();
+ aggregationFunctionsCache.add(
+ expression instanceof FunctionExpression
+ ? ((FunctionExpression) resultColumn.getExpression()).getFunctionName()
+ : null);
+ }
+ }
+ 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/AggregationPlan.java b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/AggregationPlan.java
index 8a26610..ee98f49 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/AggregationPlan.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/AggregationPlan.java
@@ -113,11 +113,7 @@ public class AggregationPlan extends RawDataQueryPlan {
@Override
public String getColumnForReaderFromPath(PartialPath path, int pathIndex) {
- String columnForReader = super.getColumnForReaderFromPath(path, pathIndex);
- if (!path.isTsAliasExists()) {
- columnForReader = this.getAggregations().get(pathIndex) + "(" + columnForReader + ")";
- }
- return columnForReader;
+ return resultColumns.get(pathIndex).getResultColumnName();
}
@Override
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/AlignByDevicePlan.java b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/AlignByDevicePlan.java
index be6ed98..3f79a19 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/AlignByDevicePlan.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/AlignByDevicePlan.java
@@ -21,6 +21,7 @@ package org.apache.iotdb.db.qp.physical.crud;
import org.apache.iotdb.db.metadata.PartialPath;
import org.apache.iotdb.db.qp.logical.Operator;
import org.apache.iotdb.db.qp.logical.Operator.OperatorType;
+import org.apache.iotdb.db.qp.strategy.PhysicalGenerator;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import org.apache.iotdb.tsfile.read.expression.IExpression;
@@ -53,6 +54,11 @@ public class AlignByDevicePlan extends QueryPlan {
super();
}
+ @Override
+ public void deduplicate(PhysicalGenerator physicalGenerator) {
+ // do nothing
+ }
+
public void setMeasurements(List<String> measurements) {
this.measurements = measurements;
}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/LastQueryPlan.java b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/LastQueryPlan.java
index 56fdd1c..4064364 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/LastQueryPlan.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/LastQueryPlan.java
@@ -19,14 +19,23 @@
package org.apache.iotdb.db.qp.physical.crud;
+import org.apache.iotdb.db.exception.metadata.MetadataException;
import org.apache.iotdb.db.exception.query.QueryProcessException;
import org.apache.iotdb.db.qp.logical.Operator;
+import org.apache.iotdb.db.qp.strategy.PhysicalGenerator;
+import org.apache.iotdb.db.query.expression.ResultColumn;
+import org.apache.iotdb.db.service.IoTDB;
import org.apache.iotdb.tsfile.read.expression.IExpression;
import org.apache.iotdb.tsfile.read.expression.impl.GlobalTimeExpression;
import org.apache.iotdb.tsfile.read.filter.TimeFilter.TimeGt;
import org.apache.iotdb.tsfile.read.filter.TimeFilter.TimeGtEq;
import org.apache.iotdb.tsfile.read.filter.basic.Filter;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
public class LastQueryPlan extends RawDataQueryPlan {
public LastQueryPlan() {
@@ -35,6 +44,23 @@ public class LastQueryPlan extends RawDataQueryPlan {
}
@Override
+ public void deduplicate(PhysicalGenerator physicalGenerator) throws MetadataException {
+ List<ResultColumn> deduplicatedResultColumns = new ArrayList<>();
+ Set<String> columnForReaderSet = new HashSet<>();
+ for (int i = 0; i < resultColumns.size(); i++) {
+ String column = resultColumns.get(i).getResultColumnName();
+ if (!columnForReaderSet.contains(column)) {
+ addDeduplicatedPaths(paths.get(i));
+ addDeduplicatedDataTypes(dataTypes.get(i));
+ deduplicatedResultColumns.add(resultColumns.get(i));
+ columnForReaderSet.add(column);
+ }
+ }
+ transformPaths(IoTDB.metaManager);
+ setResultColumns(deduplicatedResultColumns);
+ }
+
+ @Override
public void setExpression(IExpression expression) throws QueryProcessException {
if (isValidExpression(expression)) {
super.setExpression(expression);
@@ -47,9 +73,7 @@ public class LastQueryPlan extends RawDataQueryPlan {
private boolean isValidExpression(IExpression expression) {
if (expression instanceof GlobalTimeExpression) {
Filter filter = ((GlobalTimeExpression) expression).getFilter();
- if (filter instanceof TimeGtEq || filter instanceof TimeGt) {
- return true;
- }
+ return filter instanceof TimeGtEq || filter instanceof TimeGt;
}
return false;
}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/QueryPlan.java b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/QueryPlan.java
index a13de6f..c28d9c6 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/QueryPlan.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/QueryPlan.java
@@ -19,10 +19,13 @@
package org.apache.iotdb.db.qp.physical.crud;
import org.apache.iotdb.db.exception.metadata.IllegalPathException;
+import org.apache.iotdb.db.exception.metadata.MetadataException;
import org.apache.iotdb.db.exception.query.QueryProcessException;
import org.apache.iotdb.db.metadata.PartialPath;
import org.apache.iotdb.db.qp.logical.Operator;
import org.apache.iotdb.db.qp.physical.PhysicalPlan;
+import org.apache.iotdb.db.qp.strategy.PhysicalGenerator;
+import org.apache.iotdb.db.query.expression.ResultColumn;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import java.util.HashMap;
@@ -31,6 +34,7 @@ import java.util.Map;
public abstract class QueryPlan extends PhysicalPlan {
+ protected List<ResultColumn> resultColumns = null;
protected List<PartialPath> paths = null;
protected List<TSDataType> dataTypes = null;
private boolean alignByTime = true; // for disable align sql
@@ -61,6 +65,8 @@ public abstract class QueryPlan extends PhysicalPlan {
super(isQuery, operatorType);
}
+ public abstract void deduplicate(PhysicalGenerator physicalGenerator) throws MetadataException;
+
@Override
public List<PartialPath> getPaths() {
return paths;
@@ -128,17 +134,13 @@ public abstract class QueryPlan extends PhysicalPlan {
}
public String getColumnForReaderFromPath(PartialPath path, int pathIndex) {
- String columnForReader = path.isTsAliasExists() ? path.getTsAlias() : null;
- if (columnForReader == null) {
- columnForReader =
- path.isMeasurementAliasExists() ? path.getFullPathWithAlias() : path.toString();
- }
- return columnForReader;
+ ResultColumn resultColumn = resultColumns.get(pathIndex);
+ return resultColumn.hasAlias() ? resultColumn.getAlias() : path.getFullPath();
}
public String getColumnForDisplay(String columnForReader, int pathIndex)
throws IllegalPathException {
- return columnForReader;
+ return resultColumns.get(pathIndex).getResultColumnName();
}
public boolean isEnableRedirect() {
@@ -157,6 +159,14 @@ public abstract class QueryPlan extends PhysicalPlan {
this.vectorPathToIndex = vectorPathToIndex;
}
+ public List<ResultColumn> getResultColumns() {
+ return resultColumns;
+ }
+
+ public void setResultColumns(List<ResultColumn> resultColumns) {
+ this.resultColumns = resultColumns;
+ }
+
public boolean isWithoutAnyNull() {
return withoutAnyNull;
}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/RawDataQueryPlan.java b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/RawDataQueryPlan.java
index 6dc4d60..74b6b25 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/RawDataQueryPlan.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/RawDataQueryPlan.java
@@ -24,12 +24,16 @@ import org.apache.iotdb.db.metadata.MManager;
import org.apache.iotdb.db.metadata.PartialPath;
import org.apache.iotdb.db.metadata.VectorPartialPath;
import org.apache.iotdb.db.qp.logical.Operator;
+import org.apache.iotdb.db.qp.strategy.PhysicalGenerator;
+import org.apache.iotdb.db.service.IoTDB;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import org.apache.iotdb.tsfile.read.common.Path;
import org.apache.iotdb.tsfile.read.expression.IExpression;
+import org.apache.iotdb.tsfile.utils.Pair;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -54,6 +58,49 @@ public class RawDataQueryPlan extends QueryPlan {
super(isQuery, operatorType);
}
+ @Override
+ public void deduplicate(PhysicalGenerator physicalGenerator) throws MetadataException {
+ // sort paths by device, to accelerate the metadata read process
+ List<Pair<PartialPath, Integer>> indexedPaths = new ArrayList<>();
+ for (int i = 0; i < paths.size(); i++) {
+ indexedPaths.add(new Pair<>(paths.get(i), i));
+ }
+ indexedPaths.sort(Comparator.comparing(pair -> pair.left));
+
+ Map<String, Integer> pathNameToReaderIndex = new HashMap<>();
+ Set<String> columnForReaderSet = new HashSet<>();
+ Set<String> columnForDisplaySet = new HashSet<>();
+
+ for (Pair<PartialPath, Integer> indexedPath : indexedPaths) {
+ PartialPath originalPath = indexedPath.left;
+ Integer originalIndex = indexedPath.right;
+
+ String columnForReader = getColumnForReaderFromPath(originalPath, originalIndex);
+ if (!columnForReaderSet.contains(columnForReader)) {
+ addDeduplicatedPaths(originalPath);
+ addDeduplicatedDataTypes(dataTypes.get(originalIndex));
+ pathNameToReaderIndex.put(columnForReader, pathNameToReaderIndex.size());
+ if (this instanceof AggregationPlan) {
+ ((AggregationPlan) this)
+ .addDeduplicatedAggregations(getAggregations().get(originalIndex));
+ }
+ columnForReaderSet.add(columnForReader);
+ }
+
+ String columnForDisplay = getColumnForDisplay(columnForReader, originalIndex);
+ if (!columnForDisplaySet.contains(columnForDisplay)) {
+ addPathToIndex(columnForDisplay, getPathToIndex().size());
+ columnForDisplaySet.add(columnForDisplay);
+ }
+ }
+
+ if (!isRawQuery()) {
+ transformPaths(IoTDB.metaManager);
+ } else {
+ transformVectorPaths(physicalGenerator, columnForDisplaySet);
+ }
+ }
+
public IExpression getExpression() {
return expression;
}
@@ -132,6 +179,26 @@ public class RawDataQueryPlan extends QueryPlan {
}
}
+ public void transformVectorPaths(
+ PhysicalGenerator physicalGenerator, Set<String> columnForDisplaySet)
+ throws MetadataException {
+ Pair<List<PartialPath>, Map<String, Integer>> pair =
+ physicalGenerator.getSeriesSchema(getDeduplicatedPaths());
+
+ List<PartialPath> vectorizedDeduplicatedPaths = pair.left;
+ List<TSDataType> vectorizedDeduplicatedDataTypes =
+ new ArrayList<>(physicalGenerator.getSeriesTypes(vectorizedDeduplicatedPaths));
+ setDeduplicatedVectorPaths(vectorizedDeduplicatedPaths);
+ setDeduplicatedVectorDataTypes(vectorizedDeduplicatedDataTypes);
+
+ Map<String, Integer> columnForDisplayToQueryDataSetIndex = pair.right;
+ Map<String, Integer> pathToIndex = new HashMap<>();
+ for (String columnForDisplay : columnForDisplaySet) {
+ pathToIndex.put(columnForDisplay, columnForDisplayToQueryDataSetIndex.get(columnForDisplay));
+ }
+ setVectorPathToIndex(pathToIndex);
+ }
+
public List<PartialPath> getDeduplicatedVectorPaths() {
return deduplicatedVectorPaths;
}
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..bd2cc94 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
@@ -19,19 +19,30 @@
package org.apache.iotdb.db.qp.physical.crud;
+import org.apache.iotdb.db.exception.metadata.MetadataException;
import org.apache.iotdb.db.exception.query.QueryProcessException;
+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.qp.strategy.PhysicalGenerator;
+import org.apache.iotdb.db.query.expression.Expression;
+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 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;
+import org.apache.iotdb.db.service.IoTDB;
+import org.apache.iotdb.tsfile.utils.Pair;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Comparator;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
public class UDTFPlan extends RawDataQueryPlan implements UDFPlan {
@@ -52,18 +63,62 @@ 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) {
- continue;
+ public void deduplicate(PhysicalGenerator physicalGenerator) throws MetadataException {
+ // sort paths by device, to accelerate the metadata read process
+ List<Pair<PartialPath, Integer>> indexedPaths = new ArrayList<>();
+ for (int i = 0; i < resultColumns.size(); i++) {
+ for (PartialPath path : resultColumns.get(i).collectPaths()) {
+ indexedPaths.add(new Pair<>(path, i));
+ }
+ }
+ indexedPaths.sort(Comparator.comparing(pair -> pair.left));
+
+ Map<String, Integer> pathNameToReaderIndex = new HashMap<>();
+ Set<String> columnForReaderSet = new HashSet<>();
+ Set<String> columnForDisplaySet = new HashSet<>();
+
+ for (Pair<PartialPath, Integer> indexedPath : indexedPaths) {
+ PartialPath originalPath = indexedPath.left;
+ Integer originalIndex = indexedPath.right;
+
+ boolean isUdf =
+ !(resultColumns.get(originalIndex).getExpression() instanceof TimeSeriesOperand);
+
+ String columnForReader = getColumnForReaderFromPath(originalPath, originalIndex);
+ if (!columnForReaderSet.contains(columnForReader)) {
+ addDeduplicatedPaths(originalPath);
+ addDeduplicatedDataTypes(
+ isUdf ? IoTDB.metaManager.getSeriesType(originalPath) : dataTypes.get(originalIndex));
+ pathNameToReaderIndex.put(columnForReader, pathNameToReaderIndex.size());
+ columnForReaderSet.add(columnForReader);
}
- String columnName = context.getColumnName();
- if (!columnName2Executor.containsKey(columnName)) {
- UDTFExecutor executor = new UDTFExecutor(context, zoneId);
- columnName2Executor.put(columnName, executor);
+ String columnForDisplay = getColumnForDisplay(columnForReader, originalIndex);
+ if (!columnForDisplaySet.contains(columnForDisplay)) {
+ addPathToIndex(columnForDisplay, getPathToIndex().size());
+ if (isUdf) {
+ addUdfOutputColumn(columnForDisplay);
+ } else {
+ addRawQueryOutputColumn(columnForDisplay);
+ }
+ columnForDisplaySet.add(columnForDisplay);
}
+ }
+
+ setPathNameToReaderIndex(pathNameToReaderIndex);
+ }
+
+ @Override
+ public void constructUdfExecutors(List<ResultColumn> resultColumns) {
+ for (int i = 0; i < resultColumns.size(); ++i) {
+ Expression expression = resultColumns.get(i).getExpression();
+ if (!(expression instanceof FunctionExpression)) {
+ continue;
+ }
+
+ String columnName = expression.toString();
+ columnName2Executor.computeIfAbsent(
+ columnName, k -> new UDTFExecutor((FunctionExpression) expression, zoneId));
originalOutputColumnIndex2Executor.put(i, columnName2Executor.get(columnName));
}
}
@@ -132,14 +187,6 @@ 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 columnForReader;
- }
-
- @Override
public boolean isRawQuery() {
return false;
}
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 5fcab27..132fdba 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.AlignByDeviceClauseOrDisableAlignContext;
import org.apache.iotdb.db.qp.sql.SqlBaseParser.AlignByDeviceClauseOrDisableAlignStatementContext;
@@ -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,14 @@ 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.GrantRoleContext;
import org.apache.iotdb.db.qp.sql.SqlBaseParser.GrantRoleToUserContext;
import org.apache.iotdb.db.qp.sql.SqlBaseParser.GrantUserContext;
@@ -141,8 +136,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 +165,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,16 +199,13 @@ 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.sql.SqlBaseParser.WithoutNullStatementContext;
@@ -221,7 +213,16 @@ 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.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;
@@ -256,7 +257,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;
public void setZoneId(ZoneId zoneId) {
this.zoneId = zoneId;
@@ -310,9 +311,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 +320,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 +361,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 +413,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 +989,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 +1004,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.functionName != null) {
+ return parseFunctionExpression(context);
}
- return selectOp;
+ if (context.suffixPath() != null) {
+ return new TimeSeriesOperand(parseSuffixPath(context.suffixPath()));
+ }
+ if (context.literal != null) {
+ return new TimeSeriesOperand(new PartialPath(new String[] {context.literal.getText()}));
+ }
+ 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(ExpressionContext 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 +1219,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 +1239,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 +1268,9 @@ public class IoTDBSqlVisitor extends SqlBaseBaseVisitor<Operator> {
} else {
props = new HashMap<>();
}
- List<PartialPath> suffixPaths = new ArrayList<>();
- suffixPaths.add(path);
- queryOp.getSelectOperator().setSuffixPathList(suffixPaths);
+ List<ResultColumn> resultColumns = new ArrayList<>();
+ resultColumns.add(new ResultColumn(new TimeSeriesOperand(path)));
+ queryOp.getSelectOperator().setResultColumns(resultColumns);
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);
@@ -1464,7 +1418,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);
@@ -1492,7 +1446,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);
@@ -1655,13 +1609,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/LogicalChecker.java b/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalChecker.java
new file mode 100644
index 0000000..f55fe7c
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalChecker.java
@@ -0,0 +1,108 @@
+/*
+ * 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.strategy;
+
+import org.apache.iotdb.db.exception.query.LogicalOperatorException;
+import org.apache.iotdb.db.metadata.PartialPath;
+import org.apache.iotdb.db.qp.logical.Operator;
+import org.apache.iotdb.db.qp.logical.crud.QueryOperator;
+import org.apache.iotdb.db.qp.logical.crud.SelectOperator;
+import org.apache.iotdb.db.query.expression.Expression;
+import org.apache.iotdb.db.query.expression.ResultColumn;
+import org.apache.iotdb.db.query.expression.unary.TimeSeriesOperand;
+
+public class LogicalChecker {
+
+ /**
+ * TODO: make check() an abstract method and call check() in this method or outside the
+ * LogicalChecker.
+ */
+ public static void check(Operator operator) throws LogicalOperatorException {
+ if (operator instanceof QueryOperator) {
+ checkQueryOperator((QueryOperator) operator);
+ }
+ }
+
+ private static void checkQueryOperator(QueryOperator queryOperator)
+ throws LogicalOperatorException {
+ checkSelectOperator(queryOperator);
+ }
+
+ private static void checkSelectOperator(QueryOperator queryOperator)
+ throws LogicalOperatorException {
+ checkLast(queryOperator);
+ checkAggregation(queryOperator);
+ checkAlignByDevice(queryOperator);
+ }
+
+ private static void checkLast(QueryOperator queryOperator) throws LogicalOperatorException {
+ SelectOperator selectOperator = queryOperator.getSelectOperator();
+ if (!selectOperator.isLastQuery()) {
+ return;
+ }
+
+ for (ResultColumn resultColumn : selectOperator.getResultColumns()) {
+ Expression expression = resultColumn.getExpression();
+ if (!(expression instanceof TimeSeriesOperand)) {
+ throw new LogicalOperatorException("Last queries can only be applied on raw time series.");
+ }
+ }
+ }
+
+ private static void checkAggregation(QueryOperator queryOperator)
+ throws LogicalOperatorException {
+ SelectOperator selectOperator = queryOperator.getSelectOperator();
+ if (!selectOperator.hasAggregationFunction()) {
+ return;
+ }
+
+ for (ResultColumn resultColumn : selectOperator.getResultColumns()) {
+ Expression expression = resultColumn.getExpression();
+ if (expression instanceof TimeSeriesOperand) {
+ throw new LogicalOperatorException(
+ "Common queries and aggregated queries are not allowed to appear at the same time");
+ }
+ }
+ }
+
+ private static void checkAlignByDevice(QueryOperator queryOperator)
+ throws LogicalOperatorException {
+ if (!queryOperator.isAlignByDevice()) {
+ return;
+ }
+
+ SelectOperator selectOperator = queryOperator.getSelectOperator();
+ if (selectOperator.hasTimeSeriesGeneratingFunction()) {
+ throw new LogicalOperatorException("ALIGN BY DEVICE clause is not supported in UDF queries.");
+ }
+
+ for (PartialPath path : selectOperator.getPaths()) {
+ String device = path.getDevice();
+ if (!device.isEmpty()) {
+ throw new LogicalOperatorException(
+ "The paths of the SELECT clause can only be single level. In other words, "
+ + "the paths of the SELECT clause can only be measurements or STAR, without DOT."
+ + " For more details please refer to the SQL document.");
+ }
+ }
+ }
+
+ private LogicalChecker() {}
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java b/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java
index e4f5a67..51a5e72 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/LogicalGenerator.java
@@ -18,10 +18,21 @@
*/
package org.apache.iotdb.db.qp.strategy;
+import org.apache.iotdb.db.exception.metadata.IllegalPathException;
+import org.apache.iotdb.db.metadata.PartialPath;
+import org.apache.iotdb.db.qp.constant.SQLConstant;
import org.apache.iotdb.db.qp.logical.Operator;
+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.SelectOperator;
import org.apache.iotdb.db.qp.sql.IoTDBSqlVisitor;
import org.apache.iotdb.db.qp.sql.SqlBaseLexer;
import org.apache.iotdb.db.qp.sql.SqlBaseParser;
+import org.apache.iotdb.db.query.expression.ResultColumn;
+import org.apache.iotdb.db.query.expression.unary.TimeSeriesOperand;
+import org.apache.iotdb.service.rpc.thrift.TSRawDataQueryReq;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
@@ -31,13 +42,15 @@ import org.antlr.v4.runtime.misc.ParseCancellationException;
import org.antlr.v4.runtime.tree.ParseTree;
import java.time.ZoneId;
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.apache.iotdb.db.conf.IoTDBConstant.TIME;
/** LogicalGenerator. */
public class LogicalGenerator {
- public LogicalGenerator() {}
-
- public Operator generate(String sql, ZoneId zoneId) throws ParseCancellationException {
+ public static Operator generate(String sql, ZoneId zoneId) throws ParseCancellationException {
IoTDBSqlVisitor ioTDBSqlVisitor = new IoTDBSqlVisitor();
ioTDBSqlVisitor.setZoneId(zoneId);
CharStream charStream1 = CharStreams.fromString(sql);
@@ -67,4 +80,48 @@ public class LogicalGenerator {
}
return ioTDBSqlVisitor.visit(tree);
}
+
+ public static Operator generate(TSRawDataQueryReq rawDataQueryReq, ZoneId zoneId)
+ throws IllegalPathException {
+ // construct query operator and set its global time filter
+ QueryOperator queryOp = new QueryOperator(SQLConstant.TOK_QUERY);
+ FromOperator fromOp = new FromOperator(SQLConstant.TOK_FROM);
+ SelectOperator selectOp = new SelectOperator(SQLConstant.TOK_SELECT, zoneId);
+
+ // iterate the path list and add it to from operator
+ for (String p : rawDataQueryReq.getPaths()) {
+ PartialPath path = new PartialPath(p);
+ fromOp.addPrefixTablePath(path);
+ }
+ selectOp.addResultColumn(new ResultColumn(new TimeSeriesOperand(new PartialPath(""))));
+
+ queryOp.setSelectOperator(selectOp);
+ queryOp.setFromOperator(fromOp);
+
+ // set time filter operator
+ FilterOperator filterOp = new FilterOperator(SQLConstant.KW_AND);
+ PartialPath timePath = new PartialPath(TIME);
+ filterOp.setSinglePath(timePath);
+ Set<PartialPath> pathSet = new HashSet<>();
+ pathSet.add(timePath);
+ filterOp.setIsSingle(true);
+ filterOp.setPathSet(pathSet);
+
+ BasicFunctionOperator left =
+ new BasicFunctionOperator(
+ SQLConstant.GREATERTHANOREQUALTO,
+ timePath,
+ Long.toString(rawDataQueryReq.getStartTime()));
+ BasicFunctionOperator right =
+ new BasicFunctionOperator(
+ SQLConstant.LESSTHAN, timePath, Long.toString(rawDataQueryReq.getEndTime()));
+ filterOp.addChildOperator(left);
+ filterOp.addChildOperator(right);
+
+ queryOp.setFilterOperator(filterOp);
+
+ return queryOp;
+ }
+
+ private LogicalGenerator() {}
}
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 217a3bb..5c81c6e 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,10 @@ 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.Expression;
+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 org.apache.iotdb.db.service.IoTDB;
import org.apache.iotdb.db.utils.SchemaUtils;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
@@ -131,7 +134,6 @@ import org.apache.iotdb.tsfile.utils.Pair;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
@@ -152,7 +154,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 +212,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 +230,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 +249,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 +258,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(
@@ -454,21 +453,21 @@ public class PhysicalGenerator {
}
}
- protected List<TSDataType> getSeriesTypes(List<PartialPath> paths) throws MetadataException {
+ public List<TSDataType> getSeriesTypes(List<PartialPath> paths) throws MetadataException {
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()) {
+ AggregationPlan queryPlan;
+ if (queryOperator.hasTimeSeriesGeneratingFunction()) {
throw new QueryProcessException(
"User-defined and built-in hybrid aggregation is not supported.");
}
@@ -479,8 +478,9 @@ public class PhysicalGenerator {
} else {
queryPlan = new AggregationPlan();
}
- ((AggregationPlan) queryPlan)
- .setAggregations(queryOperator.getSelectOperator().getAggregations());
+
+ queryPlan.setPaths(queryOperator.getSelectOperator().getPaths());
+ queryPlan.setAggregations(queryOperator.getSelectOperator().getAggregationFunctions());
if (queryOperator.isGroupByTime()) {
GroupByTimePlan groupByTimePlan = (GroupByTimePlan) queryPlan;
@@ -505,7 +505,7 @@ public class PhysicalGenerator {
}
}
} else if (queryOperator.isGroupByLevel()) {
- ((AggregationPlan) queryPlan).setLevel(queryOperator.getLevel());
+ queryPlan.setLevel(queryOperator.getLevel());
try {
if (!verifyAllAggregationDataTypesEqual(queryOperator)) {
throw new QueryProcessException("Aggregate among unmatched data types");
@@ -519,11 +519,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 +542,7 @@ public class PhysicalGenerator {
private PhysicalPlan transformQuery(QueryOperator queryOperator) throws QueryProcessException {
QueryPlan queryPlan;
- if (queryOperator.hasAggregation()) {
+ if (queryOperator.hasAggregationFunction()) {
queryPlan = new AggPhysicalPlanRule().transform(queryOperator);
} else if (queryOperator.isFill()) {
queryPlan = new FillPhysicalPlanRule().transform(queryOperator);
@@ -550,9 +550,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 +561,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.");
@@ -597,8 +598,15 @@ public class PhysicalGenerator {
}
return queryPlan;
}
+
+ queryPlan.setResultColumns(queryOperator.getSelectOperator().getResultColumns());
+
try {
- deduplicate(queryPlan);
+ List<PartialPath> paths = queryPlan.getPaths();
+ List<TSDataType> dataTypes = getSeriesTypes(paths);
+ queryPlan.setDataTypes(dataTypes);
+
+ queryPlan.deduplicate(this);
} catch (MetadataException e) {
throw new QueryProcessException(e);
}
@@ -629,8 +637,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<ResultColumn> resultColumns = queryOperator.getSelectOperator().getResultColumns();
+ List<String> originAggregations = queryOperator.getSelectOperator().getAggregationFunctions();
// to record result measurement columns
List<String> measurements = new ArrayList<>();
@@ -644,8 +652,13 @@ public class PhysicalGenerator {
Map<String, TSDataType> measurementDataTypeMap = new HashMap<>();
List<PartialPath> paths = new ArrayList<>();
- for (int i = 0; i < suffixPaths.size(); i++) { // per suffix in SELECT
- PartialPath suffixPath = suffixPaths.get(i);
+ for (int i = 0; i < resultColumns.size(); i++) { // per suffix in SELECT
+ ResultColumn resultColumn = resultColumns.get(i);
+ Expression suffixExpression = resultColumn.getExpression();
+ PartialPath suffixPath =
+ suffixExpression instanceof TimeSeriesOperand
+ ? ((TimeSeriesOperand) suffixExpression).getPath()
+ : (((FunctionExpression) suffixExpression).getPaths().get(0));
// to record measurements in the loop of a suffix path
Set<String> measurementSetOfGivenSuffix = new LinkedHashSet<>();
@@ -658,24 +671,23 @@ public class PhysicalGenerator {
}
for (PartialPath device : devices) { // per device in FROM after deduplication
-
PartialPath fullPath = device.concatPath(suffixPath);
try {
// remove stars in SELECT to get actual paths
List<PartialPath> actualPaths = getMatchedTimeseries(fullPath);
- if (suffixPath.isTsAliasExists()) {
+ if (resultColumn.hasAlias()) {
if (actualPaths.size() == 1) {
String columnName = actualPaths.get(0).getMeasurement();
if (originAggregations != null && !originAggregations.isEmpty()) {
measurementAliasMap.put(
- originAggregations.get(i) + "(" + columnName + ")", suffixPath.getTsAlias());
+ originAggregations.get(i) + "(" + columnName + ")", resultColumn.getAlias());
} else {
- measurementAliasMap.put(columnName, suffixPath.getTsAlias());
+ measurementAliasMap.put(columnName, resultColumn.getAlias());
}
} else if (actualPaths.size() >= 2) {
throw new QueryProcessException(
"alias '"
- + suffixPath.getTsAlias()
+ + resultColumn.getAlias()
+ "' can only be matched with one time series");
}
}
@@ -852,116 +864,7 @@ public class PhysicalGenerator {
basicOperator.setSinglePath(concatPath);
}
- @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity warning
- private void deduplicate(QueryPlan queryPlan) throws MetadataException {
- // generate dataType first
- List<PartialPath> paths = queryPlan.getPaths();
- List<TSDataType> dataTypes = getSeriesTypes(paths);
- queryPlan.setDataTypes(dataTypes);
-
- // deduplicate from here
- if (queryPlan instanceof AlignByDevicePlan) {
- return;
- }
-
- RawDataQueryPlan rawDataQueryPlan = (RawDataQueryPlan) queryPlan;
- Set<String> columnForReaderSet = new HashSet<>();
- // if it's a last query, no need to sort by device
- if (queryPlan instanceof LastQueryPlan) {
- for (int i = 0; i < paths.size(); i++) {
- PartialPath path = paths.get(i);
- String column = queryPlan.getColumnForReaderFromPath(path, i);
- if (!columnForReaderSet.contains(column)) {
- TSDataType seriesType = dataTypes.get(i);
- rawDataQueryPlan.addDeduplicatedPaths(path);
- rawDataQueryPlan.addDeduplicatedDataTypes(seriesType);
- columnForReaderSet.add(column);
- }
- }
- ((LastQueryPlan) queryPlan).transformPaths(IoTDB.metaManager);
- return;
- }
-
- // sort path by device
- List<Pair<PartialPath, Integer>> indexedPaths = new ArrayList<>();
- for (int i = 0; i < paths.size(); i++) {
- PartialPath path = paths.get(i);
- 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()) {
- indexedPaths.add(new Pair<>(udfPath, i));
- }
- }
- }
- indexedPaths.sort(Comparator.comparing(pair -> pair.left));
-
- Map<String, Integer> pathNameToReaderIndex = new HashMap<>();
- Set<String> columnForDisplaySet = new HashSet<>();
- for (Pair<PartialPath, Integer> indexedPath : indexedPaths) {
- PartialPath originalPath = indexedPath.left;
- Integer originalIndex = indexedPath.right;
-
- String columnForReader = queryPlan.getColumnForReaderFromPath(originalPath, originalIndex);
- boolean isUdf = queryPlan instanceof UDTFPlan && paths.get(originalIndex) == null;
-
- if (!columnForReaderSet.contains(columnForReader)) {
- rawDataQueryPlan.addDeduplicatedPaths(originalPath);
- rawDataQueryPlan.addDeduplicatedDataTypes(
- isUdf ? IoTDB.metaManager.getSeriesType(originalPath) : dataTypes.get(originalIndex));
- pathNameToReaderIndex.put(columnForReader, pathNameToReaderIndex.size());
- if (queryPlan instanceof AggregationPlan) {
- ((AggregationPlan) queryPlan)
- .addDeduplicatedAggregations(queryPlan.getAggregations().get(originalIndex));
- }
- columnForReaderSet.add(columnForReader);
- }
-
- String columnForDisplay = queryPlan.getColumnForDisplay(columnForReader, originalIndex);
-
- if (!columnForDisplaySet.contains(columnForDisplay)) {
- queryPlan.addPathToIndex(columnForDisplay, queryPlan.getPathToIndex().size());
- if (queryPlan instanceof UDTFPlan) {
- if (isUdf) {
- ((UDTFPlan) queryPlan).addUdfOutputColumn(columnForDisplay);
- } else {
- ((UDTFPlan) queryPlan).addRawQueryOutputColumn(columnForDisplay);
- }
- }
- columnForDisplaySet.add(columnForDisplay);
- }
- }
- if (queryPlan instanceof UDTFPlan) {
- ((UDTFPlan) queryPlan).setPathNameToReaderIndex(pathNameToReaderIndex);
- return;
- }
-
- if (!rawDataQueryPlan.isRawQuery()) {
- rawDataQueryPlan.transformPaths(IoTDB.metaManager);
- } else {
- // support vector
- List<PartialPath> deduplicatedPaths = rawDataQueryPlan.getDeduplicatedPaths();
- Pair<List<PartialPath>, Map<String, Integer>> pair = getSeriesSchema(deduplicatedPaths);
-
- List<PartialPath> vectorizedDeduplicatedPaths = pair.left;
- List<TSDataType> vectorizedDeduplicatedDataTypes =
- new ArrayList<>(getSeriesTypes(vectorizedDeduplicatedPaths));
- rawDataQueryPlan.setDeduplicatedVectorPaths(vectorizedDeduplicatedPaths);
- rawDataQueryPlan.setDeduplicatedVectorDataTypes(vectorizedDeduplicatedDataTypes);
-
- Map<String, Integer> columnForDisplayToQueryDataSetIndex = pair.right;
- Map<String, Integer> pathToIndex = new HashMap<>();
- for (String columnForDisplay : columnForDisplaySet) {
- pathToIndex.put(
- columnForDisplay, columnForDisplayToQueryDataSetIndex.get(columnForDisplay));
- }
- queryPlan.setVectorPathToIndex(pathToIndex);
- }
- }
-
- protected Pair<List<PartialPath>, Map<String, Integer>> getSeriesSchema(List<PartialPath> paths)
+ public Pair<List<PartialPath>, Map<String, Integer>> getSeriesSchema(List<PartialPath> paths)
throws MetadataException {
return IoTDB.metaManager.getSeriesSchemas(paths);
}
@@ -987,12 +890,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..69c6d94 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
@@ -30,11 +30,10 @@ 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.FunctionOperator;
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.query.udf.core.context.UDFContext;
+import org.apache.iotdb.db.qp.utils.WildcardsRemover;
+import org.apache.iotdb.db.query.expression.ResultColumn;
import org.apache.iotdb.db.service.IoTDB;
-import org.apache.iotdb.tsfile.utils.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -47,211 +46,94 @@ import java.util.Set;
/** concat paths in select and from clause. */
public class ConcatPathOptimizer implements ILogicalOptimizer {
- private static final Logger logger = LoggerFactory.getLogger(ConcatPathOptimizer.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(ConcatPathOptimizer.class);
+
private static final String WARNING_NO_SUFFIX_PATHS =
- "given SFWOperator doesn't have suffix paths, cannot concat seriesPath";
+ "failed to concat series paths because the given query operator didn't have suffix paths";
private static final String WARNING_NO_PREFIX_PATHS =
- "given SFWOperator doesn't have prefix paths, cannot concat seriesPath";
+ "failed to concat series paths because the given query operator didn't have prefix paths";
- @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity warning
@Override
- public Operator transform(Operator operator, int maxDeduplicatedPathNum)
+ public Operator transform(Operator operator, int fetchSize)
throws LogicalOptimizeException, PathNumOverLimitException {
- if (!(operator instanceof SFWOperator)) {
- logger.warn("given operator isn't SFWOperator, cannot concat seriesPath");
- return operator;
- }
- SFWOperator sfwOperator = (SFWOperator) operator;
- FromOperator from = sfwOperator.getFromOperator();
- List<PartialPath> prefixPaths;
- if (from == null) {
- logger.warn(WARNING_NO_PREFIX_PATHS);
- return operator;
- } else {
- prefixPaths = from.getPrefixPaths();
- if (prefixPaths.isEmpty()) {
- logger.warn(WARNING_NO_PREFIX_PATHS);
- return operator;
- }
- }
- SelectOperator select = sfwOperator.getSelectOperator();
- List<PartialPath> initialSuffixPaths;
- if (select == null) {
- logger.warn(WARNING_NO_SUFFIX_PATHS);
- return operator;
- } else {
- initialSuffixPaths = select.getSuffixPaths();
- if (initialSuffixPaths.isEmpty()) {
- logger.warn(WARNING_NO_SUFFIX_PATHS);
- return operator;
- }
- }
-
- checkAggrOfSelectOperator(select);
+ QueryOperator queryOperator = (QueryOperator) operator;
+ if (!optimizable(queryOperator)) {
+ return queryOperator;
+ }
+ concatSelect(queryOperator);
+ removeWildcardsInSelectPaths(queryOperator, fetchSize);
+ concatFilterAndRemoveWildcards(queryOperator);
+ return queryOperator;
+ }
- boolean isAlignByDevice = false;
- if (operator instanceof QueryOperator) {
- if (!((QueryOperator) operator).isAlignByDevice()
- || ((QueryOperator) operator).isLastQuery()) {
- // concat paths and remove stars
- int seriesLimit = ((QueryOperator) operator).getSeriesLimit();
- int seriesOffset = ((QueryOperator) operator).getSeriesOffset();
- concatSelect(
- prefixPaths,
- select,
- seriesLimit,
- seriesOffset,
- maxDeduplicatedPathNum,
- ((QueryOperator) operator).getIndexType() == null);
- } else {
- isAlignByDevice = true;
- if (((QueryOperator) operator).hasUdf()) {
- throw new LogicalOptimizeException(
- "ALIGN BY DEVICE clause is not supported in UDF queries.");
- }
- for (PartialPath path : initialSuffixPaths) {
- String device = path.getDevice();
- if (!device.isEmpty()) {
- throw new LogicalOptimizeException(
- "The paths of the SELECT clause can only be single level. In other words, "
- + "the paths of the SELECT clause can only be measurements or STAR, without DOT."
- + " For more details please refer to the SQL document.");
- }
- }
- // ALIGN_BY_DEVICE leaves the 1) concat, 2) remove star, 3) slimit tasks to the next phase,
- // i.e., PhysicalGenerator.transformQuery
- }
+ private boolean optimizable(QueryOperator queryOperator) {
+ if (queryOperator.isAlignByDevice()) {
+ return false;
}
- // concat filter
- FilterOperator filter = sfwOperator.getFilterOperator();
- Set<PartialPath> filterPaths = new HashSet<>();
- if (filter == null) {
- return operator;
- }
- if (!isAlignByDevice) {
- sfwOperator.setFilterOperator(concatFilter(prefixPaths, filter, filterPaths));
+ SelectOperator select = queryOperator.getSelectOperator();
+ if (select == null || select.getResultColumns().isEmpty()) {
+ LOGGER.warn(WARNING_NO_SUFFIX_PATHS);
+ return false;
}
- sfwOperator.getFilterOperator().setPathSet(filterPaths);
- // GROUP_BY_DEVICE leaves the concatFilter to PhysicalGenerator to optimize filter without
- // prefix first
- return sfwOperator;
- }
-
- private List<PartialPath> judgeSelectOperator(SelectOperator selectOperator)
- throws LogicalOptimizeException {
- List<PartialPath> suffixPaths;
- if (selectOperator == null) {
- throw new LogicalOptimizeException(WARNING_NO_SUFFIX_PATHS);
- } else {
- suffixPaths = selectOperator.getSuffixPaths();
- if (suffixPaths.isEmpty()) {
- throw new LogicalOptimizeException(WARNING_NO_SUFFIX_PATHS);
- }
+ FromOperator from = queryOperator.getFromOperator();
+ if (from == null || from.getPrefixPaths().isEmpty()) {
+ LOGGER.warn(WARNING_NO_PREFIX_PATHS);
+ return false;
}
- return suffixPaths;
- }
- private void checkAggrOfSelectOperator(SelectOperator selectOperator)
- throws LogicalOptimizeException {
- if (!selectOperator.getAggregations().isEmpty()
- && selectOperator.getSuffixPaths().size() != selectOperator.getAggregations().size()) {
- throw new LogicalOptimizeException(
- "Common queries and aggregated queries are not allowed to appear at the same time");
- }
+ return true;
}
- private void extendListSafely(List<String> source, int index, List<String> target) {
- if (source != null && !source.isEmpty()) {
- target.add(source.get(index));
+ private void concatSelect(QueryOperator queryOperator) throws LogicalOptimizeException {
+ List<PartialPath> prefixPaths = queryOperator.getFromOperator().getPrefixPaths();
+ List<ResultColumn> resultColumns = new ArrayList<>();
+ for (ResultColumn suffixColumn : queryOperator.getSelectOperator().getResultColumns()) {
+ suffixColumn.concat(prefixPaths, resultColumns);
}
+ queryOperator.getSelectOperator().setResultColumns(resultColumns);
}
- /**
- * Extract paths from select&from cql, expand them into complete versions, and reassign them to
- * selectOperator's suffixPathList. Treat aggregations similarly.
- */
- @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity warning
- private void concatSelect(
- List<PartialPath> fromPaths,
- SelectOperator selectOperator,
- int limit,
- int offset,
- int maxDeduplicatedPathNum,
- boolean needRemoveStar)
+ private void removeWildcardsInSelectPaths(QueryOperator queryOperator, int fetchSize)
throws LogicalOptimizeException, PathNumOverLimitException {
- List<PartialPath> suffixPaths = judgeSelectOperator(selectOperator);
- List<PartialPath> afterConcatPaths = new ArrayList<>(); // null elements are for the UDFs
-
- List<String> originAggregations = selectOperator.getAggregations();
- List<String> afterConcatAggregations = new ArrayList<>(); // null elements are for the UDFs
-
- List<UDFContext> originUdfList = selectOperator.getUdfList();
- List<UDFContext> afterConcatUdfList = new ArrayList<>();
-
- for (int i = 0; i < suffixPaths.size(); i++) {
- // selectPath cannot start with ROOT, which is guaranteed by TSParser
- PartialPath selectPath = suffixPaths.get(i);
-
- if (selectPath == null) { // udf
- UDFContext originUdf = originUdfList.get(i);
- List<PartialPath> originUdfSuffixPaths = originUdf.getPaths();
-
- List<List<PartialPath>> afterConcatUdfPathsList = new ArrayList<>();
- for (PartialPath originUdfSuffixPath : originUdfSuffixPaths) {
- List<PartialPath> afterConcatUdfPaths = new ArrayList<>();
- for (PartialPath fromPath : fromPaths) {
- afterConcatUdfPaths.add(fromPath.concatPath(originUdfSuffixPath));
- }
- afterConcatUdfPathsList.add(afterConcatUdfPaths);
- }
- List<List<PartialPath>> extendedAfterConcatUdfPathsList = new ArrayList<>();
- cartesianProduct(
- afterConcatUdfPathsList, extendedAfterConcatUdfPathsList, 0, new ArrayList<>());
-
- for (List<PartialPath> afterConcatUdfPaths : extendedAfterConcatUdfPathsList) {
- afterConcatPaths.add(null);
- extendListSafely(originAggregations, i, afterConcatAggregations);
-
- afterConcatUdfList.add(
- new UDFContext(originUdf.getName(), originUdf.getAttributes(), afterConcatUdfPaths));
- }
- } else { // non-udf
- for (PartialPath fromPath : fromPaths) {
- PartialPath fullPath = fromPath.concatPath(selectPath);
- if (selectPath.isTsAliasExists()) {
- fullPath.setTsAlias(selectPath.getTsAlias());
- }
- afterConcatPaths.add(fullPath);
- extendListSafely(originAggregations, i, afterConcatAggregations);
+ if (queryOperator.getIndexType() != null) {
+ return;
+ }
- afterConcatUdfList.add(null);
- }
+ WildcardsRemover wildcardsRemover = new WildcardsRemover(queryOperator, fetchSize);
+ List<ResultColumn> resultColumns = new ArrayList<>();
+ for (ResultColumn resultColumn : queryOperator.getSelectOperator().getResultColumns()) {
+ resultColumn.removeWildcards(wildcardsRemover, resultColumns);
+ if (wildcardsRemover.checkIfPathNumberIsOverLimit(resultColumns)) {
+ break;
}
}
+ wildcardsRemover.checkIfSoffsetIsExceeded(resultColumns);
+ queryOperator.getSelectOperator().setResultColumns(resultColumns);
+ }
- if (needRemoveStar) {
- removeStarsInPath(
- afterConcatPaths,
- afterConcatAggregations,
- afterConcatUdfList,
- selectOperator,
- limit,
- offset,
- maxDeduplicatedPathNum);
- } else {
- selectOperator.setSuffixPathList(afterConcatPaths);
+ private void concatFilterAndRemoveWildcards(QueryOperator queryOperator)
+ throws LogicalOptimizeException {
+ FilterOperator filter = queryOperator.getFilterOperator();
+ if (filter == null) {
+ return;
}
+
+ Set<PartialPath> filterPaths = new HashSet<>();
+ queryOperator.setFilterOperator(
+ concatFilterAndRemoveWildcards(
+ queryOperator.getFromOperator().getPrefixPaths(), filter, filterPaths));
+ queryOperator.getFilterOperator().setPathSet(filterPaths);
}
- private FilterOperator concatFilter(
+ private FilterOperator concatFilterAndRemoveWildcards(
List<PartialPath> fromPaths, FilterOperator operator, Set<PartialPath> filterPaths)
throws LogicalOptimizeException {
if (!operator.isLeaf()) {
List<FilterOperator> newFilterList = new ArrayList<>();
for (FilterOperator child : operator.getChildren()) {
- newFilterList.add(concatFilter(fromPaths, child, filterPaths));
+ newFilterList.add(concatFilterAndRemoveWildcards(fromPaths, child, filterPaths));
}
operator.setChildren(newFilterList);
return operator;
@@ -266,7 +148,7 @@ public class ConcatPathOptimizer implements ILogicalOptimizer {
}
List<PartialPath> concatPaths = new ArrayList<>();
fromPaths.forEach(fromPath -> concatPaths.add(fromPath.concatPath(filterPath)));
- List<PartialPath> noStarPaths = removeStarsInPathWithUnique(concatPaths);
+ List<PartialPath> noStarPaths = removeWildcardsInConcatPaths(concatPaths);
filterPaths.addAll(noStarPaths);
if (noStarPaths.size() == 1) {
// Transform "select s1 from root.car.* where s1 > 10" to
@@ -306,173 +188,33 @@ public class ConcatPathOptimizer implements ILogicalOptimizer {
return filterBinaryTree;
}
- /**
- * replace "*" by actual paths.
- *
- * @param paths list of paths which may contain stars
- * @return a unique seriesPath list
- */
- private List<PartialPath> removeStarsInPathWithUnique(List<PartialPath> paths)
+ private List<PartialPath> removeWildcardsInConcatPaths(List<PartialPath> originalPaths)
throws LogicalOptimizeException {
- List<PartialPath> retPaths = new ArrayList<>();
- HashSet<PartialPath> pathSet = new HashSet<>();
+ HashSet<PartialPath> actualPaths = new HashSet<>();
try {
- for (PartialPath path : paths) {
- List<PartialPath> all = removeWildcard(path, 0, 0).left;
- if (all.size() == 0) {
+ for (PartialPath originalPath : originalPaths) {
+ List<PartialPath> all =
+ IoTDB.metaManager.getAllTimeseriesPathWithAlias(originalPath, 0, 0).left;
+ if (all.isEmpty()) {
throw new LogicalOptimizeException(
- String.format("Unknown time series %s in `where clause`", path));
- }
- for (PartialPath subPath : all) {
- if (!pathSet.contains(subPath)) {
- pathSet.add(subPath);
- retPaths.add(subPath);
- }
+ String.format("Unknown time series %s in `where clause`", originalPath));
}
+ actualPaths.addAll(all);
}
} catch (MetadataException e) {
throw new LogicalOptimizeException("error when remove star: " + e.getMessage());
}
- return retPaths;
- }
-
- @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity warning
- private void removeStarsInPath(
- List<PartialPath> afterConcatPaths,
- List<String> afterConcatAggregations,
- List<UDFContext> afterConcatUdfList,
- SelectOperator selectOperator,
- int finalLimit,
- int finalOffset,
- int maxDeduplicatedPathNum)
- throws LogicalOptimizeException, PathNumOverLimitException {
- int offset = finalOffset;
- int limit =
- finalLimit == 0 || maxDeduplicatedPathNum < finalLimit
- ? maxDeduplicatedPathNum + 1
- : finalLimit;
- int consumed = 0;
-
- List<PartialPath> newSuffixPathList = new ArrayList<>();
- List<String> newAggregations = new ArrayList<>();
- List<UDFContext> newUdfList = new ArrayList<>();
-
- for (int i = 0; i < afterConcatPaths.size(); i++) {
- try {
- PartialPath afterConcatPath = afterConcatPaths.get(i);
-
- if (afterConcatPath == null) { // udf
- UDFContext originUdf = afterConcatUdfList.get(i);
- List<PartialPath> originPaths = originUdf.getPaths();
- List<List<PartialPath>> extendedPaths = new ArrayList<>();
-
- boolean atLeastOneSeriesNotExisted = false;
- for (PartialPath originPath : originPaths) {
- List<PartialPath> actualPaths = removeWildcard(originPath, 0, 0).left;
- if (actualPaths.isEmpty()) {
- atLeastOneSeriesNotExisted = true;
- break;
- }
- checkAndSetTsAlias(actualPaths, originPath);
- extendedPaths.add(actualPaths);
- }
- if (atLeastOneSeriesNotExisted) {
- continue;
- }
-
- List<List<PartialPath>> actualPaths = new ArrayList<>();
- cartesianProduct(extendedPaths, actualPaths, 0, new ArrayList<>());
-
- for (List<PartialPath> actualPath : actualPaths) {
- if (offset != 0) {
- --offset;
- continue;
- } else if (limit != 0) {
- --limit;
- } else {
- break;
- }
-
- newSuffixPathList.add(null);
- extendListSafely(afterConcatAggregations, i, newAggregations);
-
- newUdfList.add(
- new UDFContext(originUdf.getName(), originUdf.getAttributes(), actualPath));
- }
- } else { // non-udf
- Pair<List<PartialPath>, Integer> pair = removeWildcard(afterConcatPath, limit, offset);
- List<PartialPath> actualPaths = pair.left;
- checkAndSetTsAlias(actualPaths, afterConcatPath);
-
- for (PartialPath actualPath : actualPaths) {
- newSuffixPathList.add(actualPath);
- extendListSafely(afterConcatAggregations, i, newAggregations);
-
- newUdfList.add(null);
- }
-
- consumed += pair.right;
- if (offset != 0) {
- int delta = offset - pair.right;
- offset = Math.max(delta, 0);
- if (delta < 0) {
- limit += delta;
- }
- } else {
- limit -= pair.right;
- }
- }
-
- if (limit == 0) {
- if (maxDeduplicatedPathNum < newSuffixPathList.size()) {
- throw new PathNumOverLimitException(maxDeduplicatedPathNum);
- }
- break;
- }
- } catch (MetadataException e) {
- throw new LogicalOptimizeException("error when remove star: " + e.getMessage());
- }
- }
-
- if (consumed == 0 ? finalOffset != 0 : newSuffixPathList.isEmpty()) {
- throw new LogicalOptimizeException(
- String.format(
- "The value of SOFFSET (%d) is equal to or exceeds the number of sequences (%d) that can actually be returned.",
- finalOffset, consumed));
- }
- selectOperator.setSuffixPathList(newSuffixPathList);
- selectOperator.setAggregations(newAggregations);
- selectOperator.setUdfList(newUdfList);
- }
-
- protected Pair<List<PartialPath>, Integer> removeWildcard(PartialPath path, int limit, int offset)
- throws MetadataException {
- return IoTDB.metaManager.getAllTimeseriesPathWithAlias(path, limit, offset);
- }
-
- private void checkAndSetTsAlias(List<PartialPath> actualPaths, PartialPath originPath)
- throws LogicalOptimizeException {
- if (originPath.isTsAliasExists()) {
- if (actualPaths.size() == 1) {
- actualPaths.get(0).setTsAlias(originPath.getTsAlias());
- } else if (actualPaths.size() >= 2) {
- throw new LogicalOptimizeException(
- "alias '" + originPath.getTsAlias() + "' can only be matched with one time series");
- }
- }
+ return new ArrayList<>(actualPaths);
}
- private static void cartesianProduct(
- List<List<PartialPath>> dimensionValue,
- List<List<PartialPath>> resultList,
- int layer,
- List<PartialPath> currentList) {
+ public static <T> void cartesianProduct(
+ List<List<T>> dimensionValue, List<List<T>> resultList, int layer, List<T> currentList) {
if (layer < dimensionValue.size() - 1) {
if (dimensionValue.get(layer).isEmpty()) {
cartesianProduct(dimensionValue, resultList, layer + 1, currentList);
} else {
for (int i = 0; i < dimensionValue.get(layer).size(); i++) {
- List<PartialPath> list = new ArrayList<>(currentList);
+ List<T> list = new ArrayList<>(currentList);
list.add(dimensionValue.get(layer).get(i));
cartesianProduct(dimensionValue, resultList, layer + 1, list);
}
@@ -482,7 +224,7 @@ public class ConcatPathOptimizer implements ILogicalOptimizer {
resultList.add(currentList);
} else {
for (int i = 0; i < dimensionValue.get(layer).size(); i++) {
- List<PartialPath> list = new ArrayList<>(currentList);
+ List<T> list = new ArrayList<>(currentList);
list.add(dimensionValue.get(layer).get(i));
resultList.add(list);
}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ILogicalOptimizer.java b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ILogicalOptimizer.java
index 26ab0a5..d851f7e 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ILogicalOptimizer.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ILogicalOptimizer.java
@@ -26,6 +26,6 @@ import org.apache.iotdb.db.qp.logical.Operator;
@FunctionalInterface
public interface ILogicalOptimizer {
- Operator transform(Operator operator, int maxDeduplicatedPathNum)
+ Operator transform(Operator operator, int fetchSize)
throws LogicalOptimizeException, PathNumOverLimitException;
}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/RemoveNotOptimizer.java b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/RemoveNotOptimizer.java
index 598a884..099bcd9 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/RemoveNotOptimizer.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/RemoveNotOptimizer.java
@@ -20,11 +20,13 @@ package org.apache.iotdb.db.qp.strategy.optimizer;
import org.apache.iotdb.db.exception.query.LogicalOperatorException;
import org.apache.iotdb.db.exception.query.LogicalOptimizeException;
+import org.apache.iotdb.db.metadata.PartialPath;
import org.apache.iotdb.db.qp.constant.SQLConstant;
import org.apache.iotdb.db.qp.logical.crud.FilterOperator;
import org.apache.iotdb.db.qp.logical.crud.FunctionOperator;
import java.util.List;
+import java.util.Set;
import static org.apache.iotdb.db.qp.constant.SQLConstant.KW_AND;
import static org.apache.iotdb.db.qp.constant.SQLConstant.KW_NOT;
@@ -41,7 +43,10 @@ public class RemoveNotOptimizer implements IFilterOptimizer {
*/
@Override
public FilterOperator optimize(FilterOperator filter) throws LogicalOperatorException {
- return removeNot(filter);
+ Set<PartialPath> pathSet = filter.getPathSet();
+ FilterOperator optimizedFilterOperator = removeNot(filter);
+ optimizedFilterOperator.setPathSet(pathSet);
+ return optimizedFilterOperator;
}
private FilterOperator removeNot(FilterOperator filter) throws LogicalOperatorException {
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/utils/WildcardsRemover.java b/server/src/main/java/org/apache/iotdb/db/qp/utils/WildcardsRemover.java
new file mode 100644
index 0000000..eb3e02b
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/qp/utils/WildcardsRemover.java
@@ -0,0 +1,160 @@
+/*
+ * 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.utils;
+
+import org.apache.iotdb.db.exception.metadata.MetadataException;
+import org.apache.iotdb.db.exception.query.LogicalOptimizeException;
+import org.apache.iotdb.db.exception.query.PathNumOverLimitException;
+import org.apache.iotdb.db.metadata.PartialPath;
+import org.apache.iotdb.db.qp.logical.crud.QueryOperator;
+import org.apache.iotdb.db.qp.strategy.optimizer.ConcatPathOptimizer;
+import org.apache.iotdb.db.query.control.QueryResourceManager;
+import org.apache.iotdb.db.query.expression.Expression;
+import org.apache.iotdb.db.query.expression.ResultColumn;
+import org.apache.iotdb.db.service.IoTDB;
+import org.apache.iotdb.tsfile.utils.Pair;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/** Removes wildcards (applying memory control and slimit/soffset control) */
+public class WildcardsRemover {
+
+ private final int maxDeduplicatedPathNum;
+ private final int soffset;
+
+ private int currentOffset;
+ private int currentLimit;
+
+ /** Records the path number that the MManager totally returned. */
+ private int consumed;
+
+ public WildcardsRemover(QueryOperator queryOperator, int fetchSize) {
+ // 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
+ // set it to Integer.MAX_VALUE - 1
+ maxDeduplicatedPathNum =
+ queryOperator.isLastQuery()
+ ? Integer.MAX_VALUE - 1
+ : QueryResourceManager.getInstance().getMaxDeduplicatedPathNum(fetchSize);
+ soffset = queryOperator.getSeriesOffset();
+ currentOffset = soffset;
+
+ final int slimit = queryOperator.getSeriesLimit();
+ currentLimit =
+ slimit == 0 || maxDeduplicatedPathNum < slimit ? maxDeduplicatedPathNum + 1 : slimit;
+
+ consumed = 0;
+ }
+
+ public WildcardsRemover() {
+ maxDeduplicatedPathNum = Integer.MAX_VALUE - 1;
+ soffset = 0;
+ currentLimit = maxDeduplicatedPathNum + 1;
+ consumed = 0;
+ }
+
+ public List<PartialPath> removeWildcardFrom(PartialPath path) throws LogicalOptimizeException {
+ try {
+ Pair<List<PartialPath>, Integer> pair =
+ IoTDB.metaManager.getAllTimeseriesPathWithAlias(path, currentLimit, currentOffset);
+
+ consumed += pair.right;
+ if (currentOffset != 0) {
+ int delta = currentOffset - pair.right;
+ currentOffset = Math.max(delta, 0);
+ if (delta < 0) {
+ currentLimit += delta;
+ }
+ } else {
+ currentLimit -= pair.right;
+ }
+
+ return pair.left;
+ } catch (MetadataException e) {
+ throw new LogicalOptimizeException("error occurred when removing star: " + e.getMessage());
+ }
+ }
+
+ public List<List<Expression>> removeWildcardsFrom(List<Expression> expressions)
+ throws LogicalOptimizeException {
+ // One by one, remove the wildcards from the input expressions. In most cases, an expression
+ // will produce multiple expressions after removing the wildcards. We use extendedExpressions to
+ // collect the produced expressions.
+ List<List<Expression>> extendedExpressions = new ArrayList<>();
+ for (Expression originExpression : expressions) {
+ List<Expression> actualExpressions = new ArrayList<>();
+ originExpression.removeWildcards(new WildcardsRemover(), actualExpressions);
+ if (actualExpressions.isEmpty()) {
+ // Let's ignore the eval of the function which has at least one non-existence series as
+ // input. See IOTDB-1212: https://github.com/apache/iotdb/pull/3101
+ return Collections.emptyList();
+ }
+ extendedExpressions.add(actualExpressions);
+ }
+
+ // Calculate the Cartesian product of extendedExpressions to get the actual expressions after
+ // removing all wildcards. We use actualExpressions to collect them.
+ List<List<Expression>> actualExpressions = new ArrayList<>();
+ ConcatPathOptimizer.cartesianProduct(
+ extendedExpressions, actualExpressions, 0, new ArrayList<>());
+
+ // Apply the soffset & slimit control to the actualExpressions and return the remaining
+ // expressions.
+ List<List<Expression>> remainingExpressions = new ArrayList<>();
+ for (List<Expression> actualExpression : actualExpressions) {
+ if (currentOffset != 0) {
+ --currentOffset;
+ continue;
+ } else if (currentLimit != 0) {
+ --currentLimit;
+ } else {
+ break;
+ }
+ remainingExpressions.add(actualExpression);
+ }
+ consumed += actualExpressions.size();
+ return remainingExpressions;
+ }
+
+ /** @return should break the loop or not */
+ public boolean checkIfPathNumberIsOverLimit(List<ResultColumn> resultColumns)
+ throws PathNumOverLimitException {
+ if (currentLimit == 0) {
+ if (maxDeduplicatedPathNum < resultColumns.size()) {
+ throw new PathNumOverLimitException(maxDeduplicatedPathNum);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public void checkIfSoffsetIsExceeded(List<ResultColumn> resultColumns)
+ throws LogicalOptimizeException {
+ if (consumed == 0 ? soffset != 0 : resultColumns.isEmpty()) {
+ throw new LogicalOptimizeException(
+ String.format(
+ "The value of SOFFSET (%d) is equal to or exceeds the number of sequences (%d) that can actually be returned.",
+ soffset, consumed));
+ }
+ }
+}
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/executor/LastQueryExecutor.java b/server/src/main/java/org/apache/iotdb/db/query/executor/LastQueryExecutor.java
index d6a3169..4100964 100644
--- a/server/src/main/java/org/apache/iotdb/db/query/executor/LastQueryExecutor.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/executor/LastQueryExecutor.java
@@ -101,16 +101,10 @@ public class LastQueryExecutor {
if (lastPairList.get(i).right != null && lastPairList.get(i).right.getValue() != null) {
TimeValuePair lastTimeValuePair = lastPairList.get(i).right;
RowRecord resultRecord = new RowRecord(lastTimeValuePair.getTimestamp());
+
Field pathField = new Field(TSDataType.TEXT);
- if (selectedSeries.get(i).isTsAliasExists()) {
- pathField.setBinaryV(new Binary(selectedSeries.get(i).getTsAlias()));
- } else {
- if (selectedSeries.get(i).isMeasurementAliasExists()) {
- pathField.setBinaryV(new Binary(selectedSeries.get(i).getFullPathWithAlias()));
- } else {
- pathField.setBinaryV(new Binary(selectedSeries.get(i).getFullPath()));
- }
- }
+ pathField.setBinaryV(
+ new Binary(lastQueryPlan.getResultColumns().get(i).getResultColumnName()));
resultRecord.addField(pathField);
Field valueField = new Field(TSDataType.TEXT);
diff --git a/cluster/src/main/java/org/apache/iotdb/cluster/query/ClusterConcatPathOptimizer.java b/server/src/main/java/org/apache/iotdb/db/query/expression/Expression.java
similarity index 54%
copy from cluster/src/main/java/org/apache/iotdb/cluster/query/ClusterConcatPathOptimizer.java
copy to server/src/main/java/org/apache/iotdb/db/query/expression/Expression.java
index 5d67a8c..b0c5f60 100644
--- a/cluster/src/main/java/org/apache/iotdb/cluster/query/ClusterConcatPathOptimizer.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/expression/Expression.java
@@ -17,21 +17,34 @@
* under the License.
*/
-package org.apache.iotdb.cluster.query;
+package org.apache.iotdb.db.query.expression;
import org.apache.iotdb.db.exception.metadata.MetadataException;
+import org.apache.iotdb.db.exception.query.LogicalOptimizeException;
import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.qp.strategy.optimizer.ConcatPathOptimizer;
-import org.apache.iotdb.db.service.IoTDB;
-import org.apache.iotdb.tsfile.utils.Pair;
+import org.apache.iotdb.db.qp.utils.WildcardsRemover;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import java.util.List;
+import java.util.Set;
-public class ClusterConcatPathOptimizer extends ConcatPathOptimizer {
+public interface Expression {
- @Override
- protected Pair<List<PartialPath>, Integer> removeWildcard(PartialPath path, int limit, int offset)
- throws MetadataException {
- return IoTDB.metaManager.getAllTimeseriesPathWithAlias(path, limit, offset);
+ default boolean isAggregationFunctionExpression() {
+ return false;
}
+
+ default boolean isTimeSeriesGeneratingFunctionExpression() {
+ return false;
+ }
+
+ // TODO: implement this method
+ TSDataType dataType() throws MetadataException;
+
+ void concat(List<PartialPath> prefixPaths, List<Expression> resultExpressions);
+
+ void removeWildcards(WildcardsRemover wildcardsRemover, List<Expression> resultExpressions)
+ throws LogicalOptimizeException;
+
+ void collectPaths(Set<PartialPath> pathSet);
}
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
new file mode 100644
index 0000000..2cd6269
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/query/expression/ResultColumn.java
@@ -0,0 +1,139 @@
+/*
+ * 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.expression;
+
+import org.apache.iotdb.db.exception.query.LogicalOptimizeException;
+import org.apache.iotdb.db.metadata.PartialPath;
+import org.apache.iotdb.db.qp.utils.WildcardsRemover;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * {@code ResultColumn} is used to represent a result column of a query.
+ *
+ * <p>Assume that we have time series in db as follows: <br>
+ * [ root.sg.d.a, root.sg.d.b, root.sg.e.a, root.sg.e.b ]
+ *
+ * <ul>
+ * Example 1: select a, a + b, udf(udf(b)) from root.sg.d, root.sg.e;
+ * <li>Step 1: constructed by sql visitor in logical operator: <br>
+ * result columns: <br>
+ * [a, a + b, udf(udf(b))]
+ * <li>Step 2: concatenated with prefix paths in logical optimizer:<br>
+ * result columns: <br>
+ * [root.sg.d.a, root.sg.e.a, root.sg.d.a + root.sg.d.b, root.sg.d.a + root.sg.e.b,
+ * root.sg.e.a + root.sg.d.b, root.sg.e.a + root.sg.e.b, udf(udf(root.sg.d.b)),
+ * udf(udf(root.sg.e.b))]
+ * <li>Step 3: remove wildcards in logical optimizer:<br>
+ * result columns: <br>
+ * [root.sg.d.a, root.sg.e.a, root.sg.d.a + root.sg.d.b, root.sg.d.a + root.sg.e.b,
+ * root.sg.e.a + root.sg.d.b, root.sg.e.a + root.sg.e.b, udf(udf(root.sg.d.b)),
+ * udf(udf(root.sg.e.b))]
+ * </ul>
+ *
+ * <ul>
+ * Example 2: select *, a + *, udf(udf(*)) from root.sg.d;
+ * <li>Step 1: constructed by sql visitor in logical operator: <br>
+ * result columns: <br>
+ * [*, a + * , udf(udf(*))]
+ * <li>Step 2: concatenated with prefix paths in logical optimizer:<br>
+ * result columns: <br>
+ * [root.sg.d.*, root.sg.d.a + root.sg.d.*, udf(udf(root.sg.d.*))]
+ * <li>Step 3: remove wildcards in logical optimizer:<br>
+ * result columns: <br>
+ * [root.sg.d.a, root.sg.d.b, root.sg.d.a + root.sg.d.a, root.sg.d.a + root.sg.d.b,
+ * udf(udf(root.sg.d.a)), udf(udf(root.sg.d.b))]
+ * </ul>
+ */
+public class ResultColumn {
+
+ private final Expression expression;
+ private final String alias;
+
+ public ResultColumn(Expression expression, String alias) {
+ this.expression = expression;
+ this.alias = alias;
+ }
+
+ public ResultColumn(Expression expression) {
+ this.expression = expression;
+ alias = null;
+ }
+
+ /**
+ * @param prefixPaths prefix paths in the from clause
+ * @param resultColumns used to collect the result columns
+ */
+ public void concat(List<PartialPath> prefixPaths, List<ResultColumn> resultColumns)
+ throws LogicalOptimizeException {
+ List<Expression> resultExpressions = new ArrayList<>();
+ expression.concat(prefixPaths, resultExpressions);
+ if (hasAlias() && 1 < resultExpressions.size()) {
+ throw new LogicalOptimizeException(
+ String.format("alias '%s' can only be matched with one time series", alias));
+ }
+ for (Expression resultExpression : resultExpressions) {
+ resultColumns.add(new ResultColumn(resultExpression, alias));
+ }
+ }
+
+ /**
+ * @param wildcardsRemover used to remove wildcards from {@code expression} and apply slimit &
+ * soffset control
+ * @param resultColumns used to collect the result columns
+ */
+ public void removeWildcards(WildcardsRemover wildcardsRemover, List<ResultColumn> resultColumns)
+ throws LogicalOptimizeException {
+ List<Expression> resultExpressions = new ArrayList<>();
+ expression.removeWildcards(wildcardsRemover, resultExpressions);
+ if (hasAlias() && 1 < resultExpressions.size()) {
+ throw new LogicalOptimizeException(
+ String.format("alias '%s' can only be matched with one time series", alias));
+ }
+ for (Expression resultExpression : resultExpressions) {
+ resultColumns.add(new ResultColumn(resultExpression, alias));
+ }
+ }
+
+ public Set<PartialPath> collectPaths() {
+ Set<PartialPath> pathSet = new HashSet<>();
+ expression.collectPaths(pathSet);
+ return pathSet;
+ }
+
+ public Expression getExpression() {
+ return expression;
+ }
+
+ public boolean hasAlias() {
+ return alias != null;
+ }
+
+ public String getAlias() {
+ return alias;
+ }
+
+ public String getResultColumnName() {
+ return alias != null ? alias : expression.toString();
+ }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ILogicalOptimizer.java b/server/src/main/java/org/apache/iotdb/db/query/expression/binary/AdditionExpression.java
similarity index 62%
copy from server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ILogicalOptimizer.java
copy to server/src/main/java/org/apache/iotdb/db/query/expression/binary/AdditionExpression.java
index 26ab0a5..5500ba4 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ILogicalOptimizer.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/expression/binary/AdditionExpression.java
@@ -16,16 +16,19 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.iotdb.db.qp.strategy.optimizer;
-import org.apache.iotdb.db.exception.query.LogicalOptimizeException;
-import org.apache.iotdb.db.exception.query.PathNumOverLimitException;
-import org.apache.iotdb.db.qp.logical.Operator;
+package org.apache.iotdb.db.query.expression.binary;
-/** provide a context, transform it for optimization. */
-@FunctionalInterface
-public interface ILogicalOptimizer {
+import org.apache.iotdb.db.query.expression.Expression;
- Operator transform(Operator operator, int maxDeduplicatedPathNum)
- throws LogicalOptimizeException, PathNumOverLimitException;
+public class AdditionExpression extends BinaryExpression {
+
+ public AdditionExpression(Expression leftExpression, Expression rightExpression) {
+ super(leftExpression, rightExpression);
+ }
+
+ @Override
+ protected String operator() {
+ return "+";
+ }
}
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
new file mode 100644
index 0000000..cff5bc3
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/query/expression/binary/BinaryExpression.java
@@ -0,0 +1,118 @@
+/*
+ * 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.expression.binary;
+
+import org.apache.iotdb.db.exception.query.LogicalOptimizeException;
+import org.apache.iotdb.db.metadata.PartialPath;
+import org.apache.iotdb.db.qp.utils.WildcardsRemover;
+import org.apache.iotdb.db.query.expression.Expression;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+public abstract class BinaryExpression implements Expression {
+
+ protected final Expression leftExpression;
+ protected final Expression rightExpression;
+
+ protected BinaryExpression(Expression leftExpression, Expression rightExpression) {
+ this.leftExpression = leftExpression;
+ this.rightExpression = rightExpression;
+ }
+
+ /**
+ * The result data type of all arithmetic operations will be DOUBLE.
+ *
+ * <p>TODO: This is just a simple implementation and should be optimized later.
+ */
+ @Override
+ public final TSDataType dataType() {
+ return TSDataType.DOUBLE;
+ }
+
+ @Override
+ public final void concat(List<PartialPath> prefixPaths, List<Expression> resultExpressions) {
+ List<Expression> leftExpressions = new ArrayList<>();
+ leftExpression.concat(prefixPaths, leftExpressions);
+
+ List<Expression> rightExpressions = new ArrayList<>();
+ rightExpression.concat(prefixPaths, rightExpressions);
+
+ reconstruct(leftExpressions, rightExpressions, resultExpressions);
+ }
+
+ @Override
+ public final void removeWildcards(
+ WildcardsRemover wildcardsRemover, List<Expression> resultExpressions)
+ throws LogicalOptimizeException {
+ List<Expression> leftExpressions = new ArrayList<>();
+ leftExpression.removeWildcards(wildcardsRemover, leftExpressions);
+
+ List<Expression> rightExpressions = new ArrayList<>();
+ rightExpression.removeWildcards(wildcardsRemover, rightExpressions);
+
+ reconstruct(leftExpressions, rightExpressions, resultExpressions);
+ }
+
+ private void reconstruct(
+ List<Expression> leftExpressions,
+ List<Expression> rightExpressions,
+ List<Expression> resultExpressions) {
+ for (Expression le : leftExpressions) {
+ for (Expression re : rightExpressions) {
+ switch (operator()) {
+ case "+":
+ resultExpressions.add(new AdditionExpression(le, re));
+ break;
+ case "-":
+ resultExpressions.add(new SubtractionExpression(le, re));
+ break;
+ case "*":
+ resultExpressions.add(new MultiplicationExpression(le, re));
+ break;
+ case "/":
+ resultExpressions.add(new DivisionExpression(le, re));
+ break;
+ case "%":
+ resultExpressions.add(new ModuloExpression(le, re));
+ break;
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void collectPaths(Set<PartialPath> pathSet) {
+ leftExpression.collectPaths(pathSet);
+ rightExpression.collectPaths(pathSet);
+ }
+
+ @Override
+ public final String toString() {
+ return String.format(
+ "%s %s %s", leftExpression.toString(), operator(), rightExpression.toString());
+ }
+
+ protected abstract String operator();
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ILogicalOptimizer.java b/server/src/main/java/org/apache/iotdb/db/query/expression/binary/DivisionExpression.java
similarity index 62%
copy from server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ILogicalOptimizer.java
copy to server/src/main/java/org/apache/iotdb/db/query/expression/binary/DivisionExpression.java
index 26ab0a5..e611887 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ILogicalOptimizer.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/expression/binary/DivisionExpression.java
@@ -16,16 +16,19 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.iotdb.db.qp.strategy.optimizer;
-import org.apache.iotdb.db.exception.query.LogicalOptimizeException;
-import org.apache.iotdb.db.exception.query.PathNumOverLimitException;
-import org.apache.iotdb.db.qp.logical.Operator;
+package org.apache.iotdb.db.query.expression.binary;
-/** provide a context, transform it for optimization. */
-@FunctionalInterface
-public interface ILogicalOptimizer {
+import org.apache.iotdb.db.query.expression.Expression;
- Operator transform(Operator operator, int maxDeduplicatedPathNum)
- throws LogicalOptimizeException, PathNumOverLimitException;
+public class DivisionExpression extends BinaryExpression {
+
+ public DivisionExpression(Expression leftExpression, Expression rightExpression) {
+ super(leftExpression, rightExpression);
+ }
+
+ @Override
+ protected String operator() {
+ return "/";
+ }
}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ILogicalOptimizer.java b/server/src/main/java/org/apache/iotdb/db/query/expression/binary/ModuloExpression.java
similarity index 62%
copy from server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ILogicalOptimizer.java
copy to server/src/main/java/org/apache/iotdb/db/query/expression/binary/ModuloExpression.java
index 26ab0a5..94dd905 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ILogicalOptimizer.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/expression/binary/ModuloExpression.java
@@ -16,16 +16,19 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.iotdb.db.qp.strategy.optimizer;
-import org.apache.iotdb.db.exception.query.LogicalOptimizeException;
-import org.apache.iotdb.db.exception.query.PathNumOverLimitException;
-import org.apache.iotdb.db.qp.logical.Operator;
+package org.apache.iotdb.db.query.expression.binary;
-/** provide a context, transform it for optimization. */
-@FunctionalInterface
-public interface ILogicalOptimizer {
+import org.apache.iotdb.db.query.expression.Expression;
- Operator transform(Operator operator, int maxDeduplicatedPathNum)
- throws LogicalOptimizeException, PathNumOverLimitException;
+public class ModuloExpression extends BinaryExpression {
+
+ public ModuloExpression(Expression leftExpression, Expression rightExpression) {
+ super(leftExpression, rightExpression);
+ }
+
+ @Override
+ protected String operator() {
+ return "%";
+ }
}
diff --git a/cluster/src/main/java/org/apache/iotdb/cluster/query/ClusterConcatPathOptimizer.java b/server/src/main/java/org/apache/iotdb/db/query/expression/binary/MultiplicationExpression.java
similarity index 57%
rename from cluster/src/main/java/org/apache/iotdb/cluster/query/ClusterConcatPathOptimizer.java
rename to server/src/main/java/org/apache/iotdb/db/query/expression/binary/MultiplicationExpression.java
index 5d67a8c..ae3d17b 100644
--- a/cluster/src/main/java/org/apache/iotdb/cluster/query/ClusterConcatPathOptimizer.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/expression/binary/MultiplicationExpression.java
@@ -17,21 +17,18 @@
* under the License.
*/
-package org.apache.iotdb.cluster.query;
+package org.apache.iotdb.db.query.expression.binary;
-import org.apache.iotdb.db.exception.metadata.MetadataException;
-import org.apache.iotdb.db.metadata.PartialPath;
-import org.apache.iotdb.db.qp.strategy.optimizer.ConcatPathOptimizer;
-import org.apache.iotdb.db.service.IoTDB;
-import org.apache.iotdb.tsfile.utils.Pair;
+import org.apache.iotdb.db.query.expression.Expression;
-import java.util.List;
+public class MultiplicationExpression extends BinaryExpression {
-public class ClusterConcatPathOptimizer extends ConcatPathOptimizer {
+ public MultiplicationExpression(Expression leftExpression, Expression rightExpression) {
+ super(leftExpression, rightExpression);
+ }
@Override
- protected Pair<List<PartialPath>, Integer> removeWildcard(PartialPath path, int limit, int offset)
- throws MetadataException {
- return IoTDB.metaManager.getAllTimeseriesPathWithAlias(path, limit, offset);
+ protected String operator() {
+ return "*";
}
}
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ILogicalOptimizer.java b/server/src/main/java/org/apache/iotdb/db/query/expression/binary/SubtractionExpression.java
similarity index 62%
copy from server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ILogicalOptimizer.java
copy to server/src/main/java/org/apache/iotdb/db/query/expression/binary/SubtractionExpression.java
index 26ab0a5..65bcf50 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/strategy/optimizer/ILogicalOptimizer.java
+++ b/server/src/main/java/org/apache/iotdb/db/query/expression/binary/SubtractionExpression.java
@@ -16,16 +16,19 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.iotdb.db.qp.strategy.optimizer;
-import org.apache.iotdb.db.exception.query.LogicalOptimizeException;
-import org.apache.iotdb.db.exception.query.PathNumOverLimitException;
-import org.apache.iotdb.db.qp.logical.Operator;
+package org.apache.iotdb.db.query.expression.binary;
-/** provide a context, transform it for optimization. */
-@FunctionalInterface
-public interface ILogicalOptimizer {
+import org.apache.iotdb.db.query.expression.Expression;
- Operator transform(Operator operator, int maxDeduplicatedPathNum)
- throws LogicalOptimizeException, PathNumOverLimitException;
+public class SubtractionExpression extends BinaryExpression {
+
+ public SubtractionExpression(Expression leftExpression, Expression rightExpression) {
+ super(leftExpression, rightExpression);
+ }
+
+ @Override
+ protected String operator() {
+ return "-";
+ }
}
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
new file mode 100644
index 0000000..a321f97
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/query/expression/unary/FunctionExpression.java
@@ -0,0 +1,232 @@
+/*
+ * 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.expression.unary;
+
+import org.apache.iotdb.db.exception.metadata.MetadataException;
+import org.apache.iotdb.db.exception.query.LogicalOptimizeException;
+import org.apache.iotdb.db.metadata.PartialPath;
+import org.apache.iotdb.db.qp.constant.SQLConstant;
+import org.apache.iotdb.db.qp.strategy.optimizer.ConcatPathOptimizer;
+import org.apache.iotdb.db.qp.utils.WildcardsRemover;
+import org.apache.iotdb.db.query.expression.Expression;
+import org.apache.iotdb.tsfile.exception.NotImplementedException;
+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;
+import java.util.Set;
+
+public class FunctionExpression implements Expression {
+
+ /**
+ * true: aggregation function<br>
+ * false: time series generating function
+ */
+ private final boolean isAggregationFunctionExpression;
+
+ private final String functionName;
+ private final Map<String, String> functionAttributes;
+
+ /**
+ * example: select udf(a, b, udf(c)) from root.sg.d;
+ *
+ * <p>3 expressions [root.sg.d.a, root.sg.d.b, udf(root.sg.d.c)] will be in this field.
+ */
+ private List<Expression> expressions;
+
+ private List<TSDataType> dataTypes;
+ private List<PartialPath> paths;
+
+ private String expressionString;
+ private String parametersString;
+
+ public FunctionExpression(String functionName) {
+ this.functionName = functionName;
+ functionAttributes = new LinkedHashMap<>();
+ expressions = new ArrayList<>();
+ isAggregationFunctionExpression =
+ SQLConstant.getNativeFunctionNames().contains(functionName.toLowerCase());
+ }
+
+ public FunctionExpression(
+ String functionName, Map<String, String> functionAttributes, List<Expression> expressions) {
+ this.functionName = functionName;
+ this.functionAttributes = functionAttributes;
+ this.expressions = expressions;
+ isAggregationFunctionExpression =
+ SQLConstant.getNativeFunctionNames().contains(functionName.toLowerCase());
+ }
+
+ @Override
+ public boolean isAggregationFunctionExpression() {
+ return isAggregationFunctionExpression;
+ }
+
+ @Override
+ public boolean isTimeSeriesGeneratingFunctionExpression() {
+ return !isAggregationFunctionExpression;
+ }
+
+ public void addAttribute(String key, String value) {
+ functionAttributes.put(key, value);
+ }
+
+ public void addExpression(Expression expression) {
+ expressions.add(expression);
+ }
+
+ public void setExpressions(List<Expression> expressions) {
+ this.expressions = expressions;
+ }
+
+ public String getFunctionName() {
+ return functionName;
+ }
+
+ public Map<String, String> getFunctionAttributes() {
+ return functionAttributes;
+ }
+
+ public List<Expression> getExpressions() {
+ return expressions;
+ }
+
+ @Override
+ public TSDataType dataType() {
+ // TODO: the expression type is determined in runtime
+ throw new NotImplementedException();
+ }
+
+ @Override
+ public void concat(List<PartialPath> prefixPaths, List<Expression> resultExpressions) {
+ List<List<Expression>> resultExpressionsForRecursionList = new ArrayList<>();
+
+ for (Expression suffixExpression : expressions) {
+ List<Expression> resultExpressionsForRecursion = new ArrayList<>();
+ suffixExpression.concat(prefixPaths, resultExpressionsForRecursion);
+ resultExpressionsForRecursionList.add(resultExpressionsForRecursion);
+ }
+
+ List<List<Expression>> functionExpressions = new ArrayList<>();
+ ConcatPathOptimizer.cartesianProduct(
+ resultExpressionsForRecursionList, functionExpressions, 0, new ArrayList<>());
+ for (List<Expression> functionExpression : functionExpressions) {
+ resultExpressions.add(
+ new FunctionExpression(functionName, functionAttributes, functionExpression));
+ }
+ }
+
+ @Override
+ public void removeWildcards(WildcardsRemover wildcardsRemover, List<Expression> resultExpressions)
+ throws LogicalOptimizeException {
+ for (List<Expression> functionExpression : wildcardsRemover.removeWildcardsFrom(expressions)) {
+ resultExpressions.add(
+ new FunctionExpression(functionName, functionAttributes, functionExpression));
+ }
+ }
+
+ @Override
+ public void collectPaths(Set<PartialPath> pathSet) {
+ for (Expression expression : expressions) {
+ expression.collectPaths(pathSet);
+ }
+ }
+
+ public List<TSDataType> getDataTypes() throws MetadataException {
+ if (dataTypes == null) {
+ dataTypes = new ArrayList<>();
+ for (Expression expression : expressions) {
+ dataTypes.add(expression.dataType());
+ }
+ }
+ return dataTypes;
+ }
+
+ public List<PartialPath> getPaths() {
+ if (paths == null) {
+ paths = new ArrayList<>();
+ for (Expression expression : expressions) {
+ paths.add(
+ expression instanceof TimeSeriesOperand
+ ? ((TimeSeriesOperand) expression).getPath()
+ : null);
+ }
+ }
+ return paths;
+ }
+
+ @Override
+ public String toString() {
+ if (expressionString == null) {
+ expressionString = functionName + "(" + getParametersString() + ")";
+ }
+ return expressionString;
+ }
+
+ /**
+ * Generates the parameter part of the function column name.
+ *
+ * <p>Example:
+ *
+ * <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'
+ */
+ public String getParametersString() {
+ if (parametersString == null) {
+ StringBuilder builder = new StringBuilder();
+ if (!expressions.isEmpty()) {
+ builder.append(expressions.get(0).toString());
+ for (int i = 1; i < expressions.size(); ++i) {
+ builder.append(", ").append(expressions.get(i).toString());
+ }
+ }
+ if (!functionAttributes.isEmpty()) {
+ if (!expressions.isEmpty()) {
+ builder.append(", ");
+ }
+ Iterator<Entry<String, String>> iterator = functionAttributes.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("\"");
+ }
+ }
+ parametersString = builder.toString();
+ }
+ return parametersString;
+ }
+}
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
new file mode 100644
index 0000000..afd0017
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/query/expression/unary/MinusExpression.java
@@ -0,0 +1,78 @@
+/*
+ * 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.expression.unary;
+
+import org.apache.iotdb.db.exception.metadata.MetadataException;
+import org.apache.iotdb.db.exception.query.LogicalOptimizeException;
+import org.apache.iotdb.db.metadata.PartialPath;
+import org.apache.iotdb.db.qp.utils.WildcardsRemover;
+import org.apache.iotdb.db.query.expression.Expression;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+public class MinusExpression implements Expression {
+
+ protected Expression expression;
+
+ public MinusExpression(Expression expression) {
+ this.expression = expression;
+ }
+
+ public Expression getExpression() {
+ return expression;
+ }
+
+ @Override
+ public TSDataType dataType() throws MetadataException {
+ return expression.dataType();
+ }
+
+ @Override
+ public void concat(List<PartialPath> prefixPaths, List<Expression> resultExpressions) {
+ List<Expression> resultExpressionsForRecursion = new ArrayList<>();
+ expression.concat(prefixPaths, resultExpressionsForRecursion);
+ for (Expression resultExpression : resultExpressionsForRecursion) {
+ resultExpressions.add(new MinusExpression(resultExpression));
+ }
+ }
+
+ @Override
+ public void removeWildcards(WildcardsRemover wildcardsRemover, List<Expression> resultExpressions)
+ throws LogicalOptimizeException {
+ List<Expression> resultExpressionsForRecursion = new ArrayList<>();
+ expression.removeWildcards(wildcardsRemover, resultExpressionsForRecursion);
+ for (Expression resultExpression : resultExpressionsForRecursion) {
+ resultExpressions.add(new MinusExpression(resultExpression));
+ }
+ }
+
+ @Override
+ public void collectPaths(Set<PartialPath> pathSet) {
+ expression.collectPaths(pathSet);
+ }
+
+ @Override
+ public String toString() {
+ return "-" + expression.toString();
+ }
+}
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
new file mode 100644
index 0000000..e69353c
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/query/expression/unary/TimeSeriesOperand.java
@@ -0,0 +1,82 @@
+/*
+ * 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.expression.unary;
+
+import org.apache.iotdb.db.exception.metadata.MetadataException;
+import org.apache.iotdb.db.exception.query.LogicalOptimizeException;
+import org.apache.iotdb.db.metadata.PartialPath;
+import org.apache.iotdb.db.qp.utils.WildcardsRemover;
+import org.apache.iotdb.db.query.expression.Expression;
+import org.apache.iotdb.db.service.IoTDB;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+
+import java.util.List;
+import java.util.Set;
+
+public class TimeSeriesOperand implements Expression {
+
+ protected PartialPath path;
+ protected TSDataType dataType;
+
+ public TimeSeriesOperand(PartialPath path) {
+ this.path = path;
+ }
+
+ public PartialPath getPath() {
+ return path;
+ }
+
+ public void setPath(PartialPath path) {
+ this.path = path;
+ }
+
+ @Override
+ public TSDataType dataType() throws MetadataException {
+ if (dataType == null) {
+ dataType = IoTDB.metaManager.getSeriesType(path);
+ }
+ return dataType;
+ }
+
+ @Override
+ public void concat(List<PartialPath> prefixPaths, List<Expression> resultExpressions) {
+ for (PartialPath prefixPath : prefixPaths) {
+ resultExpressions.add(new TimeSeriesOperand(prefixPath.concatPath(path)));
+ }
+ }
+
+ @Override
+ public void removeWildcards(WildcardsRemover wildcardsRemover, List<Expression> resultExpressions)
+ throws LogicalOptimizeException {
+ for (PartialPath actualPath : wildcardsRemover.removeWildcardFrom(path)) {
+ resultExpressions.add(new TimeSeriesOperand(actualPath));
+ }
+ }
+
+ @Override
+ public void collectPaths(Set<PartialPath> pathSet) {
+ pathSet.add(path);
+ }
+
+ @Override
+ public String toString() {
+ return path.isMeasurementAliasExists() ? path.getFullPathWithAlias() : path.getFullPath();
+ }
+}
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 15d2b35..fc8c344 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
@@ -82,6 +82,8 @@ import org.apache.iotdb.db.query.dataset.AlignByDeviceDataSet;
import org.apache.iotdb.db.query.dataset.DirectAlignByTimeDataSet;
import org.apache.iotdb.db.query.dataset.DirectNonAlignDataSet;
import org.apache.iotdb.db.query.dataset.UDTFDataSet;
+import org.apache.iotdb.db.query.expression.ResultColumn;
+import org.apache.iotdb.db.query.expression.unary.TimeSeriesOperand;
import org.apache.iotdb.db.tools.watermark.GroupedLSBWatermarkEncoder;
import org.apache.iotdb.db.tools.watermark.WatermarkEncoder;
import org.apache.iotdb.db.utils.QueryDataSetUtils;
@@ -987,27 +989,18 @@ public class TSServiceImpl implements TSIService.Iface {
}
// wide means not align by device
- @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity warning
private void getWideQueryHeaders(
QueryPlan plan, List<String> respColumns, List<String> columnTypes)
throws TException, MetadataException {
- // Restore column header of aggregate to func(column_name), only
- // support single aggregate function for now
+ List<ResultColumn> resultColumns = plan.getResultColumns();
List<PartialPath> paths = plan.getPaths();
List<TSDataType> seriesTypes = new ArrayList<>();
switch (plan.getOperatorType()) {
case QUERY:
case FILL:
- for (PartialPath path : paths) {
- String column;
- if (path.isTsAliasExists()) {
- column = path.getTsAlias();
- } else {
- column =
- path.isMeasurementAliasExists() ? path.getFullPathWithAlias() : path.getFullPath();
- }
- respColumns.add(column);
- seriesTypes.add(getSeriesTypeByPath(path));
+ for (int i = 0; i < resultColumns.size(); ++i) {
+ respColumns.add(resultColumns.get(i).getResultColumnName());
+ seriesTypes.add(getSeriesTypeByPath(paths.get(i)));
}
break;
case AGGREGATION:
@@ -1019,18 +1012,8 @@ public class TSServiceImpl implements TSIService.Iface {
aggregations.add(aggregations.get(0));
}
}
- for (int i = 0; i < paths.size(); i++) {
- PartialPath path = paths.get(i);
- String column;
- if (path.isTsAliasExists()) {
- column = path.getTsAlias();
- } else {
- column =
- path.isMeasurementAliasExists()
- ? aggregations.get(i) + "(" + paths.get(i).getFullPathWithAlias() + ")"
- : aggregations.get(i) + "(" + paths.get(i).getFullPath() + ")";
- }
- respColumns.add(column);
+ for (ResultColumn resultColumn : resultColumns) {
+ respColumns.add(resultColumn.getResultColumnName());
}
seriesTypes = getSeriesTypesByPaths(paths, aggregations);
break;
@@ -1038,15 +1021,9 @@ public class TSServiceImpl implements TSIService.Iface {
seriesTypes = new ArrayList<>();
UDTFPlan udtfPlan = (UDTFPlan) plan;
for (int i = 0; i < paths.size(); i++) {
- respColumns.add(
- paths.get(i) != null
- ? paths.get(i).getFullPath()
- : udtfPlan
- .getExecutorByOriginalOutputColumnIndex(i)
- .getContext()
- .getColumnName());
+ respColumns.add(resultColumns.get(i).getResultColumnName());
seriesTypes.add(
- paths.get(i) != null
+ resultColumns.get(i).getExpression() instanceof TimeSeriesOperand
? udtfPlan.getDataTypes().get(i)
: udtfPlan
.getExecutorByOriginalOutputColumnIndex(i)
diff --git a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBUDFManagementIT.java b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBUDFManagementIT.java
index f85e012..b970eaf 100644
--- a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBUDFManagementIT.java
+++ b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBUDFManagementIT.java
@@ -223,7 +223,10 @@ public class IoTDBUDFManagementIT {
statement.execute("create function aVg as \"org.apache.iotdb.db.query.udf.example.Adder\"");
fail();
} catch (SQLException throwable) {
- assertTrue(throwable.getMessage().contains("expecting ID"));
+ assertTrue(
+ throwable
+ .getMessage()
+ .contains("the given function name conflicts with the built-in function name"));
}
}
@@ -237,7 +240,10 @@ public class IoTDBUDFManagementIT {
"create function MAX_VALUE as \"org.apache.iotdb.db.query.udf.example.Adder\"");
fail();
} catch (SQLException throwable) {
- assertTrue(throwable.getMessage().contains("expecting ID"));
+ assertTrue(
+ throwable
+ .getMessage()
+ .contains("the given function name conflicts with the built-in function name"));
}
}
diff --git a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBUDTFHybridQueryIT.java b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBUDTFHybridQueryIT.java
index 4ab33dd..0710b24 100644
--- a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBUDTFHybridQueryIT.java
+++ b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBUDTFHybridQueryIT.java
@@ -155,7 +155,8 @@ public class IoTDBUDTFHybridQueryIT {
statement.executeQuery(sql);
fail();
} catch (SQLException throwable) {
- assertTrue(throwable.getMessage().contains("parsing SQL to physical plan"));
+ assertTrue(
+ throwable.getMessage().contains("Last queries can only be applied on raw time series."));
}
}
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..38593cb 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
@@ -41,24 +41,19 @@ import static org.apache.iotdb.db.index.common.IndexConstant.TOP_K;
public class IndexLogicalPlanTest {
- private LogicalGenerator generator;
-
@Before
- public void before() {
- generator = new LogicalGenerator();
- }
+ public void before() {}
@Test
public void testParseCreateIndexWholeMatching() {
String sqlStr =
"CREATE INDEX ON root.Ery.*.Glu WHERE time > 50 WITH INDEX=RTREE_PAA, PAA_dim=8";
- Operator op = generator.generate(sqlStr, ZoneId.systemDefault());
+ Operator op = LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
Assert.assertEquals(CreateIndexOperator.class, op.getClass());
CreateIndexOperator createOperator = (CreateIndexOperator) op;
Assert.assertEquals(OperatorType.CREATE_INDEX, createOperator.getType());
- Assert.assertNotNull(createOperator.getSelectedPaths());
- Assert.assertEquals("root.Ery.*.Glu", createOperator.getSelectedPaths().get(0).toString());
- Assert.assertNull(createOperator.getFromOperator());
+ Assert.assertNotNull(createOperator.getPaths());
+ Assert.assertEquals("root.Ery.*.Glu", createOperator.getPaths().get(0).toString());
Assert.assertEquals(IndexType.RTREE_PAA, createOperator.getIndexType());
Assert.assertEquals(50, createOperator.getTime());
Assert.assertEquals(1, createOperator.getProps().size());
@@ -68,14 +63,12 @@ public class IndexLogicalPlanTest {
@Test
public void testParseCreateIndexSubMatching() {
String sqlStr = "CREATE INDEX ON root.Wind.AZQ02.Speed WITH INDEX=ELB_INDEX, BLOCK_SIZE=5";
- Operator op = generator.generate(sqlStr, ZoneId.systemDefault());
+ Operator op = LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
Assert.assertEquals(CreateIndexOperator.class, op.getClass());
CreateIndexOperator createOperator = (CreateIndexOperator) op;
Assert.assertEquals(OperatorType.CREATE_INDEX, createOperator.getType());
- Assert.assertNotNull(createOperator.getSelectedPaths());
- Assert.assertEquals(
- "root.Wind.AZQ02.Speed", createOperator.getSelectedPaths().get(0).toString());
- Assert.assertNull(createOperator.getFromOperator());
+ Assert.assertNotNull(createOperator.getPaths());
+ Assert.assertEquals("root.Wind.AZQ02.Speed", createOperator.getPaths().get(0).toString());
Assert.assertEquals(IndexType.ELB_INDEX, createOperator.getIndexType());
Assert.assertEquals(1, createOperator.getProps().size());
Assert.assertEquals("5", createOperator.getProps().get(BLOCK_SIZE));
@@ -84,27 +77,24 @@ public class IndexLogicalPlanTest {
@Test
public void testParseDropIndexWholeMatching() {
String sqlStr = "DROP INDEX RTREE_PAA ON root.Ery.*.Glu";
- Operator op = generator.generate(sqlStr, ZoneId.systemDefault());
+ Operator op = LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
Assert.assertEquals(DropIndexOperator.class, op.getClass());
DropIndexOperator dropIndexOperator = (DropIndexOperator) op;
Assert.assertEquals(OperatorType.DROP_INDEX, dropIndexOperator.getType());
- Assert.assertNotNull(dropIndexOperator.getSelectedPaths());
- Assert.assertEquals("root.Ery.*.Glu", dropIndexOperator.getSelectedPaths().get(0).toString());
- Assert.assertNull(dropIndexOperator.getFromOperator());
+ Assert.assertNotNull(dropIndexOperator.getPaths());
+ Assert.assertEquals("root.Ery.*.Glu", dropIndexOperator.getPaths().get(0).toString());
Assert.assertEquals(IndexType.RTREE_PAA, dropIndexOperator.getIndexType());
}
@Test
public void testParseDropIndexSubMatching() {
String sqlStr = "DROP INDEX ELB_INDEX ON root.Wind.AZQ02.Speed";
- Operator op = generator.generate(sqlStr, ZoneId.systemDefault());
+ Operator op = LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
Assert.assertEquals(DropIndexOperator.class, op.getClass());
DropIndexOperator dropIndexOperator = (DropIndexOperator) op;
Assert.assertEquals(OperatorType.DROP_INDEX, dropIndexOperator.getType());
- Assert.assertNotNull(dropIndexOperator.getSelectedPaths());
- Assert.assertEquals(
- "root.Wind.AZQ02.Speed", dropIndexOperator.getSelectedPaths().get(0).toString());
- Assert.assertNull(dropIndexOperator.getFromOperator());
+ Assert.assertNotNull(dropIndexOperator.getPaths());
+ Assert.assertEquals("root.Wind.AZQ02.Speed", dropIndexOperator.getPaths().get(0).toString());
Assert.assertEquals(IndexType.ELB_INDEX, dropIndexOperator.getIndexType());
}
@@ -112,11 +102,13 @@ public class IndexLogicalPlanTest {
public void testParseQueryIndexWholeMatching() {
String sqlStr =
"SELECT TOP 2 Glu FROM root.Ery.* WHERE Glu LIKE (0, 120, 20, 80, 120, 100, 80, 0)";
- Operator op = generator.generate(sqlStr, ZoneId.systemDefault());
+ Operator op = LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
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.getSelectOperator().getResultColumns().get(0).getExpression().toString());
Assert.assertEquals(
"root.Ery.*", queryOperator.getFromOperator().getPrefixPaths().get(0).getFullPath());
Assert.assertEquals(IndexType.RTREE_PAA, queryOperator.getIndexType());
@@ -134,11 +126,13 @@ public class IndexLogicalPlanTest {
+ "CONTAIN (15, 14, 12, 12, 12, 11) WITH TOLERANCE 1 "
+ "CONCAT (10, 20, 25, 24, 14, 8) WITH TOLERANCE 2 "
+ "CONCAT (8, 9, 10, 14, 15, 15) WITH TOLERANCE 1";
- Operator op = generator.generate(sqlStr, ZoneId.systemDefault());
+ Operator op = LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
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.getSelectOperator().getResultColumns().get(0).getExpression().toString());
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..d2e428d 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
@@ -33,7 +33,6 @@ import org.apache.iotdb.db.service.IoTDB;
import org.antlr.v4.runtime.misc.ParseCancellationException;
import org.junit.Assert;
-import org.junit.Before;
import org.junit.Test;
import java.time.ZoneId;
@@ -41,18 +40,11 @@ import java.util.ArrayList;
public class LogicalPlanSmallTest {
- private LogicalGenerator logicalGenerator;
-
- @Before
- public void before() {
- logicalGenerator = new LogicalGenerator();
- }
-
@Test
public void testLimit() {
String sqlStr = "select * from root.vehicle.d1 limit 10";
RootOperator operator =
- (RootOperator) logicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+ (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
Assert.assertEquals(QueryOperator.class, operator.getClass());
Assert.assertEquals(10, ((QueryOperator) operator).getRowLimit());
Assert.assertEquals(0, ((QueryOperator) operator).getRowOffset());
@@ -64,7 +56,7 @@ public class LogicalPlanSmallTest {
public void testOffset() {
String sqlStr = "select * from root.vehicle.d1 limit 10 offset 20";
RootOperator operator =
- (RootOperator) logicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+ (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
Assert.assertEquals(QueryOperator.class, operator.getClass());
Assert.assertEquals(10, ((QueryOperator) operator).getRowLimit());
Assert.assertEquals(20, ((QueryOperator) operator).getRowOffset());
@@ -76,7 +68,7 @@ public class LogicalPlanSmallTest {
public void testSlimit() {
String sqlStr = "select * from root.vehicle.d1 limit 10 slimit 1";
RootOperator operator =
- (RootOperator) logicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+ (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
Assert.assertEquals(QueryOperator.class, operator.getClass());
Assert.assertEquals(10, ((QueryOperator) operator).getRowLimit());
Assert.assertEquals(0, ((QueryOperator) operator).getRowOffset());
@@ -89,7 +81,7 @@ public class LogicalPlanSmallTest {
String sqlStr =
"select * from root.vehicle.d1 where s1 < 20 and time <= now() limit 50 slimit 10 soffset 100";
RootOperator operator =
- (RootOperator) logicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+ (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
Assert.assertEquals(QueryOperator.class, operator.getClass());
Assert.assertEquals(50, ((QueryOperator) operator).getRowLimit());
Assert.assertEquals(0, ((QueryOperator) operator).getRowOffset());
@@ -102,7 +94,7 @@ public class LogicalPlanSmallTest {
String sqlStr =
"select * from root.vehicle.d1 where s1 < 20 and timestamp <= now() limit 50 slimit 10 soffset 100";
RootOperator operator =
- (RootOperator) logicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+ (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
Assert.assertEquals(QueryOperator.class, operator.getClass());
Assert.assertEquals(50, ((QueryOperator) operator).getRowLimit());
Assert.assertEquals(0, ((QueryOperator) operator).getRowOffset());
@@ -115,7 +107,7 @@ public class LogicalPlanSmallTest {
String sqlStr =
"select * from root.vehicle.d1 where s1 < 20 and time <= now() limit 1111111111111111111111";
RootOperator operator =
- (RootOperator) logicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+ (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
// expected to throw SQLParserException: Out of range. LIMIT <N>: N should be Int32.
}
@@ -123,7 +115,7 @@ public class LogicalPlanSmallTest {
public void testLimitNotPositive() {
String sqlStr = "select * from root.vehicle.d1 where s1 < 20 and time <= now() limit 0";
RootOperator operator =
- (RootOperator) logicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+ (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
// expected to throw SQLParserException: LIMIT <N>: N should be greater than 0.
}
@@ -133,7 +125,7 @@ public class LogicalPlanSmallTest {
"select * from root.vehicle.d1 where s1 < 20 and time <= now() "
+ "limit 1 offset 1111111111111111111111";
RootOperator operator =
- (RootOperator) logicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+ (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
// expected to throw SQLParserException: Out of range. OFFSET <OFFSETValue>: OFFSETValue should
// be Int32.
}
@@ -143,7 +135,7 @@ public class LogicalPlanSmallTest {
String sqlStr =
"select * from root.vehicle.d1 where s1 < 20 and time <= now() limit 1 offset -1";
RootOperator operator =
- (RootOperator) logicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+ (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
// expected to throw SQLParserException: OFFSET <OFFSETValue>: OFFSETValue should >= 0.
}
@@ -152,7 +144,7 @@ public class LogicalPlanSmallTest {
String sqlStr =
"select * from root.vehicle.d1 where s1 < 20 and time <= now() slimit 1111111111111111111111";
RootOperator operator =
- (RootOperator) logicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+ (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
// expected to throw SQLParserException: Out of range. SLIMIT <SN>: SN should be Int32.
}
@@ -160,7 +152,7 @@ public class LogicalPlanSmallTest {
public void testSlimitNotPositive() {
String sqlStr = "select * from root.vehicle.d1 where s1 < 20 and time <= now() slimit 0";
RootOperator operator =
- (RootOperator) logicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+ (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
// expected to throw SQLParserException: SLIMIT <SN>: SN should be greater than 0.
}
@@ -170,7 +162,7 @@ public class LogicalPlanSmallTest {
"select * from root.vehicle.d1 where s1 < 20 and time <= now() "
+ "slimit 1 soffset 1111111111111111111111";
RootOperator operator =
- (RootOperator) logicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+ (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
// expected to throw SQLParserException: Out of range. SOFFSET <SOFFSETValue>: SOFFSETValue
// should be Int32.
}
@@ -180,7 +172,7 @@ public class LogicalPlanSmallTest {
String sqlStr =
"select * from root.vehicle.d1 where s1 < 20 and time <= now() slimit 1 soffset 1";
RootOperator operator =
- (RootOperator) logicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+ (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
Assert.assertEquals(1, ((QueryOperator) operator).getSeriesOffset());
Assert.assertEquals(1, ((QueryOperator) operator).getSeriesLimit());
}
@@ -190,7 +182,7 @@ public class LogicalPlanSmallTest {
String sqlStr =
"select s1 from root.vehicle.d1 where s1 < 20 and time <= now() slimit 2 soffset 1";
RootOperator operator =
- (RootOperator) logicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+ (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
IoTDB.metaManager.init();
ConcatPathOptimizer concatPathOptimizer = new ConcatPathOptimizer();
concatPathOptimizer.transform(operator, 1000);
@@ -203,7 +195,7 @@ public class LogicalPlanSmallTest {
public void testDeleteStorageGroup() throws IllegalPathException {
String sqlStr = "delete storage group root.vehicle.d1";
RootOperator operator =
- (RootOperator) logicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+ (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
Assert.assertEquals(DeleteStorageGroupOperator.class, operator.getClass());
PartialPath path = new PartialPath("root.vehicle.d1");
Assert.assertEquals(path, ((DeleteStorageGroupOperator) operator).getDeletePathList().get(0));
@@ -213,7 +205,7 @@ public class LogicalPlanSmallTest {
public void testDisableAlign() {
String sqlStr = "select * from root.vehicle disable align";
RootOperator operator =
- (RootOperator) logicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+ (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
Assert.assertEquals(QueryOperator.class, operator.getClass());
Assert.assertFalse(((QueryOperator) operator).isAlignByTime());
}
@@ -222,7 +214,7 @@ public class LogicalPlanSmallTest {
public void testNotDisableAlign() {
String sqlStr = "select * from root.vehicle";
RootOperator operator =
- (RootOperator) logicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+ (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
Assert.assertEquals(QueryOperator.class, operator.getClass());
Assert.assertTrue(((QueryOperator) operator).isAlignByTime());
}
@@ -231,23 +223,23 @@ public class LogicalPlanSmallTest {
public void testDisableAlignConflictAlignByDevice() {
String sqlStr = "select * from root.vehicle disable align align by device";
RootOperator operator =
- (RootOperator) logicalGenerator.generate(sqlStr, ZoneId.systemDefault());
+ (RootOperator) LogicalGenerator.generate(sqlStr, ZoneId.systemDefault());
}
@Test
public void testChineseCharacter() throws IllegalPathException {
String sqlStr1 = "set storage group to root.一级";
RootOperator operator =
- (RootOperator) logicalGenerator.generate(sqlStr1, ZoneId.systemDefault());
+ (RootOperator) LogicalGenerator.generate(sqlStr1, ZoneId.systemDefault());
Assert.assertEquals(SetStorageGroupOperator.class, operator.getClass());
Assert.assertEquals(new PartialPath("root.一级"), ((SetStorageGroupOperator) operator).getPath());
String sqlStr2 = "select * from root.一级.设备1 limit 10 offset 20";
- operator = (RootOperator) logicalGenerator.generate(sqlStr2, ZoneId.systemDefault());
+ operator = (RootOperator) LogicalGenerator.generate(sqlStr2, ZoneId.systemDefault());
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).getSelectOperator().getPaths());
}
@Test
@@ -263,7 +255,7 @@ public class LogicalPlanSmallTest {
+ "FIRST_VALUE.SUM.LAST_VALUE.LAST.DISABLE.ALIGN.COMPRESSION.TIME.ATTRIBUTES.TAGS.RENAME.FULL.CLEAR.CACHE."
+ "SNAPSHOT.FOR.SCHEMA.TRACING.OFF where time>=1 and time < 3";
- Operator op = logicalGenerator.generate(sql, ZoneId.systemDefault());
+ Operator op = LogicalGenerator.generate(sql, ZoneId.systemDefault());
Assert.assertEquals(DeleteDataOperator.class, op.getClass());
} catch (ParseCancellationException ignored) {
}
@@ -272,47 +264,47 @@ public class LogicalPlanSmallTest {
@Test
public void testRangeDelete() throws IllegalPathException {
String sql1 = "delete from root.d1.s1 where time>=1 and time < 3";
- Operator op = logicalGenerator.generate(sql1, ZoneId.systemDefault());
+ Operator op = LogicalGenerator.generate(sql1, ZoneId.systemDefault());
Assert.assertEquals(DeleteDataOperator.class, op.getClass());
ArrayList<PartialPath> paths = new ArrayList<>();
paths.add(new PartialPath("root.d1.s1"));
- Assert.assertEquals(paths, ((DeleteDataOperator) op).getSelectedPaths());
+ Assert.assertEquals(paths, ((DeleteDataOperator) op).getPaths());
Assert.assertEquals(1, ((DeleteDataOperator) op).getStartTime());
Assert.assertEquals(2, ((DeleteDataOperator) op).getEndTime());
String sql2 = "delete from root.d1.s1 where time>=1";
- op = logicalGenerator.generate(sql2, ZoneId.systemDefault());
- Assert.assertEquals(paths, ((DeleteDataOperator) op).getSelectedPaths());
+ op = LogicalGenerator.generate(sql2, ZoneId.systemDefault());
+ Assert.assertEquals(paths, ((DeleteDataOperator) op).getPaths());
Assert.assertEquals(1, ((DeleteDataOperator) op).getStartTime());
Assert.assertEquals(Long.MAX_VALUE, ((DeleteDataOperator) op).getEndTime());
String sql3 = "delete from root.d1.s1 where time>1";
- op = logicalGenerator.generate(sql3, ZoneId.systemDefault());
- Assert.assertEquals(paths, ((DeleteDataOperator) op).getSelectedPaths());
+ op = LogicalGenerator.generate(sql3, ZoneId.systemDefault());
+ Assert.assertEquals(paths, ((DeleteDataOperator) op).getPaths());
Assert.assertEquals(2, ((DeleteDataOperator) op).getStartTime());
Assert.assertEquals(Long.MAX_VALUE, ((DeleteDataOperator) op).getEndTime());
String sql4 = "delete from root.d1.s1 where time <= 1";
- op = logicalGenerator.generate(sql4, ZoneId.systemDefault());
- Assert.assertEquals(paths, ((DeleteDataOperator) op).getSelectedPaths());
+ op = LogicalGenerator.generate(sql4, ZoneId.systemDefault());
+ Assert.assertEquals(paths, ((DeleteDataOperator) op).getPaths());
Assert.assertEquals(Long.MIN_VALUE, ((DeleteDataOperator) op).getStartTime());
Assert.assertEquals(1, ((DeleteDataOperator) op).getEndTime());
String sql5 = "delete from root.d1.s1 where time<1";
- op = logicalGenerator.generate(sql5, ZoneId.systemDefault());
- Assert.assertEquals(paths, ((DeleteDataOperator) op).getSelectedPaths());
+ op = LogicalGenerator.generate(sql5, ZoneId.systemDefault());
+ Assert.assertEquals(paths, ((DeleteDataOperator) op).getPaths());
Assert.assertEquals(Long.MIN_VALUE, ((DeleteDataOperator) op).getStartTime());
Assert.assertEquals(0, ((DeleteDataOperator) op).getEndTime());
String sql6 = "delete from root.d1.s1 where time = 3";
- op = logicalGenerator.generate(sql6, ZoneId.systemDefault());
- Assert.assertEquals(paths, ((DeleteDataOperator) op).getSelectedPaths());
+ op = LogicalGenerator.generate(sql6, ZoneId.systemDefault());
+ Assert.assertEquals(paths, ((DeleteDataOperator) op).getPaths());
Assert.assertEquals(3, ((DeleteDataOperator) op).getStartTime());
Assert.assertEquals(3, ((DeleteDataOperator) op).getEndTime());
String sql7 = "delete from root.d1.s1 where time > 5 and time >= 2";
- op = logicalGenerator.generate(sql7, ZoneId.systemDefault());
- Assert.assertEquals(paths, ((DeleteDataOperator) op).getSelectedPaths());
+ op = LogicalGenerator.generate(sql7, ZoneId.systemDefault());
+ Assert.assertEquals(paths, ((DeleteDataOperator) op).getPaths());
Assert.assertEquals(6, ((DeleteDataOperator) op).getStartTime());
Assert.assertEquals(Long.MAX_VALUE, ((DeleteDataOperator) op).getEndTime());
}
@@ -322,7 +314,7 @@ public class LogicalPlanSmallTest {
String sql = "delete from root.d1.s1 where time>=1 and time < 3 or time >1";
String errorMsg = null;
try {
- logicalGenerator.generate(sql, ZoneId.systemDefault());
+ LogicalGenerator.generate(sql, ZoneId.systemDefault());
} catch (SQLParserException e) {
errorMsg = e.getMessage();
}
@@ -334,7 +326,7 @@ public class LogicalPlanSmallTest {
sql = "delete from root.d1.s1 where time>=1 or time < 3";
errorMsg = null;
try {
- logicalGenerator.generate(sql, ZoneId.systemDefault());
+ LogicalGenerator.generate(sql, ZoneId.systemDefault());
} catch (SQLParserException e) {
errorMsg = e.getMessage();
}
@@ -346,7 +338,7 @@ public class LogicalPlanSmallTest {
String sql7 = "delete from root.d1.s1 where time = 1 and time < -1";
errorMsg = null;
try {
- logicalGenerator.generate(sql7, ZoneId.systemDefault());
+ LogicalGenerator.generate(sql7, ZoneId.systemDefault());
} catch (RuntimeException e) {
errorMsg = e.getMessage();
}
@@ -355,7 +347,7 @@ public class LogicalPlanSmallTest {
sql = "delete from root.d1.s1 where time > 5 and time <= 0";
errorMsg = null;
try {
- logicalGenerator.generate(sql, ZoneId.systemDefault());
+ LogicalGenerator.generate(sql, ZoneId.systemDefault());
} catch (SQLParserException e) {
errorMsg = e.getMessage();
}
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..47e7ade 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,7 @@ public class UDTFAlignByTimeDataSetTest {
Path path = queryPlan.getPaths().get(i);
String columnName =
path == null
- ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getContext().getColumnName()
+ ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getExpression().toString()
: path.getFullPath();
originalIndex2FieldIndex.add(path2Index.get(columnName));
}
@@ -233,7 +233,7 @@ public class UDTFAlignByTimeDataSetTest {
Path path = queryPlan.getPaths().get(i);
String columnName =
path == null
- ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getContext().getColumnName()
+ ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getExpression().toString()
: path.getFullPath();
originalIndex2FieldIndex.add(path2Index.get(columnName));
}
@@ -280,7 +280,7 @@ public class UDTFAlignByTimeDataSetTest {
Path path = queryPlan.getPaths().get(i);
String columnName =
path == null
- ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getContext().getColumnName()
+ ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getExpression().toString()
: path.getFullPath();
originalIndex2FieldIndex.add(path2Index.get(columnName));
}
@@ -339,7 +339,7 @@ public class UDTFAlignByTimeDataSetTest {
Path path = queryPlan.getPaths().get(i);
String columnName =
path == null
- ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getContext().getColumnName()
+ ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getExpression().toString()
: path.getFullPath();
originalIndex2FieldIndex.add(path2Index.get(columnName));
}
@@ -412,7 +412,7 @@ public class UDTFAlignByTimeDataSetTest {
Path path = queryPlan.getPaths().get(i);
String columnName =
path == null
- ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getContext().getColumnName()
+ ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getExpression().toString()
: path.getFullPath();
originalIndex2FieldIndex.add(path2Index.get(columnName));
}
@@ -468,7 +468,7 @@ public class UDTFAlignByTimeDataSetTest {
Path path = queryPlan.getPaths().get(i);
String columnName =
path == null
- ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getContext().getColumnName()
+ ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getExpression().toString()
: path.getFullPath();
originalIndex2FieldIndex.add(path2Index.get(columnName));
}
@@ -533,7 +533,7 @@ public class UDTFAlignByTimeDataSetTest {
Path path = queryPlan.getPaths().get(i);
String columnName =
path == null
- ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getContext().getColumnName()
+ ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getExpression().toString()
: path.getFullPath();
originalIndex2FieldIndex.add(path2Index.get(columnName));
}
@@ -604,7 +604,7 @@ public class UDTFAlignByTimeDataSetTest {
Path path = queryPlan.getPaths().get(i);
String columnName =
path == null
- ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getContext().getColumnName()
+ ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getExpression().toString()
: path.getFullPath();
originalIndex2FieldIndex.add(path2Index.get(columnName));
}
@@ -657,7 +657,7 @@ public class UDTFAlignByTimeDataSetTest {
Path path = queryPlan.getPaths().get(i);
String columnName =
path == null
- ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getContext().getColumnName()
+ ? queryPlan.getExecutorByOriginalOutputColumnIndex(i).getExpression().toString()
: path.getFullPath();
originalIndex2FieldIndex.add(path2Index.get(columnName));
}
diff --git a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/iotdb/IoTDBInterpreterTest.java b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/iotdb/IoTDBInterpreterTest.java
index 1525b3c..75fcf73 100644
--- a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/iotdb/IoTDBInterpreterTest.java
+++ b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/iotdb/IoTDBInterpreterTest.java
@@ -209,25 +209,34 @@ public class IoTDBInterpreterTest {
actual = interpreter.internalInterpret(wrongSql, null);
Assert.assertNotNull(actual);
Assert.assertEquals(Code.ERROR, actual.code());
- Assert.assertEquals(
- "SQLException: 401: Error occurred while parsing SQL to physical plan: line 1:13 missing ROOT at '<EOF>'",
- actual.message().get(0).getData());
+ Assert.assertTrue(
+ actual
+ .message()
+ .get(0)
+ .getData()
+ .contains("SQLException: 401: Error occurred while parsing SQL to physical plan"));
wrongSql = "select * from a";
actual = interpreter.internalInterpret(wrongSql, null);
Assert.assertNotNull(actual);
Assert.assertEquals(Code.ERROR, actual.code());
- Assert.assertEquals(
- "SQLException: 401: Error occurred while parsing SQL to physical plan: line 1:14 mismatched input 'a' expecting {FROM, ',', '.'}",
- actual.message().get(0).getData());
+ Assert.assertTrue(
+ actual
+ .message()
+ .get(0)
+ .getData()
+ .contains("SQLException: 401: Error occurred while parsing SQL to physical plan"));
wrongSql = "select * from root a";
actual = interpreter.internalInterpret(wrongSql, null);
Assert.assertNotNull(actual);
Assert.assertEquals(Code.ERROR, actual.code());
- Assert.assertEquals(
- "SQLException: 401: Error occurred while parsing SQL to physical plan: line 1:19 extraneous input 'a' expecting {<EOF>, ';'}",
- actual.message().get(0).getData());
+ Assert.assertTrue(
+ actual
+ .message()
+ .get(0)
+ .getData()
+ .contains("SQLException: 401: Error occurred while parsing SQL to physical plan"));
}
@Test