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

jiangtian pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new bb0f13b78bb Enhance the last query permission && Fixed the rollback 
version of alter view / table plans && Deleted the unnecessary mods in Tree 
view deletion (#17465)
bb0f13b78bb is described below

commit bb0f13b78bb8651eb6f67881efbbcfb516f0a649
Author: Caideyipi <[email protected]>
AuthorDate: Wed Apr 15 17:14:26 2026 +0800

    Enhance the last query permission && Fixed the rollback version of alter 
view / table plans && Deleted the unnecessary mods in Tree view deletion 
(#17465)
    
    * fix
    
    * fix
    
    * fix
    
    * fix
    
    * IT1
    
    * change
    
    * right-1
    
    * fixation
    
    * fix
    
    * partial
    
    * 13
    
    * limit
    
    * fix
    
    * fix
    
    * mod
    
    * remove-usls
    
    * fix
    
    * fix
    
    * fix
---
 .../rest/protocol/v2/impl/RestApiServiceImpl.java  |  26 ++--
 .../org/apache/iotdb/db/it/IoTDBRestServiceIT.java | 160 +++++++++++++++++++++
 .../org/apache/iotdb/db/it/utils/TestUtils.java    |   8 +-
 .../iotdb/session/it/IoTDBSessionQueryIT.java      |  77 ++++++++++
 .../schema/table/RenameTableColumnProcedure.java   |   4 +-
 .../schema/table/SetTablePropertiesProcedure.java  |   4 +-
 .../protocol/thrift/impl/ClientRPCServiceImpl.java | 101 ++++++++-----
 .../plan/parser/StatementGenerator.java            |   2 +-
 .../schemaengine/schemaregion/ISchemaRegion.java   |   3 +-
 .../schemaregion/impl/SchemaRegionMemoryImpl.java  |   5 +-
 .../schemaregion/impl/SchemaRegionPBTreeImpl.java  |   5 +-
 .../mtree/impl/mem/MTreeBelowSGMemoryImpl.java     |   6 +-
 12 files changed, 337 insertions(+), 64 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 f6c42533a62..e05929c6a63 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.Statement;
 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 class RestApiServiceImpl extends RestApiService {
   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;
@@ -123,7 +124,17 @@ public class RestApiServiceImpl extends RestApiService {
           new PartialPath(prefixPathList.getPrefixPaths().toArray(new 
String[0]));
       final Map<TableId, Map<IDeviceID, Map<String, Pair<TSDataType, 
TimeValuePair>>>> resultMap =
           new HashMap<>();
-      int sensorNum = 0;
+
+      // 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);
+      statement = StatementGenerator.createStatement(tsLastDataQueryReq);
+
+      final Response response = 
authorizationHandler.checkAuthority(securityContext, statement);
+      if (response != null) {
+        return response;
+      }
 
       final String prefixString = prefixPath.toString();
       for (final ISchemaRegion region : 
SchemaEngine.getInstance().getAllSchemaRegions()) {
@@ -131,22 +142,15 @@ public class RestApiServiceImpl extends RestApiService {
             && !region.getDatabaseFullPath().startsWith(prefixString)) {
           continue;
         }
-        sensorNum += region.fillLastQueryMap(prefixPath, resultMap);
+        region.fillLastQueryMap(prefixPath, resultMap, 
statement.getAuthorityScope());
       }
+
       // 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/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 76a246149cd..eb2573c7f84 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.SQLException;
 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;
@@ -476,6 +478,7 @@ public class IoTDBRestServiceIT {
     selectLast(httpClient);
 
     queryV2(httpClient);
+    selectFastLast(httpClient);
     queryGroupByLevelV2(httpClient);
     queryRowLimitV2(httpClient);
     queryShowChildPathsV2(httpClient);
@@ -886,6 +889,71 @@ public class IoTDBRestServiceIT {
     }
   }
 
+  @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<Long> timestampsResult = (List<Long>) map.get("timestamps");
+      List<Long> expressionsResult = (List<Long>) map.get("expressions");
+      List<List<Object>> valuesResult = (List<List<Object>>) map.get("values");
+      Assert.assertTrue(map.size() > 0);
+      List<Object> expressions =
+          new ArrayList<Object>() {
+            {
+              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 {
@@ -1651,6 +1719,98 @@ public class IoTDBRestServiceIT {
     }
   }
 
+  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");
+      String sql = "{\"prefix_paths\":[\"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<Long> timestampsResult = (List<Long>) map.get("timestamps");
+      List<Long> expressionsResult = (List<Long>) map.get("expressions");
+      List<List<Object>> valuesResult = (List<List<Object>>) map.get("values");
+      Assert.assertTrue(map.size() > 0);
+      List<Object> expressions =
+          new ArrayList<Object>() {
+            {
+              add("Timeseries");
+              add("Value");
+              add("DataType");
+            }
+          };
+      List<Object> timestamps =
+          new ArrayList<Object>() {
+            {
+              add(1635232153960l);
+              add(1635232153960l);
+              add(1635232153960l);
+              add(1635232143960l);
+              add(1635232153960l);
+              add(1635232153960l);
+            }
+          };
+      List<Object> values1 =
+          new ArrayList<Object>() {
+            {
+              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<Object> values2 =
+          new ArrayList<Object>() {
+            {
+              add("");
+              add("2");
+              add("1635000012345556");
+              add("1.41");
+              add("false");
+              add("3.5555");
+            }
+          };
+      List<Object> values3 =
+          new ArrayList<Object>() {
+            {
+              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));
+    } 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/db/it/utils/TestUtils.java 
b/integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java
index 43a11647c37..9c2a09024c4 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,8 +1451,9 @@ public class TestUtils {
   public static void assertResultSetEqual(
       SessionDataSet actualResultSet,
       List<String> expectedColumnNames,
-      Set<String> expectedRetArray,
+      Set<String> expectedRetSet,
       boolean ignoreTimeStamp) {
+    final Set<String> copiedSet = new HashSet<>(expectedRetSet);
     try {
       List<String> actualColumnNames = actualResultSet.getColumnNames();
       if (ignoreTimeStamp) {
@@ -1462,12 +1463,11 @@ public class TestUtils {
         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(copiedSet.remove(rowRecord.toString().replace('\t', ',')));
       }
-      assertEquals(expectedRetArray.size(), count);
+      assertEquals(0, copiedSet.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 8bd6833ec08..f65f2b4496f 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 @@ package org.apache.iotdb.session.it;
 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.it.framework.IoTDBTestRunner;
 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,81 @@ public class IoTDBSessionQueryIT {
     }
   }
 
+  @Test
+  public void lastQueryWithPrefixTest() throws IoTDBConnectionException {
+    // Only used in 1D scenarios
+    if (EnvFactory.getEnv().getDataNodeWrapperList().size() > 1) {
+      return;
+    }
+    final Set<String> 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
+      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 
{
+    // Only used in 1D scenarios
+    if (EnvFactory.getEnv().getDataNodeWrapperList().size() > 1) {
+      return;
+    }
+    final String[] retArray = new String[] {};
+    final Set<String> 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");
+        final ISession rootSession = 
EnvFactory.getEnv().getSessionConnection()) {
+      // Push last cache first
+      try (final SessionDataSet resultSet =
+          rootSession.executeFastLastDataQueryForOnePrefixPath(
+              Arrays.asList("root", "sg1", "d1"))) {
+        assertResultSetEqual(resultSet, lastQueryColumnNames, retArray2, true);
+      }
+
+      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());
+    }
+  }
+
   // ------------------------------ Aggregation Query 
------------------------------
   @Test
   public void aggregationQueryTest() {
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 da51dad2672..a2a6c72577c 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 @@ public class RenameTableColumnProcedure
         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 eedbf7fdb3d..138ae9c9b50 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 @@ public class SetTablePropertiesProcedure
         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)));
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 ed754c418c6..06b60117c5f 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.IFullPath;
 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;
@@ -113,6 +114,7 @@ import 
org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowStatement;
 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 +1172,7 @@ public class ClientRPCServiceImpl implements 
IClientRPCServiceWithHandler {
 
     try {
       final long queryId = SESSION_MANAGER.requestQueryId(clientSession, 
req.statementId);
-      // 1. Map<Device, String[] measurements> 
ISchemaFetcher.getAllSensors(prefix) ~= 50ms
+      // 1.1 Map<Device, String[] measurements> 
ISchemaFetcher.getAllSensors(prefix) ~= 50ms
 
       final PartialPath prefixPath = new 
PartialPath(req.getPrefixes().toArray(new String[0]));
       if (prefixPath.hasWildcard()) {
@@ -1184,13 +1186,26 @@ public class ClientRPCServiceImpl implements 
IClientRPCServiceWithHandler {
           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()
@@ -1286,6 +1301,20 @@ public class ClientRPCServiceImpl implements 
IClientRPCServiceWithHandler {
     long startTime = System.nanoTime();
     Throwable t = null;
     try {
+      // Place the permission check first
+      final QueryStatement 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;
@@ -1315,7 +1344,7 @@ public class ClientRPCServiceImpl implements 
IClientRPCServiceWithHandler {
       // 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());
@@ -1325,7 +1354,7 @@ public class ClientRPCServiceImpl implements 
IClientRPCServiceWithHandler {
         return resp;
       }
 
-      TEndPoint lastRegionLeader =
+      final TEndPoint lastRegionLeader =
           regionReplicaSets
               .get(regionReplicaSets.size() - 1)
               .dataNodeLocations
@@ -1336,41 +1365,51 @@ public class ClientRPCServiceImpl implements 
IClientRPCServiceWithHandler {
       // 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);
-          if (timeValuePair == null) {
-            allCached = false;
-            break;
-          } else if (timeValuePair.getValue() == null) {
-            // there is no data for this sensor
-            if (!canUseNullEntry) {
+          queryTree.appendPathPattern(fullPath);
+        }
+        queryTree.constructTree();
+        queryTree = 
s.getAuthorityScope().intersectWithFullPathPrefixTree(queryTree);
+
+        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
@@ -1390,20 +1429,6 @@ public class ClientRPCServiceImpl implements 
IClientRPCServiceWithHandler {
         }
       }
 
-      // 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);
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 4fc5e50a060..901196d0e1b 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 class StatementGenerator {
     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 4a11165353c..8d87435e108 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 @@ public interface ISchemaRegion {
 
   int fillLastQueryMap(
       final PartialPath pattern,
-      final Map<TableId, Map<IDeviceID, Map<String, Pair<TSDataType, 
TimeValuePair>>>> mapToFill)
+      final Map<TableId, Map<IDeviceID, Map<String, Pair<TSDataType, 
TimeValuePair>>>> 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 c5c3b7f57b8..2e200cf8e8c 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 class SchemaRegionMemoryImpl implements 
ISchemaRegion {
   @Override
   public int fillLastQueryMap(
       final PartialPath pattern,
-      final Map<TableId, Map<IDeviceID, Map<String, Pair<TSDataType, 
TimeValuePair>>>> mapToFill)
+      final Map<TableId, Map<IDeviceID, Map<String, Pair<TSDataType, 
TimeValuePair>>>> 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 2f4bec896dd..19517f90601 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 class SchemaRegionPBTreeImpl implements 
ISchemaRegion {
 
   @Override
   public int fillLastQueryMap(
-      PartialPath pattern,
-      Map<TableId, Map<IDeviceID, Map<String, Pair<TSDataType, 
TimeValuePair>>>> mapToFill) {
+      final PartialPath pattern,
+      final Map<TableId, Map<IDeviceID, Map<String, Pair<TSDataType, 
TimeValuePair>>>> 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 ed519030b63..d872a1130a4 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 class MTreeBelowSGMemoryImpl {
 
   public int fillLastQueryMap(
       final PartialPath prefixPath,
-      final Map<TableId, Map<IDeviceID, Map<String, Pair<TSDataType, 
TimeValuePair>>>> mapToFill)
+      final Map<TableId, Map<IDeviceID, Map<String, Pair<TSDataType, 
TimeValuePair>>>> mapToFill,
+      final PathPatternTree scope)
       throws MetadataException {
     final int[] sensorNum = {0};
     try (final EntityUpdater<IMemMNode> updater =
-        new EntityUpdater<IMemMNode>(
-            rootNode, prefixPath, store, true, SchemaConstant.ALL_MATCH_SCOPE) 
{
+        new EntityUpdater<IMemMNode>(rootNode, prefixPath, store, true, scope) 
{
 
           @Override
           protected void updateEntity(final IDeviceMNode<IMemMNode> node) {


Reply via email to