You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by hu...@apache.org on 2022/10/11 09:48:23 UTC
[iotdb] 02/04: tmp save (analyzer for SELECT INTO)
This is an automated email from the ASF dual-hosted git repository.
hui pushed a commit to branch lmh/mppSelectInto
in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 62b2d495b9f2b1e7a61a6f54400edb4ee17f1ab1
Author: Minghui Liu <li...@foxmail.com>
AuthorDate: Mon Sep 19 10:22:55 2022 +0800
tmp save (analyzer for SELECT INTO)
---
.../apache/iotdb/commons/conf/IoTDBConstant.java | 5 ++
.../org/apache/iotdb/commons/path/PartialPath.java | 13 ++++
.../iotdb/db/metadata/path/MeasurementPath.java | 4 ++
.../apache/iotdb/db/mpp/plan/analyze/Analysis.java | 22 +++++++
.../iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java | 72 ++++++++++++++++++++++
.../db/mpp/plan/statement/crud/QueryStatement.java | 14 +++++
6 files changed, 130 insertions(+)
diff --git a/node-commons/src/main/java/org/apache/iotdb/commons/conf/IoTDBConstant.java b/node-commons/src/main/java/org/apache/iotdb/commons/conf/IoTDBConstant.java
index 5d2c219e60..536fb56513 100644
--- a/node-commons/src/main/java/org/apache/iotdb/commons/conf/IoTDBConstant.java
+++ b/node-commons/src/main/java/org/apache/iotdb/commons/conf/IoTDBConstant.java
@@ -20,6 +20,7 @@ package org.apache.iotdb.commons.conf;
import java.util.HashSet;
import java.util.Set;
+import java.util.regex.Pattern;
public class IoTDBConstant {
@@ -260,4 +261,8 @@ public class IoTDBConstant {
V_0_12,
V_0_13
}
+
+ // select into
+ public static final Pattern LEVELED_PATH_TEMPLATE_PATTERN = Pattern.compile("\\$\\{\\w+}");
+ public static final String DOUBLE_COLONS = "::";
}
diff --git a/node-commons/src/main/java/org/apache/iotdb/commons/path/PartialPath.java b/node-commons/src/main/java/org/apache/iotdb/commons/path/PartialPath.java
index bec99ab45f..f745444798 100644
--- a/node-commons/src/main/java/org/apache/iotdb/commons/path/PartialPath.java
+++ b/node-commons/src/main/java/org/apache/iotdb/commons/path/PartialPath.java
@@ -550,6 +550,19 @@ public class PartialPath extends Path implements Comparable<Path>, Cloneable {
return true;
}
+ public boolean startWith(String otherNode) {
+ return nodes[0].equals(otherNode);
+ }
+
+ public boolean containNode(String otherNode) {
+ for (String node : nodes) {
+ if (node.equals(otherNode)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override
public String toString() {
return getFullPath();
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/path/MeasurementPath.java b/server/src/main/java/org/apache/iotdb/db/metadata/path/MeasurementPath.java
index 2525844e31..0de9c3bd43 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/path/MeasurementPath.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/path/MeasurementPath.java
@@ -57,6 +57,10 @@ public class MeasurementPath extends PartialPath {
this.measurementSchema = new MeasurementSchema(getMeasurement(), type);
}
+ public MeasurementPath(PartialPath path, TSDataType type, boolean isUnderAlignedEntity) {
+ this(path, new MeasurementSchema(path.getMeasurement(), type), isUnderAlignedEntity);
+ }
+
public MeasurementPath(PartialPath measurementPath, IMeasurementSchema measurementSchema) {
this(measurementPath, measurementSchema, false);
}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analysis.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analysis.java
index d45d98e22c..28639dfd4a 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analysis.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/Analysis.java
@@ -96,6 +96,9 @@ public class Analysis {
private boolean isRawDataSource;
+ // map from output column to target into path
+ private Map<String, PartialPath> outputColumnToIntoPathMap;
+
/////////////////////////////////////////////////////////////////////////////////////////////////
// Query Analysis (used in ALIGN BY DEVICE)
/////////////////////////////////////////////////////////////////////////////////////////////////
@@ -124,6 +127,9 @@ public class Analysis {
private Map<String, Boolean> deviceToIsRawDataSource;
+ // map from device name to target into path of each output column
+ private Map<String, Map<String, PartialPath>> deviceToIntoPathMap;
+
/////////////////////////////////////////////////////////////////////////////////////////////////
// Query Common Analysis (above DeviceView)
/////////////////////////////////////////////////////////////////////////////////////////////////
@@ -465,4 +471,20 @@ public class Analysis {
public void setOutputExpressions(List<Pair<Expression, String>> outputExpressions) {
this.outputExpressions = outputExpressions;
}
+
+ public Map<String, PartialPath> getOutputColumnToIntoPathMap() {
+ return outputColumnToIntoPathMap;
+ }
+
+ public void setOutputColumnToIntoPathMap(Map<String, PartialPath> outputColumnToIntoPathMap) {
+ this.outputColumnToIntoPathMap = outputColumnToIntoPathMap;
+ }
+
+ public Map<String, Map<String, PartialPath>> getDeviceToIntoPathMap() {
+ return deviceToIntoPathMap;
+ }
+
+ public void setDeviceToIntoPathMap(Map<String, Map<String, PartialPath>> deviceToIntoPathMap) {
+ this.deviceToIntoPathMap = deviceToIntoPathMap;
+ }
}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java
index a5dace95a8..baa7a465e3 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java
@@ -49,6 +49,7 @@ import org.apache.iotdb.db.mpp.plan.planner.plan.parameter.OrderByParameter;
import org.apache.iotdb.db.mpp.plan.statement.Statement;
import org.apache.iotdb.db.mpp.plan.statement.StatementNode;
import org.apache.iotdb.db.mpp.plan.statement.StatementVisitor;
+import org.apache.iotdb.db.mpp.plan.statement.component.AlignByTimeIntoComponent;
import org.apache.iotdb.db.mpp.plan.statement.component.FillComponent;
import org.apache.iotdb.db.mpp.plan.statement.component.GroupByTimeComponent;
import org.apache.iotdb.db.mpp.plan.statement.component.Ordering;
@@ -92,6 +93,7 @@ import org.apache.iotdb.db.mpp.plan.statement.metadata.template.ShowSchemaTempla
import org.apache.iotdb.db.mpp.plan.statement.sys.ExplainStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.ShowVersionStatement;
import org.apache.iotdb.db.mpp.plan.statement.sys.sync.ShowPipeSinkTypeStatement;
+import org.apache.iotdb.db.qp.constant.SQLConstant;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import org.apache.iotdb.tsfile.read.filter.GroupByFilter;
import org.apache.iotdb.tsfile.read.filter.GroupByMonthFilter;
@@ -117,6 +119,8 @@ import java.util.TimeZone;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkState;
+import static org.apache.iotdb.commons.conf.IoTDBConstant.DOUBLE_COLONS;
+import static org.apache.iotdb.commons.conf.IoTDBConstant.LEVELED_PATH_TEMPLATE_PATTERN;
import static org.apache.iotdb.commons.conf.IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD;
import static org.apache.iotdb.commons.conf.IoTDBConstant.ONE_LEVEL_PATH_WILDCARD;
import static org.apache.iotdb.db.metadata.MetadataConstant.ALL_RESULT_NODES;
@@ -238,6 +242,8 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
deviceToTransformExpressions,
deviceToMeasurementsMap);
+ analyzeInto(analysis, outputExpressions, deviceToMeasurementsMap);
+
if (queryStatement.hasHaving()) {
List<PartialPath> measurementNotExistDevices = new ArrayList<>();
for (PartialPath device : deviceList) {
@@ -417,6 +423,8 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
analysis.setRawPathToGroupedPathMap(rawPathToGroupedPathMap);
}
+ analyzeInto(analysis, outputExpressions);
+
// true if nested expressions and UDFs exist in aggregation function
// i.e. select sum(s1 + 1) from root.sg.d1
boolean isHasRawDataInputAggregation = false;
@@ -989,6 +997,70 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
ExpressionTypeAnalyzer.analyzeExpression(analysis, expression);
}
+ private void analyzeInto(Analysis analysis, List<Pair<Expression, String>> outputExpressions) {
+ Map<String, PartialPath> outputColumnToIntoPathMap = new HashMap<>();
+ List<Expression> outputColumns =
+ outputExpressions.stream()
+ .map(Pair::getLeft)
+ .collect(Collectors.toCollection(ArrayList::new));
+ AlignByTimeIntoComponent intoComponent =
+ ((AlignByTimeIntoComponent) ((QueryStatement) analysis.getStatement()).getIntoComponent());
+ List<PartialPath> intoPaths = intoComponent.getIntoPaths();
+ boolean isAligned = intoComponent.isAligned();
+
+ boolean isAllRawSeriesQuery = checkIsAllRawSeriesQuery(outputColumns);
+ if (isAllRawSeriesQuery) {
+ if (intoPaths.size() != outputColumns.size()) {
+ throw new SemanticException(
+ "select into: the number of source paths and the number of target paths should be the same.");
+ }
+ if (intoPaths.size() > new HashSet<>(intoPaths).size()) {
+ throw new SemanticException(
+ "select into: target paths in into clause should be different.");
+ }
+ for (int i = 0; i < outputColumns.size(); i++) {
+ outputColumnToIntoPathMap.put(
+ outputColumns.get(i).toString(),
+ constructIntoPath(analysis, outputColumns.get(i), intoPaths.get(i), isAligned));
+ }
+ } else {
+
+ }
+ analysis.setOutputColumnToIntoPathMap(outputColumnToIntoPathMap);
+ }
+
+ private PartialPath constructIntoPath(
+ Analysis analysis, Expression outputColumn, PartialPath path, boolean isAligned) {
+ if (!path.startWith(SQLConstant.ROOT)) {
+ throw new SemanticException("select into: ");
+ }
+ if (path.containNode(DOUBLE_COLONS)) {
+ throw new SemanticException("select into: ");
+ }
+ if (LEVELED_PATH_TEMPLATE_PATTERN.matcher(path.getFullPath()).find()) {
+ throw new SemanticException("select into: ");
+ }
+ return new MeasurementPath(path, analysis.getType(outputColumn), isAligned);
+ }
+
+ private void analyzeInto(
+ Analysis analysis,
+ List<Pair<Expression, String>> outputExpressions,
+ Map<String, Set<String>> deviceToMeasurementsMap) {
+ Map<String, Map<String, PartialPath>> deviceToIntoPathMap = new HashMap<>();
+
+ analysis.setDeviceToIntoPathMap(deviceToIntoPathMap);
+ }
+
+ private boolean checkIsAllRawSeriesQuery(List<Expression> expressions) {
+ for (Expression expression : expressions) {
+ if (!(expression instanceof TimeSeriesOperand)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Check datatype consistency in ALIGN BY DEVICE.
*
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/crud/QueryStatement.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/crud/QueryStatement.java
index 1d4490ce3c..f6f9578f59 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/crud/QueryStatement.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/crud/QueryStatement.java
@@ -27,6 +27,8 @@ import org.apache.iotdb.db.mpp.plan.expression.Expression;
import org.apache.iotdb.db.mpp.plan.expression.leaf.TimeSeriesOperand;
import org.apache.iotdb.db.mpp.plan.statement.Statement;
import org.apache.iotdb.db.mpp.plan.statement.StatementVisitor;
+import org.apache.iotdb.db.mpp.plan.statement.component.AlignByDeviceIntoComponent;
+import org.apache.iotdb.db.mpp.plan.statement.component.AlignByTimeIntoComponent;
import org.apache.iotdb.db.mpp.plan.statement.component.FillComponent;
import org.apache.iotdb.db.mpp.plan.statement.component.FromComponent;
import org.apache.iotdb.db.mpp.plan.statement.component.GroupByLevelComponent;
@@ -238,6 +240,10 @@ public class QueryStatement extends Statement {
return groupByTimeComponent != null;
}
+ public boolean isAlignByTime() {
+ return resultSetFormat == ResultSetFormat.ALIGN_BY_TIME;
+ }
+
public boolean isAlignByDevice() {
return resultSetFormat == ResultSetFormat.ALIGN_BY_DEVICE;
}
@@ -389,6 +395,14 @@ public class QueryStatement extends Statement {
if (isLastQuery()) {
throw new SemanticException("select into: last clauses are not supported.");
}
+ if (isAlignByDevice() && intoComponent instanceof AlignByTimeIntoComponent) {
+ throw new SemanticException(
+ "select into: target path is illegal, expected: full path or suffix path");
+ }
+ if (isAlignByTime() && intoComponent instanceof AlignByDeviceIntoComponent) {
+ throw new SemanticException(
+ "select into: target path is illegal, expected: target device and measurements");
+ }
}
}