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/13 10:57:33 UTC

[iotdb] 01/04: finish analyzer

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 fa3290a015b682d3c606c5ef9c0f28e7d7fb5f2f
Author: Minghui Liu <li...@foxmail.com>
AuthorDate: Wed Oct 12 17:32:55 2022 +0800

    finish analyzer
---
 .../iotdb/db/mpp/plan/analyze/AnalyzeVisitor.java  | 288 ++++++++++++++++-----
 .../plan/statement/component/IntoComponent.java    |   9 +
 2 files changed, 228 insertions(+), 69 deletions(-)

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 2731e84907..f28f1064fb 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
@@ -105,7 +105,6 @@ 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;
@@ -413,15 +412,15 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
     // device path patterns in FROM clause
     List<PartialPath> devicePatternList = queryStatement.getFromComponent().getPrefixPaths();
 
-    Set<PartialPath> deviceList = new LinkedHashSet<>();
+    Set<PartialPath> deviceSet = new LinkedHashSet<>();
     for (PartialPath devicePattern : devicePatternList) {
       // get all matched devices
-      deviceList.addAll(
+      deviceSet.addAll(
           schemaTree.getMatchedDevices(devicePattern).stream()
               .map(DeviceSchemaInfo::getDevicePath)
               .collect(Collectors.toList()));
     }
-    return deviceList;
+    return deviceSet;
   }
 
   private List<Pair<Expression, String>> analyzeSelect(
@@ -1010,72 +1009,145 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
     IntoComponent intoComponent = queryStatement.getIntoComponent();
     List<IntoItem> intoItems = intoComponent.getIntoItems();
 
-    Map<PartialPath, PartialPath> sourceDeviceToTargetDeviceMap = new HashMap<>();
     List<PartialPath> sourceDevices = new ArrayList<>(deviceSet);
+    List<PartialPath> targetDevices = new ArrayList<>(sourceDevices.size());
     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());
+      for (PartialPath sourceDevice : sourceDevices) {
+        targetDevices.add(constructIntoDevice(sourceDevice, deviceTemplate));
       }
     } 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());
+      for (IntoItem intoItem : intoItems) {
+        targetDevices.add(intoItem.getIntoDevice());
       }
     }
 
     PatternTreeMap<String, PatternTreeMapFactory.StringSerializer> intoPathPatternTreeMap =
         PatternTreeMapFactory.getIntoPathPatternTreeMap();
 
