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)) {