You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by zy...@apache.org on 2023/05/08 00:31:25 UTC

[iotdb] branch rel/1.1 updated: [To rel/1.1][IOTDB-5824][IOTDB-5826] Fix devices and template query with * (#9770)

This is an automated email from the ASF dual-hosted git repository.

zyk pushed a commit to branch rel/1.1
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/rel/1.1 by this push:
     new 2bc989c61d [To rel/1.1][IOTDB-5824][IOTDB-5826] Fix devices and template query with * (#9770)
2bc989c61d is described below

commit 2bc989c61df8f5238433189047dac855bb005fbe
Author: Chen YZ <43...@users.noreply.github.com>
AuthorDate: Mon May 8 08:31:19 2023 +0800

    [To rel/1.1][IOTDB-5824][IOTDB-5826] Fix devices and template query with * (#9770)
---
 .../iotdb/confignode/manager/ConfigManager.java    | 11 ++--
 .../iotdb/db/it/schema/IoTDBMetadataFetchIT.java   | 49 +++++++++++++++++
 .../iotdb/db/it/schema/IoTDBSchemaTemplateIT.java  | 62 ++++++++++++++++++++++
 .../org/apache/iotdb/commons/path/PartialPath.java | 40 ++++++++++++++
 .../metadata/template/ClusterTemplateManager.java  | 10 ++--
 5 files changed, 160 insertions(+), 12 deletions(-)

diff --git a/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java b/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
index 807c0e66ac..0041f38db4 100644
--- a/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
+++ b/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
@@ -186,7 +186,6 @@ import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 
-import static org.apache.iotdb.commons.conf.IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD;
 import static org.apache.iotdb.commons.conf.IoTDBConstant.ONE_LEVEL_PATH_WILDCARD;
 
 /** Entry of all management, AssignPartitionManager,AssignRegionManager. */
@@ -578,8 +577,11 @@ public class ConfigManager implements IManager {
     if (path.getFullPath().contains(IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD)) {
       return new ArrayList<>();
     }
-    // path doesn't contain * so the size of innerPathList should be 1
-    PartialPath innerPath = path.alterPrefixPath(database).get(0);
+    List<PartialPath> innerPathList = path.alterPrefixPath(database);
+    if (innerPathList.size() == 0) {
+      return new ArrayList<>();
+    }
+    PartialPath innerPath = innerPathList.get(0);
     // The innerPath contains `*` and the only `*` is not in last level
     if (innerPath.getDevice().contains(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD)) {
       return new ArrayList<>();
@@ -615,8 +617,7 @@ public class ConfigManager implements IManager {
       for (int i = 0; i < allDatabases.size(); i++) {
         String database = allDatabases.get(i);
         PartialPath databasePath = allDatabasePaths.get(i);
-        if (path.overlapWith(databasePath.concatNode(MULTI_LEVEL_PATH_WILDCARD))
-            && !scanAllRegions.containsKey(database)) {
+        if (path.overlapWithFullPathPrefix(databasePath) && !scanAllRegions.containsKey(database)) {
           List<TSeriesPartitionSlot> relatedSlot = calculateRelatedSlot(path, databasePath);
           if (relatedSlot.isEmpty()) {
             scanAllRegions.put(database, true);
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBMetadataFetchIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBMetadataFetchIT.java
index 2a669c298b..da0813d905 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBMetadataFetchIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBMetadataFetchIT.java
@@ -274,6 +274,55 @@ public class IoTDBMetadataFetchIT extends AbstractSchemaIT {
     }
   }
 
+  @Test
+  public void showDevicesWithWildcardTest() throws SQLException {
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      String[] sqls =
+          new String[] {
+            "show devices root.l*.wf01.w*",
+            "show devices root.ln.*f01.*",
+            "show devices root.l*.*f*.*t01",
+          };
+      Set<String>[] standards =
+          new Set[] {
+            new HashSet<>(
+                Arrays.asList(
+                    "root.ln.wf01.wt01,false,",
+                    "root.ln.wf01.wt02,true,",
+                    "root.ln1.wf01.wt01,false,",
+                    "root.ln2.wf01.wt01,false,")),
+            new HashSet<>(Arrays.asList("root.ln.wf01.wt01,false,", "root.ln.wf01.wt02,true,")),
+            new HashSet<>(
+                Arrays.asList(
+                    "root.ln.wf01.wt01,false,",
+                    "root.ln1.wf01.wt01,false,",
+                    "root.ln2.wf01.wt01,false,"))
+          };
+
+      for (int n = 0; n < sqls.length; n++) {
+        String sql = sqls[n];
+        Set<String> standard = standards[n];
+        try (ResultSet resultSet = statement.executeQuery(sql)) {
+          ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
+          while (resultSet.next()) {
+            StringBuilder builder = new StringBuilder();
+            for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) {
+              builder.append(resultSet.getString(i)).append(",");
+            }
+            String string = builder.toString();
+            Assert.assertTrue(standard.contains(string));
+            standard.remove(string);
+          }
+          assertEquals(0, standard.size());
+        } catch (SQLException e) {
+          e.printStackTrace();
+          fail(e.getMessage());
+        }
+      }
+    }
+  }
+
   @Test
   public void showChildPaths() throws SQLException {
     try (Connection connection = EnvFactory.getEnv().getConnection();
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBSchemaTemplateIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBSchemaTemplateIT.java
index 78d4f787bd..377458c546 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBSchemaTemplateIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/IoTDBSchemaTemplateIT.java
@@ -569,4 +569,66 @@ public class IoTDBSchemaTemplateIT extends AbstractSchemaIT {
       }
     }
   }
+
+  @Test
+  public void testShowTemplateSeriesWithFuzzyQuery() throws Exception {
+    // test create schema template repeatedly
+    try (Connection connection = EnvFactory.getEnv().getConnection();
+        Statement statement = connection.createStatement()) {
+      statement.execute("CREATE SCHEMA TEMPLATE t3 aligned (s1 INT64)");
+      // set schema template
+      statement.execute("SET SCHEMA TEMPLATE t1 TO root.sg1");
+      statement.execute("SET SCHEMA TEMPLATE t2 TO root.sg2");
+      statement.execute("SET SCHEMA TEMPLATE t3 TO root.sg3");
+      // activate schema template
+      statement.execute("create timeseries using schema template on root.sg1.d1");
+      statement.execute("create timeseries using schema template on root.sg2.d2");
+      statement.execute("create timeseries using schema template on root.sg3.d3");
+
+      Set<String> expectedResult =
+          new HashSet<>(
+              Arrays.asList(
+                  "root.sg1.d1.s1,INT64,RLE,SNAPPY",
+                  "root.sg1.d1.s2,DOUBLE,GORILLA,SNAPPY",
+                  "root.sg2.d2.s1,INT64,RLE,SNAPPY",
+                  "root.sg2.d2.s2,DOUBLE,GORILLA,SNAPPY",
+                  "root.sg3.d3.s1,INT64,RLE,SNAPPY"));
+
+      try (ResultSet resultSet = statement.executeQuery("SHOW TIMESERIES root.sg*.*.s*")) {
+        while (resultSet.next()) {
+          String actualResult =
+              resultSet.getString(ColumnHeaderConstant.TIMESERIES)
+                  + ","
+                  + resultSet.getString(ColumnHeaderConstant.DATATYPE)
+                  + ","
+                  + resultSet.getString(ColumnHeaderConstant.ENCODING)
+                  + ","
+                  + resultSet.getString(ColumnHeaderConstant.COMPRESSION);
+          Assert.assertTrue(expectedResult.contains(actualResult));
+          expectedResult.remove(actualResult);
+        }
+      }
+      Assert.assertTrue(expectedResult.isEmpty());
+      expectedResult =
+          new HashSet<>(
+              Arrays.asList(
+                  "root.sg1.d1.s1,INT64,RLE,SNAPPY", "root.sg1.d1.s2,DOUBLE,GORILLA,SNAPPY"));
+
+      try (ResultSet resultSet = statement.executeQuery("SHOW TIMESERIES root.sg1.d1.s*")) {
+        while (resultSet.next()) {
+          String actualResult =
+              resultSet.getString(ColumnHeaderConstant.TIMESERIES)
+                  + ","
+                  + resultSet.getString(ColumnHeaderConstant.DATATYPE)
+                  + ","
+                  + resultSet.getString(ColumnHeaderConstant.ENCODING)
+                  + ","
+                  + resultSet.getString(ColumnHeaderConstant.COMPRESSION);
+          Assert.assertTrue(expectedResult.contains(actualResult));
+          expectedResult.remove(actualResult);
+        }
+      }
+      Assert.assertTrue(expectedResult.isEmpty());
+    }
+  }
 }
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 e3c6690ca7..cc81983f7a 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
@@ -457,6 +457,46 @@ public class PartialPath extends Path implements Comparable<Path>, Cloneable {
     return this.nodes.length == rNodes.length;
   }
 
+  /**
+   * Test if this path pattern overlaps with input prefix full path. Overlap means the result sets
+   * generated by two path pattern share some common elements. e.g.
+   *
+   * <ul>
+   *   <li>"root.sg.**" overlaps with prefix full path "root" because "root.sg.**" share some common
+   *       element "root.sg.d" with "root.**"
+   *   <li>"root.*.d*.s" overlaps with prefix full path "root.sg" because "root.*.d*.s" share some
+   *       common element "root.sg.d1.s" with "root.sg.**"
+   *   <li>"root.*.d.s" doesn't overlap with prefix full path "root.sg.d1" because there is no
+   *       common element between "root.*.d.s" and "root.sg.d1.**"
+   * </ul>
+   *
+   * @param prefixFullPath prefix full path
+   * @return true if overlapping otherwise return false
+   */
+  public boolean overlapWithFullPathPrefix(PartialPath prefixFullPath) {
+    String[] rNodes = prefixFullPath.getNodes();
+    int rNodesIndex = 0;
+    for (int i = 0; i < this.nodes.length && rNodesIndex < rNodes.length; i++) {
+      // if encounter MULTI_LEVEL_PATH_WILDCARD
+      if (nodes[i].equals(MULTI_LEVEL_PATH_WILDCARD)) {
+        return true;
+      } else if (nodes[i].equals(ONE_LEVEL_PATH_WILDCARD)) {
+        rNodesIndex++;
+      } else if (nodes[i].contains(ONE_LEVEL_PATH_WILDCARD)) {
+        if (!Pattern.compile(nodes[i].replace("*", ".*")).matcher(rNodes[rNodesIndex]).matches()) {
+          return false;
+        } else {
+          rNodesIndex++;
+        }
+      } else if (nodes[i].equals(rNodes[rNodesIndex])) {
+        rNodesIndex++;
+      } else {
+        return false;
+      }
+    }
+    return true;
+  }
+
   /**
    * Try to check overlap between nodes1 and nodes2 with MULTI_LEVEL_PATH_WILDCARD. Time complexity
    * O(n^2).
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/template/ClusterTemplateManager.java b/server/src/main/java/org/apache/iotdb/db/metadata/template/ClusterTemplateManager.java
index b46613fb3f..59e37daaea 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/template/ClusterTemplateManager.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/template/ClusterTemplateManager.java
@@ -305,13 +305,9 @@ public class ClusterTemplateManager implements ITemplateManager {
     // and the following logic is equivalent with the above expression
 
     String measurement = pathPattern.getTailNode();
-    if (measurement.equals(MULTI_LEVEL_PATH_WILDCARD)
-        || measurement.equals(ONE_LEVEL_PATH_WILDCARD)) {
-      return pathPattern.overlapWith(
-              pathSetTemplate
-                  .concatNode(MULTI_LEVEL_PATH_WILDCARD)
-                  .concatNode(ONE_LEVEL_PATH_WILDCARD))
-          || pathPattern.overlapWith(pathSetTemplate.concatNode(ONE_LEVEL_PATH_WILDCARD));
+    if (measurement.contains(ONE_LEVEL_PATH_WILDCARD)) {
+      // if measurement is wildcard, e.g. root.sg.d1.**, root.sg.d1.*, root.sg.d1.s*
+      return pathPattern.overlapWithFullPathPrefix(pathSetTemplate);
     }
 
     if (template.hasSchema(measurement)) {