diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBSeriesPermissionIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBSeriesPermissionIT.java index a0feb9712dafc..c6e23467413fe 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBSeriesPermissionIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBSeriesPermissionIT.java @@ -354,6 +354,74 @@ private void testReadData() { "test123123456"); } + @Test + public void showTTLWithMultiLevelWildcardTest() throws SQLException { + try (Connection connection = EnvFactory.getEnv().getConnection(); + Statement statement = connection.createStatement()) { + statement.execute("create user ttl_scope_user 'test123123456'"); + statement.execute("set ttl to root.ttl_scope_a 3600000"); + statement.execute("set ttl to root.ttl_scope_b 7200000"); + + try (ResultSet resultSet = statement.executeQuery("show ttl on root.ttl_scope_a.g_0.**")) { + Assert.assertFalse(resultSet.next()); + } + + statement.execute("set ttl to root.ttl_scope_a.g_0.** 10000"); + String[] headers = + showTTLColumnHeaders.stream().map(ColumnHeader::getColumnName).toArray(String[]::new); + resultSetEqualTest( + "show ttl on root.ttl_scope_a.g_0.**", + headers, + new String[] {"root.ttl_scope_a.g_0.**,10000,"}); + + resultSetEqualTest( + "show ttl on root.*.**", headers, new String[0], "ttl_scope_user", "test123123456"); + statement.execute("grant READ_SCHEMA on root.ttl_scope_a.** to user ttl_scope_user"); + for (String query : + new String[] {"show ttl on root.*.**", "show ttl on root.ttl_*.**", "show all ttl"}) { + resultSetEqualTest( + query, + headers, + new String[] {"root.ttl_scope_a,3600000,", "root.ttl_scope_a.g_0.**,10000,"}, + "ttl_scope_user", + "test123123456"); + } + for (String query : + new String[] {"show ttl on root.*.g_*.**", "show ttl on root.ttl_*.g_0.**"}) { + resultSetEqualTest( + query, + headers, + new String[] {"root.ttl_scope_a.g_0.**,10000,"}, + "ttl_scope_user", + "test123123456"); + } + resultSetEqualTest( + "show ttl on root.ttl_scope_b.**", + headers, + new String[0], + "ttl_scope_user", + "test123123456"); + statement.execute("revoke READ_SCHEMA on root.ttl_scope_a.** from user ttl_scope_user"); + statement.execute("grant READ_SCHEMA on root.ttl_scope_a.g_0.** to user ttl_scope_user"); + for (String query : new String[] {"show ttl on root.*.**", "show ttl on root.ttl_*.**"}) { + resultSetEqualTest( + query, + headers, + new String[] {"root.ttl_scope_a.g_0.**,10000,"}, + "ttl_scope_user", + "test123123456"); + } + } finally { + try (Connection connection = EnvFactory.getEnv().getConnection(); + Statement statement = connection.createStatement()) { + executeQuietly(statement, "drop user ttl_scope_user"); + executeQuietly(statement, "unset ttl from root.ttl_scope_a.g_0.**"); + executeQuietly(statement, "unset ttl from root.ttl_scope_a"); + executeQuietly(statement, "unset ttl from root.ttl_scope_b"); + } + } + } + @Test public void ttlOperationsTest() { try { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java index d7dd2abcb1d38..995d30f525d6a 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java @@ -1786,13 +1786,19 @@ public SettableFuture showTTL(ShowTTLStatement showTTLStatemen databaseToTTL.putAll(resp.getPathTTLMap()); continue; } + PathPatternTree queryScope = new PathPatternTree(); + queryScope.appendPathPattern(pathPattern); + queryScope.constructTree(); + // Query patterns may contain wildcards before the trailing **. Only the authority + // scope is restricted to full paths and literal prefixes. for (PartialPath overlappedPathPattern : - authorityScope.getOverlappedPathPatterns(pathPattern)) { + queryScope.intersectWithFullPathPrefixTree(authorityScope).getAllPathPatterns()) { List nodes = Arrays.asList(overlappedPathPattern.getNodes()); TShowTTLReq req = new TShowTTLReq(nodes); TShowTTLResp resp = client.showTTL(req); databaseToTTL.putAll(resp.getPathTTLMap()); - if (showTTLStatement.isShowAllTTL()) { + // TTL rules can be stored on the prefix itself as well as on prefix.**. + if (overlappedPathPattern.endWithMultiLevelWildcard()) { req.setPathPattern(nodes.subList(0, nodes.size() - 1)); resp = client.showTTL(req); databaseToTTL.putAll(resp.getPathTTLMap());