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:25 UTC
[iotdb] 04/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 fb63d17c6b28c0a1e4d88fdd6fc21cb44b2d256c
Author: Minghui Liu <li...@foxmail.com>
AuthorDate: Mon Oct 10 22:26:47 2022 +0800
tmp save (analyzer for SELECT INTO)
---
.../org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 | 6 +-
.../db/metadata/path/PatternTreeMapFactory.java | 8 +
.../apache/iotdb/db/mpp/plan/analyze/Analysis.java | 34 +--
.../iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java | 233 ++++++++++++++++++---
.../iotdb/db/mpp/plan/parser/ASTVisitor.java | 42 ++--
.../component/AlignByDeviceIntoComponent.java | 40 ----
.../component/AlignByTimeIntoComponent.java | 38 ----
.../plan/statement/component/IntoComponent.java | 25 ++-
.../db/mpp/plan/statement/component/IntoItem.java | 73 +++++++
.../db/mpp/plan/statement/crud/QueryStatement.java | 10 -
.../apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java | 14 +-
11 files changed, 354 insertions(+), 169 deletions(-)
diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
index d49d19b11e..591de9e067 100644
--- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
+++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
@@ -381,7 +381,7 @@ selectStatement
intoClause
: INTO ALIGNED? intoPath (COMMA intoPath)*
- | INTO ALIGNED? intoDeviceAndMeasurement (COMMA intoDeviceAndMeasurement)*
+ | INTO intoItem (COMMA intoItem)*
;
intoPath
@@ -389,8 +389,8 @@ intoPath
| nodeNameInIntoPath (DOT nodeNameInIntoPath)* #suffixPathInIntoPath
;
-intoDeviceAndMeasurement
- : intoPath LR_BRACKET nodeNameInIntoPath (COMMA nodeNameInIntoPath)* RR_BRACKET
+intoItem
+ : ALIGNED? intoPath LR_BRACKET nodeNameInIntoPath (COMMA nodeNameInIntoPath)* RR_BRACKET
;
nodeNameInIntoPath
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/path/PatternTreeMapFactory.java b/server/src/main/java/org/apache/iotdb/db/metadata/path/PatternTreeMapFactory.java
index fe2e55869e..e1ce413315 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/path/PatternTreeMapFactory.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/path/PatternTreeMapFactory.java
@@ -49,6 +49,14 @@ public class PatternTreeMapFactory {
HashSet::new, (mod, set) -> set.add(mod), null, ModsSerializer.getInstance());
}
+ public static PatternTreeMap<String, StringSerializer> getIntoPathPatternTreeMap() {
+ return new PatternTreeMap<>(
+ HashSet::new,
+ (columnName, set) -> set.add(columnName),
+ (columnName, set) -> set.remove(columnName),
+ StringSerializer.getInstance());
+ }
+
public static class ModsSerializer implements PathPatternNode.Serializer<Modification> {
@Override
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 a5140a68e3..119f67654a 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
@@ -24,6 +24,8 @@ import org.apache.iotdb.common.rpc.thrift.TSchemaNode;
import org.apache.iotdb.commons.partition.DataPartition;
import org.apache.iotdb.commons.partition.SchemaPartition;
import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.commons.path.PatternTreeMap;
+import org.apache.iotdb.db.metadata.path.PatternTreeMapFactory;
import org.apache.iotdb.db.metadata.template.Template;
import org.apache.iotdb.db.mpp.common.NodeRef;
import org.apache.iotdb.db.mpp.common.header.DatasetHeader;
@@ -86,9 +88,6 @@ public class Analysis {
// map from grouped path name to list of input aggregation in `GROUP BY LEVEL` clause
private Map<Expression, Set<Expression>> groupByLevelExpressions;
- // map from output column to target into path
- private Map<String, PartialPath> outputColumnToIntoPathMap;
-
/////////////////////////////////////////////////////////////////////////////////////////////////
// Query Analysis (used in ALIGN BY DEVICE)
/////////////////////////////////////////////////////////////////////////////////////////////////
@@ -114,9 +113,6 @@ public class Analysis {
private Set<Expression> deviceViewOutputExpressions;
- // map from device name to target into path of each output column
- private Map<String, Map<String, PartialPath>> deviceToIntoPathMap;
-
/////////////////////////////////////////////////////////////////////////////////////////////////
// Query Common Analysis (above DeviceView)
/////////////////////////////////////////////////////////////////////////////////////////////////
@@ -143,6 +139,14 @@ public class Analysis {
// header of result dataset
private DatasetHeader respDatasetHeader;
+ /////////////////////////////////////////////////////////////////////////////////////////////////
+ // SELECT INTO Analysis (used in ALIGN BY DEVICE)
+ /////////////////////////////////////////////////////////////////////////////////////////////////
+
+ private PatternTreeMap<String, PatternTreeMapFactory.StringSerializer> intoPathPatternTreeMap;
+
+ private Map<PartialPath, Boolean> intoDeviceToAlignedMap;
+
/////////////////////////////////////////////////////////////////////////////////////////////////
// Schema Query Analysis
/////////////////////////////////////////////////////////////////////////////////////////////////
@@ -410,19 +414,21 @@ public class Analysis {
this.deviceViewOutputExpressions = deviceViewOutputExpressions;
}
- public Map<String, PartialPath> getOutputColumnToIntoPathMap() {
- return outputColumnToIntoPathMap;
+ public PatternTreeMap<String, PatternTreeMapFactory.StringSerializer>
+ getIntoPathPatternTreeMap() {
+ return intoPathPatternTreeMap;
}
- public void setOutputColumnToIntoPathMap(Map<String, PartialPath> outputColumnToIntoPathMap) {
- this.outputColumnToIntoPathMap = outputColumnToIntoPathMap;
+ public void setIntoPathPatternTreeMap(
+ PatternTreeMap<String, PatternTreeMapFactory.StringSerializer> intoPathPatternTreeMap) {
+ this.intoPathPatternTreeMap = intoPathPatternTreeMap;
}
- public Map<String, Map<String, PartialPath>> getDeviceToIntoPathMap() {
- return deviceToIntoPathMap;
+ public Map<PartialPath, Boolean> getIntoDeviceToAlignedMap() {
+ return intoDeviceToAlignedMap;
}
- public void setDeviceToIntoPathMap(Map<String, Map<String, PartialPath>> deviceToIntoPathMap) {
- this.deviceToIntoPathMap = deviceToIntoPathMap;
+ public void setIntoDeviceToAlignedMap(Map<PartialPath, Boolean> intoDeviceToAlignedMap) {
+ this.intoDeviceToAlignedMap = intoDeviceToAlignedMap;
}
}
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 d0d32de590..2731e84907 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
@@ -29,6 +29,7 @@ import org.apache.iotdb.commons.partition.SchemaPartition;
import org.apache.iotdb.commons.path.MeasurementPath;
import org.apache.iotdb.commons.path.PartialPath;
import org.apache.iotdb.commons.path.PathPatternTree;
+import org.apache.iotdb.commons.path.PatternTreeMap;
import org.apache.iotdb.db.conf.IoTDBDescriptor;
import org.apache.iotdb.db.engine.storagegroup.TsFileResource;
import org.apache.iotdb.db.engine.storagegroup.TsFileResourceStatus;
@@ -38,6 +39,7 @@ import org.apache.iotdb.db.exception.metadata.template.TemplateImcompatibeExcept
import org.apache.iotdb.db.exception.sql.MeasurementNotExistException;
import org.apache.iotdb.db.exception.sql.SemanticException;
import org.apache.iotdb.db.exception.sql.StatementAnalyzeException;
+import org.apache.iotdb.db.metadata.path.PatternTreeMapFactory;
import org.apache.iotdb.db.metadata.template.Template;
import org.apache.iotdb.db.mpp.common.MPPQueryContext;
import org.apache.iotdb.db.mpp.common.header.ColumnHeader;
@@ -56,9 +58,10 @@ 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.IntoComponent;
+import org.apache.iotdb.db.mpp.plan.statement.component.IntoItem;
import org.apache.iotdb.db.mpp.plan.statement.component.Ordering;
import org.apache.iotdb.db.mpp.plan.statement.component.ResultColumn;
import org.apache.iotdb.db.mpp.plan.statement.component.SortItem;
@@ -102,6 +105,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.db.query.control.SessionManager;
import org.apache.iotdb.db.utils.FileLoaderUtils;
import org.apache.iotdb.db.utils.TimePartitionUtils;
@@ -111,7 +115,6 @@ import org.apache.iotdb.tsfile.file.header.ChunkHeader;
import org.apache.iotdb.tsfile.file.metadata.IChunkMetadata;
import org.apache.iotdb.tsfile.file.metadata.TimeseriesMetadata;
import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
-import org.apache.iotdb.db.qp.constant.SQLConstant;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
import org.apache.iotdb.tsfile.read.TsFileSequenceReader;
@@ -140,6 +143,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TimeZone;
+import java.util.regex.Matcher;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkState;
@@ -233,6 +237,8 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
analyzeDeviceToSource(analysis, queryStatement);
analyzeDeviceView(analysis, queryStatement, outputExpressions);
+
+ analyzeInto(analysis, queryStatement, deviceSet, outputExpressions);
} else {
outputExpressions = analyzeSelect(analysis, queryStatement, schemaTree);
@@ -251,6 +257,8 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
analyzeSourceTransform(analysis, queryStatement);
analyzeSource(analysis, queryStatement);
+
+ analyzeInto(analysis, queryStatement, outputExpressions);
}
analyzeGroupBy(analysis, queryStatement);
@@ -988,40 +996,212 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
return partitionFetcher.getDataPartition(sgNameToQueryParamsMap);
}
- private void analyzeInto(Analysis analysis, List<Pair<Expression, String>> outputExpressions) {
- Map<String, PartialPath> outputColumnToIntoPathMap = new HashMap<>();
+ private void analyzeInto(
+ Analysis analysis,
+ QueryStatement queryStatement,
+ Set<PartialPath> deviceSet,
+ List<Pair<Expression, String>> outputExpressions) {
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();
-
+ outputExpressions.stream()
+ .map(Pair::getLeft)
+ .collect(Collectors.toCollection(ArrayList::new));
boolean isAllRawSeriesQuery = checkIsAllRawSeriesQuery(outputColumns);
+
+ IntoComponent intoComponent = queryStatement.getIntoComponent();
+ List<IntoItem> intoItems = intoComponent.getIntoItems();
+
+ Map<PartialPath, PartialPath> sourceDeviceToTargetDeviceMap = new HashMap<>();
+ List<PartialPath> sourceDevices = new ArrayList<>(deviceSet);
+ if (intoComponent.isDeviceExistPlaceholder()) {
+ if (intoItems.size() > 1) {
+ throw new SemanticException("");
+ }
+
+ PartialPath deviceTemplate = intoItems.get(0).getIntoDevice();
+ for (int i = 0; i < sourceDevices.size(); i++) {
+ PartialPath sourceDevice = sourceDevices.get(i);
+ PartialPath targetDevice = constructIntoDevice(sourceDevice, deviceTemplate);
+ if (sourceDeviceToTargetDeviceMap.containsKey(sourceDevice)
+ && !sourceDeviceToTargetDeviceMap.get(sourceDevice).equals(targetDevice)) {
+ throw new SemanticException("");
+ }
+ sourceDeviceToTargetDeviceMap.put(sourceDevices.get(i), intoItems.get(i).getIntoDevice());
+ }
+ } else {
+ if (intoItems.size() != sourceDevices.size()) {
+ throw new SemanticException("");
+ }
+
+ for (int i = 0; i < sourceDevices.size(); i++) {
+ PartialPath sourceDevice = sourceDevices.get(i);
+ PartialPath targetDevice = intoItems.get(i).getIntoDevice();
+ if (sourceDeviceToTargetDeviceMap.containsKey(sourceDevice)
+ && !sourceDeviceToTargetDeviceMap.get(sourceDevice).equals(targetDevice)) {
+ throw new SemanticException("");
+ }
+ sourceDeviceToTargetDeviceMap.put(sourceDevices.get(i), intoItems.get(i).getIntoDevice());
+ }
+ }
+
+ PatternTreeMap<String, PatternTreeMapFactory.StringSerializer> intoPathPatternTreeMap =
+ PatternTreeMapFactory.getIntoPathPatternTreeMap();
+
if (isAllRawSeriesQuery) {
+
+ } else {
+ // disable placeholder
+ for (IntoItem intoItem : intoItems) {
+ if (intoItem.isMeasurementsExistPlaceholder()) {
+ throw new SemanticException(
+ "select into: placeholders can only be used in raw timeseries data queries.");
+ }
+ }
+
+ List<PartialPath> intoPaths =
+ intoItems.stream()
+ .map(IntoItem::getIntoPaths)
+ .flatMap(List::stream)
+ .collect(Collectors.toList());
+
+ // check quantity consistency
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.");
+ "select into: the number of source columns 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 < intoPaths.size(); i++) {
+ if (intoPathPatternTreeMap.getOverlapped(intoPaths.get(i)).size() > 1) {
+ throw new SemanticException(
+ "select into: target paths in into clause should be different.");
+ }
+ intoPathPatternTreeMap.append(intoPaths.get(i), outputColumns.get(i).toString());
}
- for (int i = 0; i < outputColumns.size(); i++) {
- outputColumnToIntoPathMap.put(
- outputColumns.get(i).toString(),
- constructIntoPath(analysis, outputColumns.get(i), intoPaths.get(i), isAligned));
+ }
+ analyzeIntoDevices(analysis, intoItems);
+ analysis.setIntoPathPatternTreeMap(intoPathPatternTreeMap);
+ }
+
+ private PartialPath constructIntoDevice(PartialPath sourceDevice, PartialPath deviceTemplate) {
+ String[] sourceNodes = sourceDevice.getNodes();
+ String[] templateNodes = deviceTemplate.getNodes();
+
+ List<String> targetNodes = new ArrayList<>();
+ for (int nodeIndex = 0; nodeIndex < templateNodes.length; nodeIndex++) {
+ String curNode = templateNodes[nodeIndex];
+ if (curNode.equals(DOUBLE_COLONS)) {
+ if (nodeIndex != templateNodes.length - 1) {
+ throw new SemanticException("");
+ }
+ // copy
+ for (; nodeIndex < sourceNodes.length; nodeIndex++) {
+ targetNodes.add(sourceNodes[nodeIndex]);
+ }
+ break;
}
+
+ Matcher m = LEVELED_PATH_TEMPLATE_PATTERN.matcher(curNode);
+ String resNode = curNode;
+ while (m.find()) {
+ String param = m.group();
+ int index;
+ try {
+ index = Integer.parseInt(param.substring(2, param.length() - 1).trim());
+ } catch (NumberFormatException e) {
+ throw new SemanticException("select into: the i of ${i} should be an integer.");
+ }
+ if (index < 1 || index >= sourceNodes.length) {
+ throw new SemanticException(
+ "select into: the i of ${i} should be greater than 0 and equal to or less than the length of queried path prefix.");
+ }
+ }
+ targetNodes.add(resNode);
+ }
+ return new PartialPath(targetNodes.toArray(new String[0]));
+ }
+
+ private void analyzeInto(
+ Analysis analysis,
+ QueryStatement queryStatement,
+ List<Pair<Expression, String>> outputExpressions) {
+ if (queryStatement.getIntoComponent() == null) {
+ return;
+ }
+
+ List<Expression> outputColumns =
+ outputExpressions.stream()
+ .map(Pair::getLeft)
+ .collect(Collectors.toCollection(ArrayList::new));
+ boolean isAllRawSeriesQuery = checkIsAllRawSeriesQuery(outputColumns);
+
+ IntoComponent intoComponent = queryStatement.getIntoComponent();
+ List<IntoItem> intoItems = intoComponent.getIntoItems();
+
+ PatternTreeMap<String, PatternTreeMapFactory.StringSerializer> intoPathPatternTreeMap =
+ PatternTreeMapFactory.getIntoPathPatternTreeMap();
+
+ if (isAllRawSeriesQuery) {
+
} else {
+ // disable placeholder
+ for (IntoItem intoItem : intoItems) {
+ if (intoItem.isDeviceExistPlaceholder() || intoItem.isMeasurementsExistPlaceholder()) {
+ throw new SemanticException(
+ "select into: placeholders can only be used in raw timeseries data queries.");
+ }
+ }
+ List<PartialPath> intoPaths =
+ intoItems.stream()
+ .map(IntoItem::getIntoPaths)
+ .flatMap(List::stream)
+ .collect(Collectors.toList());
+
+ // check quantity consistency
+ if (intoPaths.size() != outputColumns.size()) {
+ throw new SemanticException(
+ "select into: the number of source columns and the number of target paths should be the same.");
+ }
+
+ for (int i = 0; i < intoPaths.size(); i++) {
+ intoPathPatternTreeMap.append(intoPaths.get(i), outputColumns.get(i).toString());
+ if (intoPathPatternTreeMap.getOverlapped(intoPaths.get(i)).size() > 1) {
+ throw new SemanticException(
+ "select into: target paths in into clause should be different.");
+ }
+ }
}
- analysis.setOutputColumnToIntoPathMap(outputColumnToIntoPathMap);
+ analyzeIntoDevices(analysis, intoItems);
+ analysis.setIntoPathPatternTreeMap(intoPathPatternTreeMap);
+ }
+
+ private void analyzeIntoDevices(Analysis analysis, List<IntoItem> intoItems) {
+ Map<PartialPath, Boolean> intoDeviceToAlignedMap = new HashMap<>();
+ for (IntoItem intoItem : intoItems) {
+ PartialPath devicePath = intoItem.getIntoDevice();
+ boolean isAligned = intoItem.isAligned();
+ if (intoDeviceToAlignedMap.containsKey(devicePath)
+ && intoDeviceToAlignedMap.get(devicePath) != isAligned) {
+ throw new SemanticException(
+ String.format(
+ "select into: inconsistent alignment property specified for device '%s'.",
+ devicePath));
+ }
+ intoDeviceToAlignedMap.put(devicePath, isAligned);
+ }
+ analysis.setIntoDeviceToAlignedMap(intoDeviceToAlignedMap);
+ }
+
+ private boolean checkIsAllRawSeriesQuery(List<Expression> expressions) {
+ for (Expression expression : expressions) {
+ if (!(expression instanceof TimeSeriesOperand)) {
+ return true;
+ }
+ }
+ return false;
}
private PartialPath constructIntoPath(
- Analysis analysis, Expression outputColumn, PartialPath path, boolean isAligned) {
+ Analysis analysis, Expression outputColumn, PartialPath path, boolean isAligned) {
if (!path.startWith(SQLConstant.ROOT)) {
throw new SemanticException("select into: ");
}
@@ -1034,15 +1214,6 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
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);
- }
-
/**
* Check datatype consistency in ALIGN BY DEVICE.
*
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
index 38391e156d..c4f9ddf867 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/parser/ASTVisitor.java
@@ -63,14 +63,14 @@ import org.apache.iotdb.db.mpp.plan.expression.unary.LogicNotExpression;
import org.apache.iotdb.db.mpp.plan.expression.unary.NegationExpression;
import org.apache.iotdb.db.mpp.plan.expression.unary.RegularExpression;
import org.apache.iotdb.db.mpp.plan.statement.Statement;
-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.FillPolicy;
import org.apache.iotdb.db.mpp.plan.statement.component.FromComponent;
import org.apache.iotdb.db.mpp.plan.statement.component.GroupByLevelComponent;
import org.apache.iotdb.db.mpp.plan.statement.component.GroupByTimeComponent;
import org.apache.iotdb.db.mpp.plan.statement.component.HavingCondition;
+import org.apache.iotdb.db.mpp.plan.statement.component.IntoComponent;
+import org.apache.iotdb.db.mpp.plan.statement.component.IntoItem;
import org.apache.iotdb.db.mpp.plan.statement.component.OrderByComponent;
import org.apache.iotdb.db.mpp.plan.statement.component.Ordering;
import org.apache.iotdb.db.mpp.plan.statement.component.ResultColumn;
@@ -1369,31 +1369,27 @@ public class ASTVisitor extends IoTDBSqlParserBaseVisitor<Statement> {
// parse INTO clause
private void parseIntoClause(IoTDBSqlParser.IntoClauseContext ctx) {
- boolean isAligned = ctx.ALIGNED() != null;
- if (ctx.intoDeviceAndMeasurement().size() > 0) {
- List<Pair<PartialPath, List<PartialPath>>> intoDeviceAndMeasurementList = new ArrayList<>();
- for (IoTDBSqlParser.IntoDeviceAndMeasurementContext intoDeviceAndMeasurementContext :
- ctx.intoDeviceAndMeasurement()) {
- PartialPath intoDevice = parseIntoPath(intoDeviceAndMeasurementContext.intoPath());
- List<PartialPath> intoMeasurements =
- intoDeviceAndMeasurementContext.nodeNameInIntoPath().stream()
- .map(
- nodeNameInIntoPathContext ->
- new PartialPath(parseNodeNameInIntoPath(nodeNameInIntoPathContext), false))
- .collect(Collectors.toList());
- intoDeviceAndMeasurementList.add(new Pair<>(intoDevice, intoMeasurements));
- }
- queryStatement.setIntoComponent(
- new AlignByDeviceIntoComponent(intoDeviceAndMeasurementList, isAligned));
- } else {
- List<PartialPath> intoPaths = new ArrayList<>();
- for (IoTDBSqlParser.IntoPathContext intoPathContext : ctx.intoPath()) {
- intoPaths.add(parseIntoPath(intoPathContext));
+ if (ctx.intoItem().size() > 0) {
+ List<IntoItem> intoItems = new ArrayList<>();
+ for (IoTDBSqlParser.IntoItemContext intoItemContext : ctx.intoItem()) {
+ intoItems.add(parseIntoItem(intoItemContext));
}
- queryStatement.setIntoComponent(new AlignByTimeIntoComponent(intoPaths, isAligned));
+ queryStatement.setIntoComponent(new IntoComponent(intoItems));
+ } else {
+ throw new SemanticException("The syntax of SELECT INTO statement has changed from v0.14");
}
}
+ private IntoItem parseIntoItem(IoTDBSqlParser.IntoItemContext intoItemContext) {
+ boolean isAligned = intoItemContext.ALIGNED() != null;
+ PartialPath intoDevice = parseIntoPath(intoItemContext.intoPath());
+ List<String> intoMeasurements =
+ intoItemContext.nodeNameInIntoPath().stream()
+ .map(this::parseNodeNameInIntoPath)
+ .collect(Collectors.toList());
+ return new IntoItem(intoDevice, intoMeasurements, isAligned);
+ }
+
private PartialPath parseIntoPath(IoTDBSqlParser.IntoPathContext intoPathContext) {
if (intoPathContext instanceof IoTDBSqlParser.FullPathInIntoPathContext) {
return parseFullPathInIntoPath((IoTDBSqlParser.FullPathInIntoPathContext) intoPathContext);
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/AlignByDeviceIntoComponent.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/AlignByDeviceIntoComponent.java
deleted file mode 100644
index 4cf1b14b78..0000000000
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/AlignByDeviceIntoComponent.java
+++ /dev/null
@@ -1,40 +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.mpp.plan.statement.component;
-
-import org.apache.iotdb.commons.path.PartialPath;
-import org.apache.iotdb.tsfile.utils.Pair;
-
-import java.util.List;
-
-public class AlignByDeviceIntoComponent extends IntoComponent {
-
- private final List<Pair<PartialPath, List<PartialPath>>> intoDeviceAndMeasurementList;
-
- public AlignByDeviceIntoComponent(
- List<Pair<PartialPath, List<PartialPath>>> intoDeviceAndMeasurementList, boolean isAligned) {
- super(isAligned);
- this.intoDeviceAndMeasurementList = intoDeviceAndMeasurementList;
- }
-
- public List<Pair<PartialPath, List<PartialPath>>> getIntoDeviceAndMeasurementList() {
- return intoDeviceAndMeasurementList;
- }
-}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/AlignByTimeIntoComponent.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/AlignByTimeIntoComponent.java
deleted file mode 100644
index c45a1c082d..0000000000
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/AlignByTimeIntoComponent.java
+++ /dev/null
@@ -1,38 +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.mpp.plan.statement.component;
-
-import org.apache.iotdb.commons.path.PartialPath;
-
-import java.util.List;
-
-public class AlignByTimeIntoComponent extends IntoComponent {
-
- private final List<PartialPath> intoPaths;
-
- public AlignByTimeIntoComponent(List<PartialPath> intoPaths, boolean isAligned) {
- super(isAligned);
- this.intoPaths = intoPaths;
- }
-
- public List<PartialPath> getIntoPaths() {
- return intoPaths;
- }
-}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/IntoComponent.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/IntoComponent.java
index 1e22c6fb9e..1eaa3ff073 100644
--- a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/IntoComponent.java
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/IntoComponent.java
@@ -19,16 +19,29 @@
package org.apache.iotdb.db.mpp.plan.statement.component;
+import org.apache.iotdb.db.mpp.plan.statement.StatementNode;
+
+import java.util.List;
+
/** This class maintains information of {@code INTO} clause. */
-public abstract class IntoComponent {
+public class IntoComponent extends StatementNode {
- protected final boolean isAligned;
+ private final List<IntoItem> intoItems;
+
+ public IntoComponent(List<IntoItem> intoItems) {
+ this.intoItems = intoItems;
+ }
- protected IntoComponent(boolean isAligned) {
- this.isAligned = isAligned;
+ public List<IntoItem> getIntoItems() {
+ return intoItems;
}
- public boolean isAligned() {
- return isAligned;
+ public boolean isDeviceExistPlaceholder() {
+ for (IntoItem intoItem : intoItems) {
+ if (intoItem.isDeviceExistPlaceholder()) {
+ return true;
+ }
+ }
+ return false;
}
}
diff --git a/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/IntoItem.java b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/IntoItem.java
new file mode 100644
index 0000000000..4efafe3cef
--- /dev/null
+++ b/server/src/main/java/org/apache/iotdb/db/mpp/plan/statement/component/IntoItem.java
@@ -0,0 +1,73 @@
+/*
+ * 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.mpp.plan.statement.component;
+
+import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.db.mpp.plan.statement.StatementNode;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.apache.iotdb.commons.conf.IoTDBConstant.DOUBLE_COLONS;
+import static org.apache.iotdb.commons.conf.IoTDBConstant.LEVELED_PATH_TEMPLATE_PATTERN;
+
+public class IntoItem extends StatementNode {
+
+ private final PartialPath intoDevice;
+ private final List<String> intoMeasurements;
+ private final boolean isAligned;
+
+ public IntoItem(PartialPath intoDevice, List<String> intoMeasurements, boolean isAligned) {
+ this.intoDevice = intoDevice;
+ this.intoMeasurements = intoMeasurements;
+ this.isAligned = isAligned;
+ }
+
+ public PartialPath getIntoDevice() {
+ return intoDevice;
+ }
+
+ public List<String> getIntoMeasurements() {
+ return intoMeasurements;
+ }
+
+ public boolean isAligned() {
+ return isAligned;
+ }
+
+ public boolean isDeviceExistPlaceholder() {
+ return intoDevice.containNode(DOUBLE_COLONS)
+ || LEVELED_PATH_TEMPLATE_PATTERN.matcher(intoDevice.getFullPath()).find();
+ }
+
+ public boolean isMeasurementsExistPlaceholder() {
+ for (String measurement : intoMeasurements) {
+ if (measurement.equals(DOUBLE_COLONS)
+ || LEVELED_PATH_TEMPLATE_PATTERN.matcher(measurement).find()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public List<PartialPath> getIntoPaths() {
+ return intoMeasurements.stream().map(intoDevice::concatNode).collect(Collectors.toList());
+ }
+}
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 ddab00ec44..d0c05930be 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,8 +27,6 @@ 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;
@@ -399,14 +397,6 @@ 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");
- }
}
}
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 767d499d3d..ae7d4d96bb 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
@@ -1271,25 +1271,31 @@ public class IoTDBSqlVisitor extends IoTDBSqlParserBaseVisitor<Operator> {
private SelectIntoOperator parseAndConstructSelectIntoOperator(
IoTDBSqlParser.SelectStatementContext ctx) {
+ IoTDBSqlParser.IntoClauseContext intoClauseContext = ctx.intoClause();
+ if (intoClauseContext.intoItem().size() > 0) {
+ throw new SQLParserException(
+ "The new syntax of SELECT INTO statement will be supported starting from v0.14");
+ }
+
if (queryOp.getFromComponent().getPrefixPaths().size() != 1) {
throw new SQLParserException(
"select into: the number of prefix paths in the from clause should be 1.");
}
-
int sourcePathsCount = queryOp.getSelectComponent().getResultColumns().size();
- if (sourcePathsCount != ctx.intoClause().intoPath().size()) {
+ if (sourcePathsCount != intoClauseContext.intoPath().size()) {
throw new SQLParserException(
"select into: the number of source paths and the number of target paths should be the same.");
}
SelectIntoOperator selectIntoOperator = new SelectIntoOperator();
selectIntoOperator.setQueryOperator(queryOp);
+
List<PartialPath> intoPaths = new ArrayList<>();
for (int i = 0; i < sourcePathsCount; ++i) {
- intoPaths.add(parseIntoPath(ctx.intoClause().intoPath(i)));
+ intoPaths.add(parseIntoPath(intoClauseContext.intoPath(i)));
}
selectIntoOperator.setIntoPaths(intoPaths);
- selectIntoOperator.setIntoPathsAligned(ctx.intoClause().ALIGNED() != null);
+ selectIntoOperator.setIntoPathsAligned(intoClauseContext.ALIGNED() != null);
return selectIntoOperator;
}