From a56f2d5e721035a3855656b028d9b4dade23db77 Mon Sep 17 00:00:00 2001 From: Caideyipi <87789683+Caideyipi@users.noreply.github.com> Date: Mon, 13 Apr 2026 16:30:48 +0800 Subject: [PATCH 01/19] fix --- .../protocol/v2/impl/RestApiServiceImpl.java | 19 ++++---- .../thrift/impl/ClientRPCServiceImpl.java | 43 ++++++++++++------- 2 files changed, 39 insertions(+), 23 deletions(-) diff --git a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java index f6c42533a6231..08338c8dde49a 100644 --- a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java +++ b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java @@ -133,20 +133,23 @@ public Response executeFastLastQueryStatement( } sensorNum += region.fillLastQueryMap(prefixPath, resultMap); } + + final IClientSession clientSession = SESSION_MANAGER.getCurrSession(); + final TSLastDataQueryReq tsLastDataQueryReq = + FastLastHandler.createTSLastDataQueryReq(clientSession, prefixPathList); + statement = StatementGenerator.createStatement(tsLastDataQueryReq); + + final Response response = authorizationHandler.checkAuthority(securityContext, statement); + if (response != null) { + return response; + } + // Check cache first if (!TableDeviceSchemaCache.getInstance().getLastCache(resultMap)) { - IClientSession clientSession = SESSION_MANAGER.getCurrSession(); - TSLastDataQueryReq tsLastDataQueryReq = - FastLastHandler.createTSLastDataQueryReq(clientSession, prefixPathList); - statement = StatementGenerator.createStatement(tsLastDataQueryReq); - if (ExecuteStatementHandler.validateStatement(statement)) { return FastLastHandler.buildErrorResponse(TSStatusCode.EXECUTE_STATEMENT_ERROR); } - Optional.ofNullable(authorizationHandler.checkAuthority(securityContext, statement)) - .ifPresent(Response.class::cast); - queryId = SESSION_MANAGER.requestQueryId(); SessionInfo sessionInfo = SESSION_MANAGER.getSessionInfo(clientSession); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java index ed754c418c635..875709d6f45c6 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java @@ -1199,7 +1199,20 @@ public TSExecuteStatementResp executeFastLastDataQueryForOnePrefixPath( return executeLastDataQueryInternal(convert(req), SELECT_RESULT); } - // 2.2 all sensors hit cache, return response ~= 20ms + // 2.2 Check permission, the cost is rather low because the req only contains one prefix path + final Statement s = StatementGenerator.createStatement(convert(req)); + final TSStatus status = + AuthorityChecker.checkAuthority( + s, + new TreeAccessCheckContext( + clientSession.getUserId(), + clientSession.getUsername(), + clientSession.getClientAddress())); + if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + return RpcUtils.getTSExecuteStatementResp(status); + } + + // 2.3 all sensors hit cache, return response ~= 20ms final TsBlockBuilder builder = LastQueryUtil.createTsBlockBuilder(sensorNum); for (final Map.Entry>>> @@ -1332,6 +1345,20 @@ public TSExecuteStatementResp executeFastLastDataQueryForOneDeviceV2( .get(0) .mPPDataExchangeEndPoint; + // Place the permission check at first + final Statement s = StatementGenerator.createStatement(convert(req)); + // permission check + final TSStatus status = + AuthorityChecker.checkAuthority( + s, + new TreeAccessCheckContext( + clientSession.getUserId(), + clientSession.getUsername(), + clientSession.getClientAddress())); + if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + return RpcUtils.getTSExecuteStatementResp(status); + } + // the device's dataRegion's leader of the latest time partition is on current node, may can // read directly from cache if (isSameNode(lastRegionLeader)) { @@ -1390,20 +1417,6 @@ public TSExecuteStatementResp executeFastLastDataQueryForOneDeviceV2( } } - // cache miss - Statement s = StatementGenerator.createStatement(convert(req)); - // permission check - TSStatus status = - AuthorityChecker.checkAuthority( - s, - new TreeAccessCheckContext( - clientSession.getUserId(), - clientSession.getUsername(), - clientSession.getClientAddress())); - if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - return RpcUtils.getTSExecuteStatementResp(status); - } - quota = DataNodeThrottleQuotaManager.getInstance() .checkQuota(SESSION_MANAGER.getCurrSession().getUsername(), s); From 0ecbd0143cc2b7904d4b11e92321414ff774763e Mon Sep 17 00:00:00 2001 From: Caideyipi <87789683+Caideyipi@users.noreply.github.com> Date: Mon, 13 Apr 2026 16:33:11 +0800 Subject: [PATCH 02/19] fix --- .../iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java index 08338c8dde49a..e708c9434cd63 100644 --- a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java +++ b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java @@ -123,7 +123,6 @@ public Response executeFastLastQueryStatement( new PartialPath(prefixPathList.getPrefixPaths().toArray(new String[0])); final Map>>> resultMap = new HashMap<>(); - int sensorNum = 0; final String prefixString = prefixPath.toString(); for (final ISchemaRegion region : SchemaEngine.getInstance().getAllSchemaRegions()) { @@ -131,9 +130,10 @@ public Response executeFastLastQueryStatement( && !region.getDatabaseFullPath().startsWith(prefixString)) { continue; } - sensorNum += region.fillLastQueryMap(prefixPath, resultMap); + region.fillLastQueryMap(prefixPath, resultMap); } + // Check permission, the cost is rather low because the req only contains one prefix path final IClientSession clientSession = SESSION_MANAGER.getCurrSession(); final TSLastDataQueryReq tsLastDataQueryReq = FastLastHandler.createTSLastDataQueryReq(clientSession, prefixPathList); From 5c10f846b3b92a119813a988aa08b53e295d8b30 Mon Sep 17 00:00:00 2001 From: Caideyipi <87789683+Caideyipi@users.noreply.github.com> Date: Mon, 13 Apr 2026 16:35:16 +0800 Subject: [PATCH 03/19] fix --- .../iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java index 875709d6f45c6..f5ed068fbd0b5 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java @@ -1345,7 +1345,7 @@ public TSExecuteStatementResp executeFastLastDataQueryForOneDeviceV2( .get(0) .mPPDataExchangeEndPoint; - // Place the permission check at first + // Place the permission check first final Statement s = StatementGenerator.createStatement(convert(req)); // permission check final TSStatus status = From 532280ab7f257cebd39d349bb5300c09e96e5dbb Mon Sep 17 00:00:00 2001 From: Caideyipi <87789683+Caideyipi@users.noreply.github.com> Date: Mon, 13 Apr 2026 16:37:13 +0800 Subject: [PATCH 04/19] fix --- .../thrift/impl/ClientRPCServiceImpl.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java index f5ed068fbd0b5..9b248aed98de1 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java @@ -1299,6 +1299,20 @@ public TSExecuteStatementResp executeFastLastDataQueryForOneDeviceV2( long startTime = System.nanoTime(); Throwable t = null; try { + // Place the permission check first + final Statement s = StatementGenerator.createStatement(convert(req)); + // permission check + final TSStatus status = + AuthorityChecker.checkAuthority( + s, + new TreeAccessCheckContext( + clientSession.getUserId(), + clientSession.getUsername(), + clientSession.getClientAddress())); + if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + return RpcUtils.getTSExecuteStatementResp(status); + } + String db; String device; PartialPath devicePath; @@ -1345,20 +1359,6 @@ public TSExecuteStatementResp executeFastLastDataQueryForOneDeviceV2( .get(0) .mPPDataExchangeEndPoint; - // Place the permission check first - final Statement s = StatementGenerator.createStatement(convert(req)); - // permission check - final TSStatus status = - AuthorityChecker.checkAuthority( - s, - new TreeAccessCheckContext( - clientSession.getUserId(), - clientSession.getUsername(), - clientSession.getClientAddress())); - if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - return RpcUtils.getTSExecuteStatementResp(status); - } - // the device's dataRegion's leader of the latest time partition is on current node, may can // read directly from cache if (isSameNode(lastRegionLeader)) { From 0b0f4c86b0dae25455aa38dc743faab8645142e4 Mon Sep 17 00:00:00 2001 From: Caideyipi <87789683+Caideyipi@users.noreply.github.com> Date: Mon, 13 Apr 2026 17:48:04 +0800 Subject: [PATCH 05/19] IT1 --- .../java/org/apache/iotdb/it/env/EnvType.java | 2 +- .../iotdb/session/it/IoTDBSessionQueryIT.java | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/EnvType.java b/integration-test/src/main/java/org/apache/iotdb/it/env/EnvType.java index 7c2ee415cf1b4..fd2a7417d1d77 100644 --- a/integration-test/src/main/java/org/apache/iotdb/it/env/EnvType.java +++ b/integration-test/src/main/java/org/apache/iotdb/it/env/EnvType.java @@ -29,7 +29,7 @@ public enum EnvType { TABLE_CLUSTER1; public static EnvType getSystemEnvType() { - String envValue = System.getProperty("TestEnv", Simple.name()); + String envValue = System.getProperty("TestEnv", Remote.name()); return EnvType.valueOf(envValue); } } diff --git a/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java index 8bd6833ec089d..5e9524de964c0 100644 --- a/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java @@ -22,6 +22,7 @@ import org.apache.iotdb.common.rpc.thrift.TAggregationType; import org.apache.iotdb.commons.conf.IoTDBConstant; import org.apache.iotdb.db.it.utils.AlignedWriteUtil; +import org.apache.iotdb.db.it.utils.TestUtils; import org.apache.iotdb.isession.ISession; import org.apache.iotdb.isession.SessionDataSet; import org.apache.iotdb.it.env.EnvFactory; @@ -29,6 +30,7 @@ import org.apache.iotdb.itbase.category.ClusterIT; import org.apache.iotdb.itbase.category.LocalStandaloneIT; import org.apache.iotdb.rpc.IoTDBConnectionException; +import org.apache.iotdb.rpc.RedirectException; import org.apache.iotdb.rpc.StatementExecutionException; import org.junit.AfterClass; @@ -249,6 +251,32 @@ public void lastQueryForOneDeviceNoSchema() throws IoTDBConnectionException { } } + @Test + public void lastQueryWithoutPermissionTest() throws IoTDBConnectionException { + final String[] retArray = new String[] {}; + TestUtils.executeNonQuery(EnvFactory.getEnv(), "create user abcd 'veryComplexPassword@123'"); + + try (final ISession session = + EnvFactory.getEnv().getSessionConnection("abcd", "veryComplexPassword@123")) { + try (final SessionDataSet resultSet = + session.executeLastDataQueryForOneDevice( + "root.sg1", "root.sg1.d1", Arrays.asList("notExist", "s1"), true)) { + assertResultSetEqual(resultSet, lastQueryColumnNames, retArray, true); + } + + try (final SessionDataSet resultSet = + session.executeFastLastDataQueryForOnePrefixPath(Arrays.asList("root", "sg1", "d1"))) { + assertResultSetEqual(resultSet, lastQueryColumnNames, retArray, true); + } + } catch (StatementExecutionException | RedirectException e) { + e.printStackTrace(); + fail(e.getMessage()); + } finally { + TestUtils.executeNonQueries( + EnvFactory.getEnv(), Arrays.asList("drop database root.sg1", "drop user abcd")); + } + } + // ------------------------------ Aggregation Query ------------------------------ @Test public void aggregationQueryTest() { From 6deaad0fc5eaa6b289286007a421c797dd02c738 Mon Sep 17 00:00:00 2001 From: Caideyipi <87789683+Caideyipi@users.noreply.github.com> Date: Mon, 13 Apr 2026 18:09:18 +0800 Subject: [PATCH 06/19] change --- .../java/org/apache/iotdb/it/env/EnvType.java | 2 +- .../iotdb/db/it/IoTDBRestServiceIT.java | 103 ++++++++++++++++++ .../iotdb/session/it/IoTDBSessionQueryIT.java | 6 + 3 files changed, 110 insertions(+), 1 deletion(-) diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/EnvType.java b/integration-test/src/main/java/org/apache/iotdb/it/env/EnvType.java index fd2a7417d1d77..7c2ee415cf1b4 100644 --- a/integration-test/src/main/java/org/apache/iotdb/it/env/EnvType.java +++ b/integration-test/src/main/java/org/apache/iotdb/it/env/EnvType.java @@ -29,7 +29,7 @@ public enum EnvType { TABLE_CLUSTER1; public static EnvType getSystemEnvType() { - String envValue = System.getProperty("TestEnv", Remote.name()); + String envValue = System.getProperty("TestEnv", Simple.name()); return EnvType.valueOf(envValue); } } diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java index 76a246149cd94..599e5ec755899 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java @@ -476,6 +476,7 @@ public void insertAndQuery() { selectLast(httpClient); queryV2(httpClient); + selectFastLast(httpClient); queryGroupByLevelV2(httpClient); queryRowLimitV2(httpClient); queryShowChildPathsV2(httpClient); @@ -1651,6 +1652,108 @@ public void queryV2(CloseableHttpClient httpClient) { } } + public void selectFastLast(CloseableHttpClient httpClient) { + CloseableHttpResponse response = null; + try { + HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/fastLastQuery"); + String sql = "{\"PrefixPathList\":[[\"root\",\"sg25\"]]}"; + httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); + response = httpClient.execute(httpPost); + HttpEntity responseEntity = response.getEntity(); + String message = EntityUtils.toString(responseEntity, "utf-8"); + ObjectMapper mapper = new ObjectMapper(); + Map map = mapper.readValue(message, Map.class); + List timestampsResult = (List) map.get("timestamps"); + List expressionsResult = (List) map.get("expressions"); + List> valuesResult = (List>) map.get("values"); + Assert.assertTrue(map.size() > 0); + List expressions = + new ArrayList() { + { + add("root.sg25.s3"); + add("root.sg25.s4"); + add("root.sg25.s5"); + add("root.sg25.s6"); + add("root.sg25.s7"); + add("root.sg25.s8"); + add("root.sg25.s4 + 1"); + add("root.sg25.s4 + 1"); + } + }; + List timestamps = + new ArrayList() { + { + add(1635232143960l); + add(1635232153960l); + } + }; + List values1 = + new ArrayList() { + { + add("2aa"); + add(""); + } + }; + List values2 = + new ArrayList() { + { + add(11); + add(2); + } + }; + List values3 = + new ArrayList() { + { + add(1635000012345555l); + add(1635000012345556l); + } + }; + + List values4 = + new ArrayList() { + { + add(1.41); + add(null); + } + }; + List values5 = + new ArrayList() { + { + add(null); + add(false); + } + }; + List values6 = + new ArrayList() { + { + add(null); + add(3.5555); + } + }; + + Assert.assertEquals(expressions, expressionsResult); + Assert.assertEquals(timestamps, timestampsResult); + Assert.assertEquals(values1, valuesResult.get(0)); + Assert.assertEquals(values2, valuesResult.get(1)); + Assert.assertEquals(values3, valuesResult.get(2)); + Assert.assertEquals(values4, valuesResult.get(3)); + Assert.assertEquals(values5, valuesResult.get(4)); + Assert.assertEquals(values6, valuesResult.get(5)); + } catch (IOException e) { + e.printStackTrace(); + fail(e.getMessage()); + } finally { + try { + if (response != null) { + response.close(); + } + } catch (IOException e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + } + public void queryGroupByLevelV2(CloseableHttpClient httpClient) { CloseableHttpResponse response = null; try { diff --git a/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java index 5e9524de964c0..9bc160e77392e 100644 --- a/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java @@ -258,6 +258,12 @@ public void lastQueryWithoutPermissionTest() throws IoTDBConnectionException { try (final ISession session = EnvFactory.getEnv().getSessionConnection("abcd", "veryComplexPassword@123")) { + // Push last cache first + try (final SessionDataSet resultSet = + session.executeFastLastDataQueryForOnePrefixPath(Arrays.asList("root", "sg1", "d1"))) { + assertResultSetEqual(resultSet, lastQueryColumnNames, retArray, true); + } + try (final SessionDataSet resultSet = session.executeLastDataQueryForOneDevice( "root.sg1", "root.sg1.d1", Arrays.asList("notExist", "s1"), true)) { From e6eecae1752cabaff8b3e0395cc36b06c31004dc Mon Sep 17 00:00:00 2001 From: Caideyipi <87789683+Caideyipi@users.noreply.github.com> Date: Mon, 13 Apr 2026 18:26:33 +0800 Subject: [PATCH 07/19] right-1 --- .../iotdb/db/it/IoTDBRestServiceIT.java | 110 ++++++++---------- 1 file changed, 48 insertions(+), 62 deletions(-) diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java index 599e5ec755899..f6e0393effc49 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java @@ -1656,7 +1656,7 @@ public void selectFastLast(CloseableHttpClient httpClient) { CloseableHttpResponse response = null; try { HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/fastLastQuery"); - String sql = "{\"PrefixPathList\":[[\"root\",\"sg25\"]]}"; + String sql = "{\"prefix_paths\":[\"root\",\"sg25\"]}"; httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); response = httpClient.execute(httpPost); HttpEntity responseEntity = response.getEntity(); @@ -1668,77 +1668,63 @@ public void selectFastLast(CloseableHttpClient httpClient) { List> valuesResult = (List>) map.get("values"); Assert.assertTrue(map.size() > 0); List expressions = - new ArrayList() { - { - add("root.sg25.s3"); - add("root.sg25.s4"); - add("root.sg25.s5"); - add("root.sg25.s6"); - add("root.sg25.s7"); - add("root.sg25.s8"); - add("root.sg25.s4 + 1"); - add("root.sg25.s4 + 1"); - } - }; + new ArrayList() { + { + add("Timeseries"); + add("Value"); + add("DataType"); + } + }; List timestamps = - new ArrayList() { - { - add(1635232143960l); - add(1635232153960l); - } - }; + new ArrayList() { + { + add(1635232153960l); + add(1635232153960l); + add(1635232153960l); + add(1635232143960l); + add(1635232153960l); + add(1635232153960l); + } + }; List values1 = - new ArrayList() { - { - add("2aa"); - add(""); - } - }; + new ArrayList() { + { + add("root.sg25.s3"); + add("root.sg25.s4"); + add("root.sg25.s5"); + add("root.sg25.s6"); + add("root.sg25.s7"); + add("root.sg25.s8"); + } + }; List values2 = - new ArrayList() { - { - add(11); - add(2); - } - }; + new ArrayList() { + { + add(""); + add("2"); + add("1635000012345556"); + add("1.41"); + add("false"); + add("3.5555"); + } + }; List values3 = - new ArrayList() { - { - add(1635000012345555l); - add(1635000012345556l); - } - }; - - List values4 = - new ArrayList() { - { - add(1.41); - add(null); - } - }; - List values5 = - new ArrayList() { - { - add(null); - add(false); - } - }; - List values6 = - new ArrayList() { - { - add(null); - add(3.5555); - } - }; + new ArrayList() { + { + add("TEXT"); + add("INT32"); + add("INT64"); + add("FLOAT"); + add("BOOLEAN"); + add("DOUBLE"); + } + }; Assert.assertEquals(expressions, expressionsResult); Assert.assertEquals(timestamps, timestampsResult); Assert.assertEquals(values1, valuesResult.get(0)); Assert.assertEquals(values2, valuesResult.get(1)); Assert.assertEquals(values3, valuesResult.get(2)); - Assert.assertEquals(values4, valuesResult.get(3)); - Assert.assertEquals(values5, valuesResult.get(4)); - Assert.assertEquals(values6, valuesResult.get(5)); } catch (IOException e) { e.printStackTrace(); fail(e.getMessage()); From 10cd6e6a70c6175becd5865febeeb72e66d7ebb2 Mon Sep 17 00:00:00 2001 From: Caideyipi <87789683+Caideyipi@users.noreply.github.com> Date: Mon, 13 Apr 2026 18:36:18 +0800 Subject: [PATCH 08/19] fixation --- .../iotdb/session/it/IoTDBSessionQueryIT.java | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java index 9bc160e77392e..cb45a7444acdd 100644 --- a/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java @@ -251,6 +251,34 @@ public void lastQueryForOneDeviceNoSchema() throws IoTDBConnectionException { } } + @Test + public void lastQueryWithPrefixTest() throws IoTDBConnectionException { + final String[] retArray = + new String[] { + "30,root.sg1.d1.s3,30,INT64", + "30,root.sg1.d1.s4,false,BOOLEAN", + "40,root.sg1.d1.s5,aligned_test40,TEXT", + "23,root.sg1.d1.s1,230000.0,FLOAT", + "40,root.sg1.d1.s2,40,INT32" + }; + + try (final ISession session = EnvFactory.getEnv().getSessionConnection()) { + // Push last cache first + try (final SessionDataSet resultSet = + session.executeFastLastDataQueryForOnePrefixPath(Arrays.asList("root", "sg1", "d1"))) { + assertResultSetEqual(resultSet, lastQueryColumnNames, retArray, true); + } + + try (final SessionDataSet resultSet = + session.executeFastLastDataQueryForOnePrefixPath(Arrays.asList("root", "sg1", "d1"))) { + assertResultSetEqual(resultSet, lastQueryColumnNames, retArray, true); + } + } catch (StatementExecutionException | RedirectException e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + @Test public void lastQueryWithoutPermissionTest() throws IoTDBConnectionException { final String[] retArray = new String[] {}; @@ -277,9 +305,6 @@ public void lastQueryWithoutPermissionTest() throws IoTDBConnectionException { } catch (StatementExecutionException | RedirectException e) { e.printStackTrace(); fail(e.getMessage()); - } finally { - TestUtils.executeNonQueries( - EnvFactory.getEnv(), Arrays.asList("drop database root.sg1", "drop user abcd")); } } From 25ce4109cc9b4ffb077cbb75ebcaf7d93b31c4b9 Mon Sep 17 00:00:00 2001 From: Caideyipi <87789683+Caideyipi@users.noreply.github.com> Date: Mon, 13 Apr 2026 18:49:29 +0800 Subject: [PATCH 09/19] fix --- .../iotdb/db/it/IoTDBRestServiceIT.java | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java index f6e0393effc49..caec922a1cb59 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java @@ -19,6 +19,7 @@ package org.apache.iotdb.db.it; import org.apache.iotdb.commons.schema.column.ColumnHeaderConstant; +import org.apache.iotdb.db.it.utils.TestUtils; import org.apache.iotdb.it.env.EnvFactory; import org.apache.iotdb.it.env.cluster.node.DataNodeWrapper; import org.apache.iotdb.it.framework.IoTDBTestRunner; @@ -54,6 +55,7 @@ import java.sql.Statement; import java.util.ArrayList; import java.util.Base64; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -887,6 +889,71 @@ public void queryWithWrongAuthorization() { } } + @Test + public void queryFastLastWithWrongAuthorization() { + CloseableHttpResponse response = null; + + TestUtils.executeNonQuery("create user abcd 'strongPassword@1234'"); + try { + final CloseableHttpClient httpClient = HttpClientBuilder.create().build(); + final HttpPost httpPost = new HttpPost("http://127.0.0.1:" + port + "/rest/v2/fastLastQuery"); + httpPost.addHeader("Content-type", "application/json; charset=utf-8"); + httpPost.setHeader("Accept", "application/json"); + final String authorization = getAuthorization("abcd", "strongPassword@1234"); + httpPost.setHeader("Authorization", authorization); + final String sql = "{\"prefix_paths\":[\"root\",\"sg25\"]}"; + httpPost.setEntity(new StringEntity(sql, Charset.defaultCharset())); + for (int i = 0; i < 30; i++) { + try { + response = httpClient.execute(httpPost); + break; + } catch (Exception e) { + if (i == 29) { + throw e; + } + try { + Thread.sleep(1000); + } catch (InterruptedException ex) { + throw new RuntimeException(ex); + } + } + } + + Assert.assertEquals(200, response.getStatusLine().getStatusCode()); + String message = EntityUtils.toString(response.getEntity(), "utf-8"); + ObjectMapper mapper = new ObjectMapper(); + Map map = mapper.readValue(message, Map.class); + List timestampsResult = (List) map.get("timestamps"); + List expressionsResult = (List) map.get("expressions"); + List> valuesResult = (List>) map.get("values"); + Assert.assertTrue(map.size() > 0); + List expressions = + new ArrayList() { + { + add("Timeseries"); + add("Value"); + add("DataType"); + } + }; + + Assert.assertEquals(expressions, expressionsResult); + Assert.assertEquals(Collections.emptyList(), timestampsResult); + Assert.assertEquals(Collections.emptyList(), valuesResult); + } catch (IOException e) { + e.printStackTrace(); + fail(e.getMessage()); + } finally { + try { + if (response != null) { + response.close(); + } + } catch (IOException e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } + } + public void query(CloseableHttpClient httpClient) { CloseableHttpResponse response = null; try { From 87a61b61ce44e8c83f7803b633c06640e48bb96e Mon Sep 17 00:00:00 2001 From: Caideyipi <87789683+Caideyipi@users.noreply.github.com> Date: Tue, 14 Apr 2026 10:28:52 +0800 Subject: [PATCH 10/19] partial --- .../apache/iotdb/db/it/utils/TestUtils.java | 7 +++---- .../iotdb/session/it/IoTDBSessionQueryIT.java | 18 +++++++++--------- .../table/RenameTableColumnProcedure.java | 4 +++- .../table/SetTablePropertiesProcedure.java | 4 +++- 4 files changed, 18 insertions(+), 15 deletions(-) diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java b/integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java index 43a11647c3740..e2427b98b9a8e 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java @@ -1451,7 +1451,7 @@ public static void assertResultSetEqual( public static void assertResultSetEqual( SessionDataSet actualResultSet, List expectedColumnNames, - Set expectedRetArray, + Set expectedRetSet, boolean ignoreTimeStamp) { try { List actualColumnNames = actualResultSet.getColumnNames(); @@ -1462,12 +1462,11 @@ public static void assertResultSetEqual( assertEquals(expectedColumnNames, actualColumnNames.subList(1, actualColumnNames.size())); } - int count = 0; while (actualResultSet.hasNext()) { RowRecord rowRecord = actualResultSet.next(); - assertTrue(expectedRetArray.remove(rowRecord.toString().replace('\t', ','))); + assertTrue(expectedRetSet.remove(rowRecord.toString().replace('\t', ','))); } - assertEquals(expectedRetArray.size(), count); + assertEquals(0, expectedRetSet.size()); } catch (IoTDBConnectionException | StatementExecutionException e) { e.printStackTrace(); fail(e.getMessage()); diff --git a/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java index cb45a7444acdd..3d008031fa234 100644 --- a/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java @@ -56,7 +56,7 @@ public class IoTDBSessionQueryIT { @BeforeClass public static void setUp() throws Exception { System.setProperty(IoTDBConstant.IOTDB_CONF, "src/test/resources/"); - EnvFactory.getEnv().initClusterEnvironment(); + EnvFactory.getEnv().initClusterEnvironment(1, 3); AlignedWriteUtil.insertDataWithSession(); } @@ -253,14 +253,14 @@ public void lastQueryForOneDeviceNoSchema() throws IoTDBConnectionException { @Test public void lastQueryWithPrefixTest() throws IoTDBConnectionException { - final String[] retArray = - new String[] { - "30,root.sg1.d1.s3,30,INT64", - "30,root.sg1.d1.s4,false,BOOLEAN", - "40,root.sg1.d1.s5,aligned_test40,TEXT", - "23,root.sg1.d1.s1,230000.0,FLOAT", - "40,root.sg1.d1.s2,40,INT32" - }; + final Set retArray = + new HashSet<>( + Arrays.asList( + "30,root.sg1.d1.s3,30,INT64", + "30,root.sg1.d1.s4,false,BOOLEAN", + "40,root.sg1.d1.s5,aligned_test40,TEXT", + "23,root.sg1.d1.s1,230000.0,FLOAT", + "40,root.sg1.d1.s2,40,INT32")); try (final ISession session = EnvFactory.getEnv().getSessionConnection()) { // Push last cache first diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/RenameTableColumnProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/RenameTableColumnProcedure.java index da51dad267266..a2a6c72577cf9 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/RenameTableColumnProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/RenameTableColumnProcedure.java @@ -180,7 +180,9 @@ private void rollbackRenameColumn(final ConfigNodeProcedureEnv env) { env.getConfigManager() .getClusterSchemaManager() .executePlan( - new RenameTableColumnPlan(database, tableName, newName, oldName), + this instanceof RenameViewColumnProcedure + ? new RenameViewColumnPlan(database, tableName, newName, oldName) + : new RenameTableColumnPlan(database, tableName, newName, oldName), isGeneratedByPipe); if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { setFailure(new ProcedureException(new IoTDBException(status))); diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/SetTablePropertiesProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/SetTablePropertiesProcedure.java index eedbf7fdb3d0a..138ae9c9b50ea 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/SetTablePropertiesProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/SetTablePropertiesProcedure.java @@ -203,7 +203,9 @@ private void rollbackSetProperties(final ConfigNodeProcedureEnv env) { env.getConfigManager() .getClusterSchemaManager() .executePlan( - new SetTablePropertiesPlan(database, tableName, originalProperties), + this instanceof SetViewPropertiesProcedure + ? new SetViewPropertiesPlan(database, tableName, originalProperties) + : new SetTablePropertiesPlan(database, tableName, originalProperties), isGeneratedByPipe); if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { setFailure(new ProcedureException(new IoTDBException(status))); From 5b2acdca4ae4a1ba4e3a6692feac8d92adbd9ee4 Mon Sep 17 00:00:00 2001 From: Caideyipi <87789683+Caideyipi@users.noreply.github.com> Date: Tue, 14 Apr 2026 10:29:05 +0800 Subject: [PATCH 11/19] 13 --- .../java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java index 3d008031fa234..913142632c383 100644 --- a/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java @@ -56,7 +56,7 @@ public class IoTDBSessionQueryIT { @BeforeClass public static void setUp() throws Exception { System.setProperty(IoTDBConstant.IOTDB_CONF, "src/test/resources/"); - EnvFactory.getEnv().initClusterEnvironment(1, 3); + EnvFactory.getEnv().initClusterEnvironment(); AlignedWriteUtil.insertDataWithSession(); } From 27cbb3116247d6ce7d4f069bffd856498dd5ca79 Mon Sep 17 00:00:00 2001 From: Caideyipi <87789683+Caideyipi@users.noreply.github.com> Date: Tue, 14 Apr 2026 10:41:04 +0800 Subject: [PATCH 12/19] limit --- .../test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java | 4 ++++ .../java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java index caec922a1cb59..eb2573c7f8441 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRestServiceIT.java @@ -1720,6 +1720,10 @@ public void queryV2(CloseableHttpClient httpClient) { } public void selectFastLast(CloseableHttpClient httpClient) { + // Only used in 1D scenarios + if (EnvFactory.getEnv().getDataNodeWrapperList().size() > 1) { + return; + } CloseableHttpResponse response = null; try { HttpPost httpPost = getHttpPost("http://127.0.0.1:" + port + "/rest/v2/fastLastQuery"); diff --git a/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java index 913142632c383..326957d8ad2a6 100644 --- a/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java @@ -253,6 +253,10 @@ public void lastQueryForOneDeviceNoSchema() throws IoTDBConnectionException { @Test public void lastQueryWithPrefixTest() throws IoTDBConnectionException { + // Only used in 1D scenarios + if (EnvFactory.getEnv().getDataNodeWrapperList().size() > 1) { + return; + } final Set retArray = new HashSet<>( Arrays.asList( From efc50a4cc44bd0d1657ddf3056a951aaff1f3e97 Mon Sep 17 00:00:00 2001 From: Caideyipi <87789683+Caideyipi@users.noreply.github.com> Date: Tue, 14 Apr 2026 14:13:37 +0800 Subject: [PATCH 13/19] fix --- .../test/java/org/apache/iotdb/db/it/utils/TestUtils.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java b/integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java index e2427b98b9a8e..9c2a09024c4d9 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java @@ -1453,6 +1453,7 @@ public static void assertResultSetEqual( List expectedColumnNames, Set expectedRetSet, boolean ignoreTimeStamp) { + final Set copiedSet = new HashSet<>(expectedRetSet); try { List actualColumnNames = actualResultSet.getColumnNames(); if (ignoreTimeStamp) { @@ -1464,9 +1465,9 @@ public static void assertResultSetEqual( while (actualResultSet.hasNext()) { RowRecord rowRecord = actualResultSet.next(); - assertTrue(expectedRetSet.remove(rowRecord.toString().replace('\t', ','))); + assertTrue(copiedSet.remove(rowRecord.toString().replace('\t', ','))); } - assertEquals(0, expectedRetSet.size()); + assertEquals(0, copiedSet.size()); } catch (IoTDBConnectionException | StatementExecutionException e) { e.printStackTrace(); fail(e.getMessage()); From 9a134c8afd8c5e71e3b932caee3dce8ed71a4030 Mon Sep 17 00:00:00 2001 From: Caideyipi <87789683+Caideyipi@users.noreply.github.com> Date: Tue, 14 Apr 2026 15:16:12 +0800 Subject: [PATCH 14/19] fix --- .../procedure/impl/schema/table/DropTableProcedure.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/DropTableProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/DropTableProcedure.java index 1f02014e9943b..36eb16dc164d8 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/DropTableProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/DropTableProcedure.java @@ -154,6 +154,10 @@ private void invalidateCache(final ConfigNodeProcedureEnv env) { } private void deleteData(final ConfigNodeProcedureEnv env) { + if (this instanceof DropViewProcedure) { + setNextState(DropTableState.DROP_TABLE); + return; + } final Map relatedDataRegionGroup = env.getConfigManager().getRelatedDataRegionGroup4TableModel(database); From 4a7f7faf8e2735eeea31424d5515a9e6e85a9048 Mon Sep 17 00:00:00 2001 From: Caideyipi <87789683+Caideyipi@users.noreply.github.com> Date: Tue, 14 Apr 2026 15:17:30 +0800 Subject: [PATCH 15/19] mod --- .../procedure/impl/schema/table/DropTableColumnProcedure.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/DropTableColumnProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/DropTableColumnProcedure.java index 66e1789e9ba72..516d657e2674a 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/DropTableColumnProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/DropTableColumnProcedure.java @@ -183,6 +183,10 @@ private void invalidateCache(final ConfigNodeProcedureEnv env) { } private void executeOnRegions(final ConfigNodeProcedureEnv env) { + if (this instanceof DropViewColumnProcedure) { + setNextState(DropTableColumnState.DROP_COLUMN); + return; + } final Map relatedRegionGroup = isAttributeColumn ? env.getConfigManager().getRelatedSchemaRegionGroup4TableModel(database) From ebcfc4ffe2af10ee40fdc5f1b37781639fb170d5 Mon Sep 17 00:00:00 2001 From: Caideyipi <87789683+Caideyipi@users.noreply.github.com> Date: Tue, 14 Apr 2026 18:24:49 +0800 Subject: [PATCH 16/19] remove-usls --- .../procedure/impl/schema/table/DropTableColumnProcedure.java | 4 ---- .../procedure/impl/schema/table/DropTableProcedure.java | 4 ---- 2 files changed, 8 deletions(-) diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/DropTableColumnProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/DropTableColumnProcedure.java index 516d657e2674a..66e1789e9ba72 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/DropTableColumnProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/DropTableColumnProcedure.java @@ -183,10 +183,6 @@ private void invalidateCache(final ConfigNodeProcedureEnv env) { } private void executeOnRegions(final ConfigNodeProcedureEnv env) { - if (this instanceof DropViewColumnProcedure) { - setNextState(DropTableColumnState.DROP_COLUMN); - return; - } final Map relatedRegionGroup = isAttributeColumn ? env.getConfigManager().getRelatedSchemaRegionGroup4TableModel(database) diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/DropTableProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/DropTableProcedure.java index 36eb16dc164d8..1f02014e9943b 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/DropTableProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/DropTableProcedure.java @@ -154,10 +154,6 @@ private void invalidateCache(final ConfigNodeProcedureEnv env) { } private void deleteData(final ConfigNodeProcedureEnv env) { - if (this instanceof DropViewProcedure) { - setNextState(DropTableState.DROP_TABLE); - return; - } final Map relatedDataRegionGroup = env.getConfigManager().getRelatedDataRegionGroup4TableModel(database); From 4d651e4b01cead819c3304760ec3ac1eb0a3f07e Mon Sep 17 00:00:00 2001 From: Caideyipi <87789683+Caideyipi@users.noreply.github.com> Date: Wed, 15 Apr 2026 10:29:25 +0800 Subject: [PATCH 17/19] fix --- .../protocol/v2/impl/RestApiServiceImpl.java | 21 ++++++------ .../iotdb/session/it/IoTDBSessionQueryIT.java | 20 +++++++++-- .../thrift/impl/ClientRPCServiceImpl.java | 33 ++++++++++--------- .../plan/parser/StatementGenerator.java | 2 +- .../schemaregion/ISchemaRegion.java | 3 +- .../impl/SchemaRegionMemoryImpl.java | 5 +-- .../impl/SchemaRegionPBTreeImpl.java | 5 +-- .../impl/mem/MTreeBelowSGMemoryImpl.java | 6 ++-- 8 files changed, 57 insertions(+), 38 deletions(-) diff --git a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java index e708c9434cd63..e05929c6a639b 100644 --- a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java +++ b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java @@ -40,6 +40,7 @@ import org.apache.iotdb.db.queryengine.plan.statement.StatementType; import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowsStatement; import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertTabletStatement; +import org.apache.iotdb.db.queryengine.plan.statement.crud.QueryStatement; import org.apache.iotdb.db.schemaengine.SchemaEngine; import org.apache.iotdb.db.schemaengine.schemaregion.ISchemaRegion; import org.apache.iotdb.db.utils.CommonUtils; @@ -111,7 +112,7 @@ public RestApiServiceImpl() { public Response executeFastLastQueryStatement( PrefixPathList prefixPathList, SecurityContext securityContext) { Long queryId = null; - Statement statement = null; + QueryStatement statement = null; boolean finish = false; long startTime = System.nanoTime(); Throwable t = null; @@ -124,15 +125,6 @@ public Response executeFastLastQueryStatement( final Map>>> resultMap = new HashMap<>(); - final String prefixString = prefixPath.toString(); - for (final ISchemaRegion region : SchemaEngine.getInstance().getAllSchemaRegions()) { - if (!prefixString.startsWith(region.getDatabaseFullPath()) - && !region.getDatabaseFullPath().startsWith(prefixString)) { - continue; - } - region.fillLastQueryMap(prefixPath, resultMap); - } - // Check permission, the cost is rather low because the req only contains one prefix path final IClientSession clientSession = SESSION_MANAGER.getCurrSession(); final TSLastDataQueryReq tsLastDataQueryReq = @@ -144,6 +136,15 @@ public Response executeFastLastQueryStatement( return response; } + final String prefixString = prefixPath.toString(); + for (final ISchemaRegion region : SchemaEngine.getInstance().getAllSchemaRegions()) { + if (!prefixString.startsWith(region.getDatabaseFullPath()) + && !region.getDatabaseFullPath().startsWith(prefixString)) { + continue; + } + region.fillLastQueryMap(prefixPath, resultMap, statement.getAuthorityScope()); + } + // Check cache first if (!TableDeviceSchemaCache.getInstance().getLastCache(resultMap)) { if (ExecuteStatementHandler.validateStatement(statement)) { diff --git a/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java index 326957d8ad2a6..f65f2b4496fdd 100644 --- a/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/session/it/IoTDBSessionQueryIT.java @@ -285,15 +285,29 @@ public void lastQueryWithPrefixTest() throws IoTDBConnectionException { @Test public void lastQueryWithoutPermissionTest() throws IoTDBConnectionException { + // Only used in 1D scenarios + if (EnvFactory.getEnv().getDataNodeWrapperList().size() > 1) { + return; + } final String[] retArray = new String[] {}; + final Set retArray2 = + new HashSet<>( + Arrays.asList( + "30,root.sg1.d1.s3,30,INT64", + "30,root.sg1.d1.s4,false,BOOLEAN", + "40,root.sg1.d1.s5,aligned_test40,TEXT", + "23,root.sg1.d1.s1,230000.0,FLOAT", + "40,root.sg1.d1.s2,40,INT32")); TestUtils.executeNonQuery(EnvFactory.getEnv(), "create user abcd 'veryComplexPassword@123'"); try (final ISession session = - EnvFactory.getEnv().getSessionConnection("abcd", "veryComplexPassword@123")) { + EnvFactory.getEnv().getSessionConnection("abcd", "veryComplexPassword@123"); + final ISession rootSession = EnvFactory.getEnv().getSessionConnection()) { // Push last cache first try (final SessionDataSet resultSet = - session.executeFastLastDataQueryForOnePrefixPath(Arrays.asList("root", "sg1", "d1"))) { - assertResultSetEqual(resultSet, lastQueryColumnNames, retArray, true); + rootSession.executeFastLastDataQueryForOnePrefixPath( + Arrays.asList("root", "sg1", "d1"))) { + assertResultSetEqual(resultSet, lastQueryColumnNames, retArray2, true); } try (final SessionDataSet resultSet = diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java index 9b248aed98de1..79c9795c7064d 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java @@ -113,6 +113,7 @@ import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowsOfOneDeviceStatement; import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowsStatement; import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertTabletStatement; +import org.apache.iotdb.db.queryengine.plan.statement.crud.QueryStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.CreateAlignedTimeSeriesStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.CreateMultiTimeSeriesStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.CreateTimeSeriesStatement; @@ -1170,7 +1171,7 @@ public TSExecuteStatementResp executeFastLastDataQueryForOnePrefixPath( try { final long queryId = SESSION_MANAGER.requestQueryId(clientSession, req.statementId); - // 1. Map ISchemaFetcher.getAllSensors(prefix) ~= 50ms + // 1.1 Map ISchemaFetcher.getAllSensors(prefix) ~= 50ms final PartialPath prefixPath = new PartialPath(req.getPrefixes().toArray(new String[0])); if (prefixPath.hasWildcard()) { @@ -1184,13 +1185,26 @@ public TSExecuteStatementResp executeFastLastDataQueryForOnePrefixPath( new HashMap<>(); int sensorNum = 0; + // 1.2 Check permission, the cost is rather low because the req only contains one prefix path + final QueryStatement s = StatementGenerator.createStatement(convert(req)); + final TSStatus status = + AuthorityChecker.checkAuthority( + s, + new TreeAccessCheckContext( + clientSession.getUserId(), + clientSession.getUsername(), + clientSession.getClientAddress())); + if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + return RpcUtils.getTSExecuteStatementResp(status); + } + final String prefixString = prefixPath.toString(); for (final ISchemaRegion region : SchemaEngine.getInstance().getAllSchemaRegions()) { if (!prefixString.startsWith(region.getDatabaseFullPath()) && !region.getDatabaseFullPath().startsWith(prefixString)) { continue; } - sensorNum += region.fillLastQueryMap(prefixPath, resultMap); + sensorNum += region.fillLastQueryMap(prefixPath, resultMap, s.getAuthorityScope()); } // 2.DATA_NODE_SCHEMA_CACHE.getLastCache() @@ -1199,20 +1213,7 @@ public TSExecuteStatementResp executeFastLastDataQueryForOnePrefixPath( return executeLastDataQueryInternal(convert(req), SELECT_RESULT); } - // 2.2 Check permission, the cost is rather low because the req only contains one prefix path - final Statement s = StatementGenerator.createStatement(convert(req)); - final TSStatus status = - AuthorityChecker.checkAuthority( - s, - new TreeAccessCheckContext( - clientSession.getUserId(), - clientSession.getUsername(), - clientSession.getClientAddress())); - if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - return RpcUtils.getTSExecuteStatementResp(status); - } - - // 2.3 all sensors hit cache, return response ~= 20ms + // 2.2 all sensors hit cache, return response ~= 20ms final TsBlockBuilder builder = LastQueryUtil.createTsBlockBuilder(sensorNum); for (final Map.Entry>>> diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/StatementGenerator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/StatementGenerator.java index 4fc5e50a060af..901196d0e1b08 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/StatementGenerator.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/StatementGenerator.java @@ -176,7 +176,7 @@ public static Statement createStatement(TSRawDataQueryReq rawDataQueryReq) return queryStatement; } - public static Statement createStatement(TSLastDataQueryReq lastDataQueryReq) + public static QueryStatement createStatement(TSLastDataQueryReq lastDataQueryReq) throws IllegalPathException { final long startTime = System.nanoTime(); // construct query statement diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/ISchemaRegion.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/ISchemaRegion.java index 4a11165353cd6..8d87435e108a8 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/ISchemaRegion.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/ISchemaRegion.java @@ -359,7 +359,8 @@ long countPathsUsingTemplate(int templateId, PathPatternTree patternTree) int fillLastQueryMap( final PartialPath pattern, - final Map>>> mapToFill) + final Map>>> mapToFill, + final PathPatternTree scope) throws MetadataException; // endregion diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionMemoryImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionMemoryImpl.java index c5c3b7f57b8cf..2e200cf8e8c55 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionMemoryImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionMemoryImpl.java @@ -1461,9 +1461,10 @@ public void updateSubtreeMeasurementCountForTemplate(final int templateId, final @Override public int fillLastQueryMap( final PartialPath pattern, - final Map>>> mapToFill) + final Map>>> mapToFill, + final PathPatternTree scope) throws MetadataException { - return mTree.fillLastQueryMap(pattern, mapToFill); + return mTree.fillLastQueryMap(pattern, mapToFill, scope); } @Override diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionPBTreeImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionPBTreeImpl.java index 2f4bec896ddf4..19517f9060186 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionPBTreeImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionPBTreeImpl.java @@ -1517,8 +1517,9 @@ public void deleteTableDevicesInBlackList( @Override public int fillLastQueryMap( - PartialPath pattern, - Map>>> mapToFill) { + final PartialPath pattern, + final Map>>> mapToFill, + final PathPatternTree scope) { throw new UnsupportedOperationException("Not implemented"); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java index ed519030b630e..d872a1130a4ee 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java @@ -1299,12 +1299,12 @@ public IDeviceSchemaInfo next() { public int fillLastQueryMap( final PartialPath prefixPath, - final Map>>> mapToFill) + final Map>>> mapToFill, + final PathPatternTree scope) throws MetadataException { final int[] sensorNum = {0}; try (final EntityUpdater updater = - new EntityUpdater( - rootNode, prefixPath, store, true, SchemaConstant.ALL_MATCH_SCOPE) { + new EntityUpdater(rootNode, prefixPath, store, true, scope) { @Override protected void updateEntity(final IDeviceMNode node) { From a1175c2a256eed3cc8d4e9a84512d74519a4cd64 Mon Sep 17 00:00:00 2001 From: Caideyipi <87789683+Caideyipi@users.noreply.github.com> Date: Wed, 15 Apr 2026 10:39:41 +0800 Subject: [PATCH 18/19] fix --- .../thrift/impl/ClientRPCServiceImpl.java | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java index 79c9795c7064d..d8441c56d6a61 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java @@ -42,6 +42,7 @@ import org.apache.iotdb.commons.path.MeasurementPath; import org.apache.iotdb.commons.path.NonAlignedFullPath; import org.apache.iotdb.commons.path.PartialPath; +import org.apache.iotdb.commons.path.PathPatternTree; import org.apache.iotdb.commons.utils.PathUtils; import org.apache.iotdb.db.audit.DNAuditLogger; import org.apache.iotdb.db.auth.AuthorityChecker; @@ -1301,7 +1302,7 @@ public TSExecuteStatementResp executeFastLastDataQueryForOneDeviceV2( Throwable t = null; try { // Place the permission check first - final Statement s = StatementGenerator.createStatement(convert(req)); + final QueryStatement s = StatementGenerator.createStatement(convert(req)); // permission check final TSStatus status = AuthorityChecker.checkAuthority( @@ -1343,7 +1344,7 @@ public TSExecuteStatementResp executeFastLastDataQueryForOneDeviceV2( // no valid DataRegion if (regionReplicaSets.isEmpty() || regionReplicaSets.size() == 1 && NOT_ASSIGNED == regionReplicaSets.get(0)) { - TSExecuteStatementResp resp = + final TSExecuteStatementResp resp = createResponse(DatasetHeaderFactory.getLastQueryHeader(), queryId); resp.setStatus(RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS, "")); resp.setQueryResult(Collections.emptyList()); @@ -1353,7 +1354,7 @@ public TSExecuteStatementResp executeFastLastDataQueryForOneDeviceV2( return resp; } - TEndPoint lastRegionLeader = + final TEndPoint lastRegionLeader = regionReplicaSets .get(regionReplicaSets.size() - 1) .dataNodeLocations @@ -1364,24 +1365,32 @@ public TSExecuteStatementResp executeFastLastDataQueryForOneDeviceV2( // read directly from cache if (isSameNode(lastRegionLeader)) { // the device's all dataRegions' leader are on current node, can use null entry in cache - boolean canUseNullEntry = + final boolean canUseNullEntry = regionReplicaSets.stream() .limit(regionReplicaSets.size() - 1L) .allMatch( regionReplicaSet -> isSameNode( regionReplicaSet.dataNodeLocations.get(0).mPPDataExchangeEndPoint)); - int sensorNum = req.sensors.size(); - TsBlockBuilder builder = LastQueryUtil.createTsBlockBuilder(sensorNum); + final int sensorNum = req.sensors.size(); + final TsBlockBuilder builder = LastQueryUtil.createTsBlockBuilder(sensorNum); boolean allCached = true; - for (String sensor : req.sensors) { - MeasurementPath fullPath; + + PathPatternTree queryTree = new PathPatternTree(); + for (final String sensor : req.sensors) { + final MeasurementPath fullPath; if (req.isLegalPathNodes()) { fullPath = devicePath.concatAsMeasurementPath(sensor); } else { fullPath = devicePath.concatAsMeasurementPath((new PartialPath(sensor)).getFullPath()); } - TimeValuePair timeValuePair = DATA_NODE_SCHEMA_CACHE.getLastCache(fullPath); + queryTree.appendPathPattern(fullPath); + } + queryTree.constructTree(); + queryTree = s.getAuthorityScope().intersectWithFullPathPrefixTree(queryTree); + + for (final MeasurementPath fullPath : queryTree.getAllPathPatterns(true)) { + final TimeValuePair timeValuePair = DATA_NODE_SCHEMA_CACHE.getLastCache(fullPath); if (timeValuePair == null) { allCached = false; break; From 7bce02f1c40da36544d28682533f54e9c22d7df1 Mon Sep 17 00:00:00 2001 From: Caideyipi <87789683+Caideyipi@users.noreply.github.com> Date: Wed, 15 Apr 2026 14:38:55 +0800 Subject: [PATCH 19/19] fix --- .../thrift/impl/ClientRPCServiceImpl.java | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java index d8441c56d6a61..06b60117c5fc0 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java @@ -1389,25 +1389,27 @@ public TSExecuteStatementResp executeFastLastDataQueryForOneDeviceV2( queryTree.constructTree(); queryTree = s.getAuthorityScope().intersectWithFullPathPrefixTree(queryTree); - for (final MeasurementPath fullPath : queryTree.getAllPathPatterns(true)) { - final TimeValuePair timeValuePair = DATA_NODE_SCHEMA_CACHE.getLastCache(fullPath); - if (timeValuePair == null) { - allCached = false; - break; - } else if (timeValuePair.getValue() == null) { - // there is no data for this sensor - if (!canUseNullEntry) { + if (!queryTree.isEmpty()) { + for (final MeasurementPath fullPath : queryTree.getAllPathPatterns(true)) { + final TimeValuePair timeValuePair = DATA_NODE_SCHEMA_CACHE.getLastCache(fullPath); + if (timeValuePair == null) { allCached = false; break; + } else if (timeValuePair.getValue() == null) { + // there is no data for this sensor + if (!canUseNullEntry) { + allCached = false; + break; + } + } else { + // we don't consider TTL + LastQueryUtil.appendLastValueRespectBlob( + builder, + timeValuePair.getTimestamp(), + new Binary(fullPath.getFullPath(), TSFileConfig.STRING_CHARSET), + timeValuePair.getValue(), + timeValuePair.getValue().getDataType().name()); } - } else { - // we don't consider TTL - LastQueryUtil.appendLastValueRespectBlob( - builder, - timeValuePair.getTimestamp(), - new Binary(fullPath.getFullPath(), TSFileConfig.STRING_CHARSET), - timeValuePair.getValue(), - timeValuePair.getValue().getDataType().name()); } } // cache hit