-    if (isAllRawSeriesQuery) {
+    if (intoComponent.isMeasurementsExistPlaceholder()) {
+      if (!isAllRawSeriesQuery) {
+        throw new SemanticException("");
+      }
+
+      if (intoComponent.isDeviceExistPlaceholder()) {
+        String measurementTemplate = intoItems.get(0).getIntoMeasurements().get(0);
+        for (int i = 0; i < targetDevices.size(); i++) {
+          PartialPath targetDevice = targetDevices.get(i);
+          for (Expression outputColumn : outputColumns) {
+            PartialPath intoPath =
+                targetDevice.concatNode(
+                    constructIntoMeasurement(
+                        sourceDevices.get(i).concatNode(outputColumn.toString()),
+                        measurementTemplate));
+            intoPathPatternTreeMap.append(intoPath, outputColumn.toString());
+            if (intoPathPatternTreeMap.getOverlapped(intoPath).size() > 1) {
+              throw new SemanticException(
+                  "select into: target paths in into clause should be different.");
+            }
+          }
+        }
+      } else {
+        for (int deviceIndex = 0; deviceIndex < sourceDevices.size(); deviceIndex++) {
+          IntoItem intoItem = intoItems.get(deviceIndex);
+          List<String> intoMeasurements = intoItem.getIntoMeasurements();
+          PartialPath targetDevice = targetDevices.get(deviceIndex);
+
+          if (intoItem.isMeasurementsExistPlaceholder()) {
+            if (intoMeasurements.size() > 1) {
+              throw new SemanticException("");
+            }
+
+            String measurementTemplate = intoMeasurements.get(0);
+            for (Expression outputColumn : outputColumns) {
+              PartialPath intoPath =
+                  targetDevice.concatNode(
+                      constructIntoMeasurement(
+                          sourceDevices.get(deviceIndex).concatNode(outputColumn.toString()),
+                          measurementTemplate));
+              intoPathPatternTreeMap.append(intoPath, outputColumn.toString());
+              if (intoPathPatternTreeMap.getOverlapped(intoPath).size() > 1) {
+                throw new SemanticException(
+                    "select into: target paths in into clause should be different.");
+              }
+            }
+          } else {
+            if (intoMeasurements.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 measurementIndex = 0;
+                measurementIndex < intoMeasurements.size();
+                measurementIndex++) {
+              PartialPath intoPath =
+                  targetDevice.concatNode(intoMeasurements.get(measurementIndex));
+              intoPathPatternTreeMap.append(
+                  intoPath, outputColumns.get(measurementIndex).toString());
+              if (intoPathPatternTreeMap.getOverlapped(intoPath).size() > 1) {
+                throw new SemanticException(
+                    "select into: target paths in into clause should be different.");
+              }
+            }
+          }
+        }
+      }
     } else {
-      // disable placeholder
-      for (IntoItem intoItem : intoItems) {
-        if (intoItem.isMeasurementsExistPlaceholder()) {
+      for (int deviceIndex = 0; deviceIndex < sourceDevices.size(); deviceIndex++) {
+        IntoItem intoItem = intoItems.get(deviceIndex);
+        List<String> intoMeasurements = intoItem.getIntoMeasurements();
+        if (intoMeasurements.size() != outputColumns.size()) {
           throw new SemanticException(
-              "select into: placeholders can only be used in raw timeseries data queries.");
+              "select into: the number of source columns and the number of target paths should be the same.");
         }
-      }
 
-      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.");
+        PartialPath targetDevice = targetDevices.get(deviceIndex);
+        for (int measurementIndex = 0;
+            measurementIndex < intoMeasurements.size();
+            measurementIndex++) {
+          PartialPath intoPath = targetDevice.concatNode(intoMeasurements.get(measurementIndex));
+          intoPathPatternTreeMap.append(intoPath, outputColumns.get(measurementIndex).toString());
+          if (intoPathPatternTreeMap.getOverlapped(intoPath).size() > 1) {
+            throw new SemanticException(
+                "select into: target paths in into clause should be different.");
+          }
+        }
       }
+    }
+
+    if (isAllRawSeriesQuery) {
+      if (intoComponent.isDeviceExistPlaceholder()) {
+        if (intoComponent.isMeasurementsExistPlaceholder()) {
+          String measurementTemplate = intoItems.get(0).getIntoMeasurements().get(0);
+          for (int i = 0; i < targetDevices.size(); i++) {
+            PartialPath targetDevice = targetDevices.get(i);
+            for (Expression outputColumn : outputColumns) {
+              PartialPath intoPath =
+                  targetDevice.concatNode(
+                      constructIntoMeasurement(
+                          sourceDevices.get(i).concatNode(outputColumn.toString()),
+                          measurementTemplate));
+              intoPathPatternTreeMap.append(intoPath, outputColumn.toString());
+              if (intoPathPatternTreeMap.getOverlapped(intoPath).size() > 1) {
+                throw new SemanticException(
+                    "select into: target paths in into clause should be different.");
+              }
+            }
+          }
+        } else {
 
-      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());
       }
+    } else {
+
     }
     analyzeIntoDevices(analysis, intoItems);
     analysis.setIntoPathPatternTreeMap(intoPathPatternTreeMap);
@@ -1092,17 +1164,16 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
         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();
+      Matcher matcher = LEVELED_PATH_TEMPLATE_PATTERN.matcher(resNode);
+      while (matcher.find()) {
+        String param = matcher.group();
         int index;
         try {
           index = Integer.parseInt(param.substring(2, param.length() - 1).trim());
@@ -1113,6 +1184,8 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
           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.");
         }
+        resNode = matcher.replaceFirst(sourceNodes[index]);
+        matcher = LEVELED_PATH_TEMPLATE_PATTERN.matcher(resNode);
       }
       targetNodes.add(resNode);
     }
@@ -1136,11 +1209,68 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
     IntoComponent intoComponent = queryStatement.getIntoComponent();
     List<IntoItem> intoItems = intoComponent.getIntoItems();
 
