This is an automated email from the ASF dual-hosted git repository.
SpriCoder pushed a commit to branch fs/inner-view
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/fs/inner-view by this push:
new d9de3fa4538 [FS] escape virtual table directory path segments
d9de3fa4538 is described below
commit d9de3fa45387208e6c596cc68406a0769d85ff68
Author: spricoder <[email protected]>
AuthorDate: Thu Sep 17 07:17:40 2026 +0800
[FS] escape virtual table directory path segments
---
.../ByDatabaseVirtualDirectoryResolver.java | 21 +++++++----
.../TableByTableVirtualDirectoryResolver.java | 43 ++++++++++++++++------
.../TableVirtualDirectoryResolverTest.java | 42 +++++++++++++++++++++
3 files changed, 87 insertions(+), 19 deletions(-)
diff --git
a/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/fs/virtualdir/ByDatabaseVirtualDirectoryResolver.java
b/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/fs/virtualdir/ByDatabaseVirtualDirectoryResolver.java
index 16b9d326272..ba10a23a0df 100644
---
a/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/fs/virtualdir/ByDatabaseVirtualDirectoryResolver.java
+++
b/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/fs/virtualdir/ByDatabaseVirtualDirectoryResolver.java
@@ -64,7 +64,8 @@ public class ByDatabaseVirtualDirectoryResolver implements
VirtualDirectoryResol
}
List<FsNode> nodes = new ArrayList<>();
for (FsNode node : delegate.list(canonicalPath(segments))) {
- nodes.add(VirtualDirectoryNodes.rewrite(node,
path.resolve(node.getName()), NAME));
+ String encodedName = VirtualDirectorySegments.encode(node.getName());
+ nodes.add(VirtualDirectoryNodes.rewrite(node, path.resolve(encodedName),
NAME));
}
return nodes;
}
@@ -114,20 +115,22 @@ public class ByDatabaseVirtualDirectoryResolver
implements VirtualDirectoryResol
if (database == null) {
continue;
}
- FsPath path =
VirtualDirectoryPaths.resolverRootPath(NAME).resolve(database);
+ String encodedDatabase = VirtualDirectorySegments.encode(database);
+ FsPath path =
VirtualDirectoryPaths.resolverRootPath(NAME).resolve(encodedDatabase);
nodes.add(
VirtualDirectoryNodes.directory(
- database, path, NAME,
canonicalDatabasePath(database).toString(), "database"));
+ encodedDatabase, path, NAME,
canonicalDatabasePath(database).toString(), "database"));
}
return nodes;
}
private FsNode describeDatabase(String database) throws SQLException {
+ String decodedDatabase = VirtualDirectorySegments.decode(database);
for (SqlRow row : executor.query("SHOW DATABASES")) {
- if (database.equals(row.get("Database"))) {
+ if (decodedDatabase.equals(row.get("Database"))) {
FsPath path =
VirtualDirectoryPaths.resolverRootPath(NAME).resolve(database);
return VirtualDirectoryNodes.directory(
- database, path, NAME, canonicalDatabasePath(database).toString(),
"database");
+ database, path, NAME,
canonicalDatabasePath(decodedDatabase).toString(), "database");
}
}
return VirtualDirectoryPaths.unknown(
@@ -144,13 +147,15 @@ public class ByDatabaseVirtualDirectoryResolver
implements VirtualDirectoryResol
return canonicalPath(segments);
}
- private FsPath canonicalPath(List<String> segments) {
+ private FsPath canonicalPath(List<String> segments) throws SQLException {
if (segments.isEmpty()) {
return FsPath.absolute("/");
}
- StringBuilder builder = new
StringBuilder(canonicalDatabasePath(segments.get(0)).toString());
+ StringBuilder builder =
+ new StringBuilder(
+
canonicalDatabasePath(VirtualDirectorySegments.decode(segments.get(0))).toString());
for (int i = 1; i < segments.size(); i++) {
- builder.append('/').append(segments.get(i));
+
builder.append('/').append(VirtualDirectorySegments.decode(segments.get(i)));
}
return FsPath.absolute(builder.toString());
}
diff --git
a/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/fs/virtualdir/TableByTableVirtualDirectoryResolver.java
b/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/fs/virtualdir/TableByTableVirtualDirectoryResolver.java
index 32fcc40fdef..736d2a97a14 100644
---
a/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/fs/virtualdir/TableByTableVirtualDirectoryResolver.java
+++
b/iotdb-client/cli/src/main/java/org/apache/iotdb/cli/fs/virtualdir/TableByTableVirtualDirectoryResolver.java
@@ -63,10 +63,13 @@ public class TableByTableVirtualDirectoryResolver
implements VirtualDirectoryRes
return listTableDirectories();
}
if (segments.size() == 1) {
- return listDatabaseDirectories(path, segments.get(0));
+ return listDatabaseDirectories(path,
VirtualDirectorySegments.decode(segments.get(0)));
}
if (segments.size() == 2) {
- return listTableFiles(path, segments.get(0), segments.get(1));
+ return listTableFiles(
+ path,
+ VirtualDirectorySegments.decode(segments.get(0)),
+ VirtualDirectorySegments.decode(segments.get(1)));
}
return new ArrayList<>();
}
@@ -78,12 +81,15 @@ public class TableByTableVirtualDirectoryResolver
implements VirtualDirectoryRes
return rootNode();
}
if (segments.size() == 1) {
- return tableExistsInAnyDatabase(segments.get(0))
+ String table = VirtualDirectorySegments.decode(segments.get(0));
+ return tableExistsInAnyDatabase(table)
? VirtualDirectoryNodes.directory(segments.get(0), path, NAME, "",
"table")
: VirtualDirectoryPaths.unknown(path);
}
if (segments.size() == 2) {
- return tableExists(segments.get(1), segments.get(0))
+ String table = VirtualDirectorySegments.decode(segments.get(0));
+ String database = VirtualDirectorySegments.decode(segments.get(1));
+ return tableExists(database, table)
? VirtualDirectoryNodes.directory(segments.get(1), path, NAME, "",
"database")
: VirtualDirectoryPaths.unknown(path);
}
@@ -126,10 +132,11 @@ public class TableByTableVirtualDirectoryResolver
implements VirtualDirectoryRes
}
List<FsNode> nodes = new ArrayList<>();
for (String table : tables) {
+ String encodedTable = VirtualDirectorySegments.encode(table);
nodes.add(
VirtualDirectoryNodes.directory(
- table,
- VirtualDirectoryPaths.resolverRootPath(NAME).resolve(table),
+ encodedTable,
+
VirtualDirectoryPaths.resolverRootPath(NAME).resolve(encodedTable),
NAME,
"",
"table"));
@@ -143,8 +150,10 @@ public class TableByTableVirtualDirectoryResolver
implements VirtualDirectoryRes
if (!tables(database).contains(table)) {
continue;
}
+ String encodedDatabase = VirtualDirectorySegments.encode(database);
nodes.add(
- VirtualDirectoryNodes.directory(database, path.resolve(database),
NAME, "", "database"));
+ VirtualDirectoryNodes.directory(
+ encodedDatabase, path.resolve(encodedDatabase), NAME, "",
"database"));
}
return nodes;
}
@@ -159,7 +168,9 @@ public class TableByTableVirtualDirectoryResolver
implements VirtualDirectoryRes
for (String fileName : fileNames) {
FsPath canonicalPath = FsPath.absolute("/" + database + "/" + fileName);
FsNode node = delegate.describe(canonicalPath);
- nodes.add(VirtualDirectoryNodes.rewrite(node, path.resolve(fileName),
NAME));
+ nodes.add(
+ VirtualDirectoryNodes.rewrite(
+ node, path.resolve(VirtualDirectorySegments.encode(fileName)),
NAME));
}
return nodes;
}
@@ -206,11 +217,21 @@ public class TableByTableVirtualDirectoryResolver
implements VirtualDirectoryRes
throw new SQLException(
String.format(FsVirtualMessages.EXCEPTION_PATH_IS_NOT_READABLE_ARG_4B338AD7,
path));
}
- return canonicalTableFilePath(segments);
+ return canonicalTableFilePath(
+ VirtualDirectorySegments.decode(segments.get(0)),
+ VirtualDirectorySegments.decode(segments.get(1)),
+ VirtualDirectorySegments.decode(segments.get(2)));
+ }
+
+ private static FsPath canonicalTableFilePath(List<String> segments) throws
SQLException {
+ return canonicalTableFilePath(
+ VirtualDirectorySegments.decode(segments.get(0)),
+ VirtualDirectorySegments.decode(segments.get(1)),
+ VirtualDirectorySegments.decode(segments.get(2)));
}
- private static FsPath canonicalTableFilePath(List<String> segments) {
- return FsPath.absolute("/" + segments.get(1) + "/" + segments.get(2));
+ private static FsPath canonicalTableFilePath(String table, String database,
String fileName) {
+ return FsPath.absolute("/" + database + "/" + fileName);
}
private static String identifier(String value) {
diff --git
a/iotdb-client/cli/src/test/java/org/apache/iotdb/cli/fs/virtualdir/TableVirtualDirectoryResolverTest.java
b/iotdb-client/cli/src/test/java/org/apache/iotdb/cli/fs/virtualdir/TableVirtualDirectoryResolverTest.java
index 8e2680bb0e9..e675c3ac279 100644
---
a/iotdb-client/cli/src/test/java/org/apache/iotdb/cli/fs/virtualdir/TableVirtualDirectoryResolverTest.java
+++
b/iotdb-client/cli/src/test/java/org/apache/iotdb/cli/fs/virtualdir/TableVirtualDirectoryResolverTest.java
@@ -66,6 +66,27 @@ public class TableVirtualDirectoryResolverTest {
assertEquals("/db1", nodes.get(0).getMetadata().get("canonicalPath"));
}
+ @Test
+ public void byDatabaseEscapesDatabaseAndChildNames() throws SQLException {
+ when(executor.query("SHOW DATABASES"))
+ .thenReturn(SqlRow.list(SqlRow.of("Database", "db name")));
+ when(delegate.list(FsPath.absolute("/db name")))
+ .thenReturn(
+ Arrays.asList(
+ new FsNode(
+ "table name.csv",
+ FsPath.absolute("/db name/table name.csv"),
+ FsNodeType.TABLE_DATA_FILE)));
+
+ List<FsNode> databases =
byDatabase.list(FsPath.absolute("/.virtual/by-database"));
+ List<FsNode> children =
byDatabase.list(FsPath.absolute("/.virtual/by-database/db%20name"));
+
+ assertEquals("db%20name", databases.get(0).getName());
+ assertEquals("/.virtual/by-database/db%20name",
databases.get(0).getPath().toString());
+ assertEquals(
+ "/.virtual/by-database/db%20name/table%20name.csv",
children.get(0).getPath().toString());
+ }
+
@Test
public void byDatabaseListsCanonicalChildrenUnderVirtualPath() throws
SQLException {
when(delegate.list(FsPath.absolute("/db1")))
@@ -118,4 +139,25 @@ public class TableVirtualDirectoryResolverTest {
assertEquals("1,42", lines.get(1));
verify(delegate).readLines(FsPath.absolute("/db1/t1.csv"), 5);
}
+
+ @Test
+ public void byTableEscapesTableAndDatabaseNames() throws SQLException {
+ when(executor.query("SHOW DATABASES"))
+ .thenReturn(SqlRow.list(SqlRow.of("Database", "db name")));
+ when(executor.query("SHOW TABLES FROM \"db name\""))
+ .thenReturn(SqlRow.list(SqlRow.of("TableName", "table name")));
+ when(delegate.readLines(FsPath.absolute("/db name/table name.csv"), 5))
+ .thenReturn(Arrays.asList("Time,value", "1,42"));
+
+ List<FsNode> tables = byTable.list(FsPath.absolute("/.virtual/by-table"));
+ List<FsNode> databases =
byTable.list(FsPath.absolute("/.virtual/by-table/table%20name"));
+ List<String> lines =
+ byTable.readLines(
+
FsPath.absolute("/.virtual/by-table/table%20name/db%20name/table%20name.csv"),
5);
+
+ assertEquals("table%20name", tables.get(0).getName());
+ assertEquals("db%20name", databases.get(0).getName());
+ assertEquals("1,42", lines.get(1));
+ verify(delegate).readLines(FsPath.absolute("/db name/table name.csv"), 5);
+ }
}