+    List<PartialPath> intoPaths = new ArrayList<>();
     PatternTreeMap<String, PatternTreeMapFactory.StringSerializer> intoPathPatternTreeMap =
         PatternTreeMapFactory.getIntoPathPatternTreeMap();
 
     if (isAllRawSeriesQuery) {
+      List<PartialPath> sourcePaths =
+          outputColumns.stream()
+              .map(expression -> ((TimeSeriesOperand) expression).getPath())
+              .collect(Collectors.toList());
+
+      if (intoComponent.isDeviceExistPlaceholder()) {
+        if (intoComponent.isMeasurementsExistPlaceholder()) {
+          if (intoItems.size() > 1) {
+            throw new SemanticException("");
+          }
+          if (intoItems.get(0).getIntoMeasurements().size() > 1) {
+            throw new SemanticException("");
+          }
+
+          PartialPath deviceTemplate = intoItems.get(0).getIntoDevice();
+          String measurementTemplate = intoItems.get(0).getIntoMeasurements().get(0);
+          for (PartialPath sourcePath : sourcePaths) {
+            intoPaths.add(constructIntoPath(sourcePath, deviceTemplate, measurementTemplate));
+          }
+        } else {
+          int sourcePathIndex = 0;
+          for (IntoItem intoItem : intoItems) {
+            PartialPath deviceTemplate = intoItem.getIntoDevice();
+            List<String> measurementList = intoItem.getIntoMeasurements();
+            for (String measurement : measurementList) {
+              intoPaths.add(
+                  constructIntoPath(sourcePaths.get(sourcePathIndex), deviceTemplate, measurement));
+              sourcePathIndex++;
+            }
+          }
+        }
+      } else {
+        if (intoComponent.isMeasurementsExistPlaceholder()) {
+          if (intoItems.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 < intoItems.size(); i++) {
+            if (intoItems.get(i).getIntoMeasurements().size() != 1) {
+              throw new SemanticException("");
+            }
 
+            PartialPath targetDevice = intoItems.get(i).getIntoDevice();
+            intoPaths.add(
+                targetDevice.concatNode(
+                    constructIntoMeasurement(
+                        sourcePaths.get(i), intoItems.get(0).getIntoMeasurements().get(0))));
+          }
+        } else {
+          intoPaths =
+              intoItems.stream()
+                  .map(IntoItem::getIntoPaths)
+                  .flatMap(List::stream)
+                  .collect(Collectors.toList());
+        }
+      }
     } else {
       // disable placeholder
       for (IntoItem intoItem : intoItems) {
@@ -1150,26 +1280,27 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
         }
       }
 
-      List<PartialPath> intoPaths =
+      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.");
-      }
+    // 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.");
-        }
+    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.");
       }
     }
+
     analyzeIntoDevices(analysis, intoItems);
     analysis.setIntoPathPatternTreeMap(intoPathPatternTreeMap);
   }
@@ -1194,24 +1325,43 @@ public class AnalyzeVisitor extends StatementVisitor<Analysis, MPPQueryContext>
   private boolean checkIsAllRawSeriesQuery(List<Expression> expressions) {
     for (Expression expression : expressions) {
       if (!(expression instanceof TimeSeriesOperand)) {
-        return true;
+        return false;
       }
     }
-    return false;
+    return true;
   }
 
   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: ");
+      PartialPath sourcePath, PartialPath deviceTemplate, String measurementTemplate) {
+    PartialPath targetDevice = constructIntoDevice(sourcePath.getDevicePath(), deviceTemplate);
+    String targetMeasurement = constructIntoMeasurement(sourcePath, measurementTemplate);
+    return targetDevice.concatNode(targetMeasurement);
+  }
+
+  private String constructIntoMeasurement(PartialPath sourcePath, String measurementTemplate) {
+    if (measurementTemplate.equals(DOUBLE_COLONS)) {
+      return sourcePath.getMeasurement();
     }
-    if (LEVELED_PATH_TEMPLATE_PATTERN.matcher(path.getFullPath()).find()) {
-      throw new SemanticException("select into: ");
+
+    String[] sourceNodes = sourcePath.getNodes();
+    String resNode = measurementTemplate;
+    Matcher matcher = LEVELED_PATH_TEMPLATE_PATTERN.matcher(resNode);
+    while (matcher.find()) {
+      String param = matcher.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.");
+      }
+      resNode = matcher.replaceFirst(sourceNodes[index]);
+      matcher = LEVELED_PATH_TEMPLATE_PATTERN.matcher(resNode);
     }
-    return new MeasurementPath(path, analysis.getType(outputColumn), isAligned);
+    return resNode;
   }
 
   /**
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 1eaa3ff073..c5848a3752 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
@@ -44,4 +44,13 @@ public class IntoComponent extends StatementNode {
     }
     return false;
   }
+
+  public boolean isMeasurementsExistPlaceholder() {
+    for (IntoItem intoItem : intoItems) {
+      if (intoItem.isMeasurementsExistPlaceholder()) {
+        return true;
+      }
+    }
+    return false;
+  }
 }