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

justinchen pushed a commit to branch c-ger-p
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit 177787a269ba67b413f4f780297ce9b69a79e339
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
---
 .../org/apache/iotdb/db/it/IoTDBRestServiceIT.java | 160 +++++++++++++
 .../org/apache/iotdb/db/it/utils/TestUtils.java    |  26 ++
 .../iotdb/session/it/IoTDBSessionQueryIT.java      |  77 ++++++
 .../schema/table/RenameTableColumnProcedure.java   | 247 +++++++++++++++++++
 .../schema/table/SetTablePropertiesProcedure.java  | 264 +++++++++++++++++++++
 .../protocol/rest/v2/impl/RestApiServiceImpl.java  |  31 ++-
 .../protocol/thrift/impl/ClientRPCServiceImpl.java |  84 ++++---
 .../plan/parser/StatementGenerator.java            |   2 +-
 .../schemaengine/schemaregion/ISchemaRegion.java   |   2 +-
 .../schemaregion/impl/SchemaRegionMemoryImpl.java  |   4 +-
 .../schemaregion/impl/SchemaRegionPBTreeImpl.java  |   2 +-
 .../mtree/impl/mem/MTreeBelowSGMemoryImpl.java     |   5 +-
 12 files changed, 865 insertions(+), 39 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 ad1b93ad2d8..e8eca4937d5 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.db.queryengine.common.header.ColumnHeaderConstant;
+import org.apache.iotdb.db.it.utils.TestUtils;
 import org.apache.iotdb.it.env.EnvFactory;
 import org.apache.iotdb.it.env.cluster.env.SimpleEnv;
 import org.apache.iotdb.it.env.cluster.node.DataNodeWrapper;
@@ -57,6 +58,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;
@@ -513,6 +515,7 @@ public class IoTDBRestServiceIT {
     selectLast(httpClient);
 
     queryV2(httpClient);
+    selectFastLast(httpClient);
     queryGroupByLevelV2(httpClient);
     queryRowLimitV2(httpClient);
     queryShowChildPathsV2(httpClient);
@@ -923,6 +926,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 {
@@ -1677,6 +1745,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 abf59367082..f45209c7888 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
@@ -684,6 +684,32 @@ public class TestUtils {
     }
   }
 
+  public static void assertResultSetEqual(
+      SessionDataSet actualResultSet,
+      List<String> expectedColumnNames,
+      Set<String> expectedRetSet,
+      boolean ignoreTimeStamp) {
+    final Set<String> copiedSet = new HashSet<>(expectedRetSet);
+    try {
+      List<String> actualColumnNames = actualResultSet.getColumnNames();
+      if (ignoreTimeStamp) {
+        assertEquals(expectedColumnNames, actualColumnNames);
+      } else {
+        assertEquals(TIMESTAMP_STR, actualColumnNames.get(0));
+        assertEquals(expectedColumnNames, actualColumnNames.subList(1, 
actualColumnNames.size()));
+      }
+
+      while (actualResultSet.hasNext()) {
+        RowRecord rowRecord = actualResultSet.next();
+        assertTrue(copiedSet.remove(rowRecord.toString().replace('\t', ',')));
+      }
+      assertEquals(0, copiedSet.size());
+    } catch (IoTDBConnectionException | StatementExecutionException e) {
+      e.printStackTrace();
+      fail(e.getMessage());
+    }
+  }
+
   public static void createUser(String userName, String password) {
     createUser(EnvFactory.getEnv(), userName, password);
   }
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 ba5c22ab996..8ba5fcc6170 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;
@@ -244,6 +246,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
new file mode 100644
index 00000000000..a2a6c72577c
--- /dev/null
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/RenameTableColumnProcedure.java
@@ -0,0 +1,247 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.confignode.procedure.impl.schema.table;
+
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.commons.exception.IoTDBException;
+import org.apache.iotdb.commons.exception.MetadataException;
+import org.apache.iotdb.commons.schema.table.TsTable;
+import 
org.apache.iotdb.confignode.consensus.request.write.table.RenameTableColumnPlan;
+import 
org.apache.iotdb.confignode.consensus.request.write.table.view.RenameViewColumnPlan;
+import org.apache.iotdb.confignode.procedure.env.ConfigNodeProcedureEnv;
+import org.apache.iotdb.confignode.procedure.exception.ProcedureException;
+import 
org.apache.iotdb.confignode.procedure.impl.schema.table.view.RenameViewColumnProcedure;
+import 
org.apache.iotdb.confignode.procedure.state.schema.RenameTableColumnState;
+import org.apache.iotdb.confignode.procedure.store.ProcedureType;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+import org.apache.tsfile.utils.Pair;
+import org.apache.tsfile.utils.ReadWriteIOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Objects;
+
+public class RenameTableColumnProcedure
+    extends AbstractAlterOrDropTableProcedure<RenameTableColumnState> {
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(RenameTableColumnProcedure.class);
+
+  private String oldName;
+  private String newName;
+
+  public RenameTableColumnProcedure(final boolean isGeneratedByPipe) {
+    super(isGeneratedByPipe);
+  }
+
+  public RenameTableColumnProcedure(
+      final String database,
+      final String tableName,
+      final String queryId,
+      final String oldName,
+      final String newName,
+      final boolean isGeneratedByPipe) {
+    super(database, tableName, queryId, isGeneratedByPipe);
+    this.oldName = oldName;
+    this.newName = newName;
+  }
+
+  @Override
+  protected Flow executeFromState(
+      final ConfigNodeProcedureEnv env, final RenameTableColumnState state)
+      throws InterruptedException {
+    final long startTime = System.currentTimeMillis();
+    try {
+      switch (state) {
+        case COLUMN_CHECK:
+          LOGGER.info("Column check for table {}.{} when renaming column", 
database, tableName);
+          columnCheck(env);
+          break;
+        case PRE_RELEASE:
+          LOGGER.info("Pre release info of table {}.{} when renaming column", 
database, tableName);
+          preRelease(env);
+          break;
+        case RENAME_COLUMN:
+          LOGGER.info("Rename column to table {}.{} on config node", database, 
tableName);
+          renameColumn(env);
+          break;
+        case COMMIT_RELEASE:
+          LOGGER.info(
+              "Commit release info of table {}.{} when renaming column", 
database, tableName);
+          commitRelease(env);
+          return Flow.NO_MORE_STATE;
+        default:
+          setFailure(new ProcedureException("Unrecognized 
RenameTableColumnState " + state));
+          return Flow.NO_MORE_STATE;
+      }
+      return Flow.HAS_MORE_STATE;
+    } finally {
+      LOGGER.info(
+          "RenameTableColumn-{}.{}-{} costs {}ms",
+          database,
+          tableName,
+          state,
+          (System.currentTimeMillis() - startTime));
+    }
+  }
+
+  private void columnCheck(final ConfigNodeProcedureEnv env) {
+    try {
+      final Pair<TSStatus, TsTable> result =
+          env.getConfigManager()
+              .getClusterSchemaManager()
+              .tableColumnCheckForColumnRenaming(
+                  database, tableName, oldName, newName, this instanceof 
RenameViewColumnProcedure);
+      final TSStatus status = result.getLeft();
+      if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+        setFailure(new ProcedureException(new IoTDBException(status)));
+        return;
+      }
+      table = result.getRight();
+      setNextState(RenameTableColumnState.PRE_RELEASE);
+    } catch (final MetadataException e) {
+      setFailure(new ProcedureException(e));
+    }
+  }
+
+  @Override
+  protected void preRelease(final ConfigNodeProcedureEnv env) {
+    super.preRelease(env);
+    setNextState(RenameTableColumnState.RENAME_COLUMN);
+  }
+
+  private void renameColumn(final ConfigNodeProcedureEnv env) {
+    final TSStatus status =
+        env.getConfigManager()
+            .getClusterSchemaManager()
+            .executePlan(
+                this instanceof RenameViewColumnProcedure
+                    ? new RenameViewColumnPlan(database, tableName, oldName, 
newName)
+                    : new RenameTableColumnPlan(database, tableName, oldName, 
newName),
+                isGeneratedByPipe);
+    if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+      setFailure(new ProcedureException(new IoTDBException(status)));
+    } else {
+      setNextState(RenameTableColumnState.COMMIT_RELEASE);
+    }
+  }
+
+  @Override
+  protected void rollbackState(final ConfigNodeProcedureEnv env, final 
RenameTableColumnState state)
+      throws IOException, InterruptedException, ProcedureException {
+    final long startTime = System.currentTimeMillis();
+    try {
+      switch (state) {
+        case RENAME_COLUMN:
+          LOGGER.info(
+              "Start rollback Renaming column to table {}.{} on configNode",
+              database,
+              table.getTableName());
+          rollbackRenameColumn(env);
+          break;
+        case PRE_RELEASE:
+          LOGGER.info(
+              "Start rollback pre release info of table {}.{}", database, 
table.getTableName());
+          rollbackPreRelease(env);
+          break;
+      }
+    } finally {
+      LOGGER.info(
+          "Rollback RenameTableColumn-{} costs {}ms.",
+          state,
+          (System.currentTimeMillis() - startTime));
+    }
+  }
+
+  private void rollbackRenameColumn(final ConfigNodeProcedureEnv env) {
+    if (table == null) {
+      return;
+    }
+    final TSStatus status =
+        env.getConfigManager()
+            .getClusterSchemaManager()
+            .executePlan(
+                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)));
+    }
+  }
+
+  @Override
+  protected RenameTableColumnState getState(final int stateId) {
+    return RenameTableColumnState.values()[stateId];
+  }
+
+  @Override
+  protected int getStateId(final RenameTableColumnState state) {
+    return state.ordinal();
+  }
+
+  @Override
+  protected RenameTableColumnState getInitialState() {
+    return RenameTableColumnState.COLUMN_CHECK;
+  }
+
+  @Override
+  protected String getActionMessage() {
+    return "rename table column";
+  }
+
+  @Override
+  public void serialize(final DataOutputStream stream) throws IOException {
+    stream.writeShort(
+        isGeneratedByPipe
+            ? 
ProcedureType.PIPE_ENRICHED_RENAME_TABLE_COLUMN_PROCEDURE.getTypeCode()
+            : ProcedureType.RENAME_TABLE_COLUMN_PROCEDURE.getTypeCode());
+    innerSerialize(stream);
+  }
+
+  protected void innerSerialize(final DataOutputStream stream) throws 
IOException {
+    super.serialize(stream);
+
+    ReadWriteIOUtils.write(oldName, stream);
+    ReadWriteIOUtils.write(newName, stream);
+  }
+
+  @Override
+  public void deserialize(final ByteBuffer byteBuffer) {
+    super.deserialize(byteBuffer);
+
+    this.oldName = ReadWriteIOUtils.readString(byteBuffer);
+    this.newName = ReadWriteIOUtils.readString(byteBuffer);
+  }
+
+  @Override
+  public boolean equals(final Object o) {
+    return super.equals(o)
+        && Objects.equals(oldName, ((RenameTableColumnProcedure) o).oldName)
+        && Objects.equals(newName, ((RenameTableColumnProcedure) o).newName);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(super.hashCode(), oldName, newName);
+  }
+}
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
new file mode 100644
index 00000000000..138ae9c9b50
--- /dev/null
+++ 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/SetTablePropertiesProcedure.java
@@ -0,0 +1,264 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.confignode.procedure.impl.schema.table;
+
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.commons.exception.IoTDBException;
+import org.apache.iotdb.commons.exception.MetadataException;
+import org.apache.iotdb.commons.schema.table.TsTable;
+import 
org.apache.iotdb.confignode.consensus.request.write.table.SetTablePropertiesPlan;
+import 
org.apache.iotdb.confignode.consensus.request.write.table.view.SetViewPropertiesPlan;
+import org.apache.iotdb.confignode.procedure.env.ConfigNodeProcedureEnv;
+import org.apache.iotdb.confignode.procedure.exception.ProcedureException;
+import 
org.apache.iotdb.confignode.procedure.impl.schema.table.view.SetViewPropertiesProcedure;
+import 
org.apache.iotdb.confignode.procedure.state.schema.SetTablePropertiesState;
+import org.apache.iotdb.confignode.procedure.store.ProcedureType;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+import org.apache.tsfile.utils.Pair;
+import org.apache.tsfile.utils.ReadWriteIOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import static 
org.apache.iotdb.confignode.procedure.state.schema.SetTablePropertiesState.COMMIT_RELEASE;
+import static 
org.apache.iotdb.confignode.procedure.state.schema.SetTablePropertiesState.PRE_RELEASE;
+import static 
org.apache.iotdb.confignode.procedure.state.schema.SetTablePropertiesState.SET_PROPERTIES;
+import static 
org.apache.iotdb.confignode.procedure.state.schema.SetTablePropertiesState.VALIDATE_TABLE;
+
+public class SetTablePropertiesProcedure
+    extends AbstractAlterOrDropTableProcedure<SetTablePropertiesState> {
+
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(SetTablePropertiesProcedure.class);
+
+  private Map<String, String> originalProperties = new HashMap<>();
+  private Map<String, String> updatedProperties;
+
+  public SetTablePropertiesProcedure(final boolean isGeneratedByPipe) {
+    super(isGeneratedByPipe);
+  }
+
+  public SetTablePropertiesProcedure(
+      final String database,
+      final String tableName,
+      final String queryId,
+      final Map<String, String> properties,
+      final boolean isGeneratedByPipe) {
+    super(database, tableName, queryId, isGeneratedByPipe);
+    this.updatedProperties = properties;
+  }
+
+  @Override
+  protected Flow executeFromState(
+      final ConfigNodeProcedureEnv env, final SetTablePropertiesState state)
+      throws InterruptedException {
+    final long startTime = System.currentTimeMillis();
+    try {
+      switch (state) {
+        case VALIDATE_TABLE:
+          validateTable(env);
+          LOGGER.info(
+              "Validate table for table {}.{} when setting properties", 
database, tableName);
+          if (!isFailed() && Objects.isNull(table)) {
+            LOGGER.info(
+                "The updated table has the same properties with the original 
one. Skip the procedure.");
+            return Flow.NO_MORE_STATE;
+          }
+          break;
+        case PRE_RELEASE:
+          preRelease(env);
+          LOGGER.info(
+              "Pre release info for table {}.{} when setting properties", 
database, tableName);
+          break;
+        case SET_PROPERTIES:
+          setProperties(env);
+          LOGGER.info("Set properties to table {}.{}", database, tableName);
+          break;
+        case COMMIT_RELEASE:
+          commitRelease(env);
+          LOGGER.info(
+              "Commit release info of table {}.{} when setting properties", 
database, tableName);
+          return Flow.NO_MORE_STATE;
+        default:
+          setFailure(new ProcedureException("Unrecognized AddTableColumnState 
" + state));
+          return Flow.NO_MORE_STATE;
+      }
+      return Flow.HAS_MORE_STATE;
+    } finally {
+      LOGGER.info(
+          "SetTableProperties-{}.{}-{} costs {}ms",
+          database,
+          tableName,
+          state,
+          (System.currentTimeMillis() - startTime));
+    }
+  }
+
+  private void validateTable(final ConfigNodeProcedureEnv env) {
+    try {
+      final Pair<TSStatus, TsTable> result =
+          env.getConfigManager()
+              .getClusterSchemaManager()
+              .updateTableProperties(
+                  database,
+                  tableName,
+                  originalProperties,
+                  updatedProperties,
+                  this instanceof SetViewPropertiesProcedure);
+      final TSStatus status = result.getLeft();
+      if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+        setFailure(new ProcedureException(new IoTDBException(status)));
+        return;
+      }
+      table = result.getRight();
+      setNextState(PRE_RELEASE);
+    } catch (final MetadataException e) {
+      setFailure(new ProcedureException(e));
+    }
+  }
+
+  @Override
+  protected void preRelease(final ConfigNodeProcedureEnv env) {
+    super.preRelease(env);
+    setNextState(SET_PROPERTIES);
+  }
+
+  private void setProperties(final ConfigNodeProcedureEnv env) {
+    final TSStatus status =
+        env.getConfigManager()
+            .getClusterSchemaManager()
+            .executePlan(
+                this instanceof SetViewPropertiesProcedure
+                    ? new SetViewPropertiesPlan(database, tableName, 
updatedProperties)
+                    : new SetTablePropertiesPlan(database, tableName, 
updatedProperties),
+                isGeneratedByPipe);
+    if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+      setFailure(new ProcedureException(new IoTDBException(status)));
+    } else {
+      setNextState(COMMIT_RELEASE);
+    }
+  }
+
+  @Override
+  protected String getActionMessage() {
+    return "set table properties";
+  }
+
+  @Override
+  protected void rollbackState(
+      final ConfigNodeProcedureEnv env, final SetTablePropertiesState state)
+      throws IOException, InterruptedException, ProcedureException {
+    final long startTime = System.currentTimeMillis();
+    try {
+      switch (state) {
+        case PRE_RELEASE:
+          LOGGER.info(
+              "Start rollback pre release info for table {}.{} when setting 
properties",
+              database,
+              table.getTableName());
+          rollbackPreRelease(env);
+          break;
+        case SET_PROPERTIES:
+          LOGGER.info(
+              "Start rollback set properties to table {}.{}", database, 
table.getTableName());
+          rollbackSetProperties(env);
+          break;
+      }
+    } finally {
+      LOGGER.info(
+          "Rollback SetTableProperties-{} costs {}ms.",
+          state,
+          (System.currentTimeMillis() - startTime));
+    }
+  }
+
+  private void rollbackSetProperties(final ConfigNodeProcedureEnv env) {
+    if (table == null) {
+      return;
+    }
+    final TSStatus status =
+        env.getConfigManager()
+            .getClusterSchemaManager()
+            .executePlan(
+                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)));
+    }
+  }
+
+  @Override
+  protected SetTablePropertiesState getState(final int stateId) {
+    return SetTablePropertiesState.values()[stateId];
+  }
+
+  @Override
+  protected int getStateId(final SetTablePropertiesState state) {
+    return state.ordinal();
+  }
+
+  @Override
+  protected SetTablePropertiesState getInitialState() {
+    return VALIDATE_TABLE;
+  }
+
+  @Override
+  public void serialize(final DataOutputStream stream) throws IOException {
+    stream.writeShort(
+        isGeneratedByPipe
+            ? 
ProcedureType.PIPE_ENRICHED_SET_TABLE_PROPERTIES_PROCEDURE.getTypeCode()
+            : ProcedureType.SET_TABLE_PROPERTIES_PROCEDURE.getTypeCode());
+    innerSerialize(stream);
+  }
+
+  protected void innerSerialize(final DataOutputStream stream) throws 
IOException {
+    super.serialize(stream);
+
+    ReadWriteIOUtils.write(originalProperties, stream);
+    ReadWriteIOUtils.write(updatedProperties, stream);
+  }
+
+  @Override
+  public void deserialize(final ByteBuffer byteBuffer) {
+    super.deserialize(byteBuffer);
+
+    this.originalProperties = ReadWriteIOUtils.readMap(byteBuffer);
+    this.updatedProperties = ReadWriteIOUtils.readMap(byteBuffer);
+  }
+
+  @Override
+  public boolean equals(final Object o) {
+    return super.equals(o)
+        && Objects.equals(updatedProperties, ((SetTablePropertiesProcedure) 
o).updatedProperties);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hash(super.hashCode(), updatedProperties);
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/impl/RestApiServiceImpl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/impl/RestApiServiceImpl.java
index 05fc4b80084..23aca924b7c 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/impl/RestApiServiceImpl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/impl/RestApiServiceImpl.java
@@ -55,6 +55,7 @@ import 
org.apache.iotdb.db.queryengine.plan.parser.StatementGenerator;
 import org.apache.iotdb.db.queryengine.plan.statement.Statement;
 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;
@@ -102,7 +103,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();
 
@@ -111,7 +112,23 @@ public class RestApiServiceImpl extends RestApiService {
 
       PartialPath prefixPath =
           new PartialPath(prefixPathList.getPrefixPaths().toArray(new 
String[0]));
+<<<<<<< 
HEAD:iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/impl/RestApiServiceImpl.java
       final Map<PartialPath, Map<String, TimeValuePair>> resultMap = new 
HashMap<>();
+=======
+      final Map<TableId, Map<IDeviceID, Map<String, Pair<TSDataType, 
TimeValuePair>>>> resultMap =
+          new HashMap<>();
+
+      // 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;
+      }
+>>>>>>> bb0f13b78bb (Enhance the last query permission && Fixed the rollback 
version of alter view / table plans && Deleted the unnecessary mods in Tree 
view deletion 
(#17465)):external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java
 
       final String prefixString = prefixPath.toString();
       for (ISchemaRegion region : 
SchemaEngine.getInstance().getAllSchemaRegions()) {
@@ -119,22 +136,28 @@ public class RestApiServiceImpl extends RestApiService {
             && !region.getDatabaseFullPath().startsWith(prefixString)) {
           continue;
         }
+<<<<<<< 
HEAD:iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/impl/RestApiServiceImpl.java
         region.fillLastQueryMap(prefixPath, resultMap);
+=======
+        region.fillLastQueryMap(prefixPath, resultMap, 
statement.getAuthorityScope());
+>>>>>>> bb0f13b78bb (Enhance the last query permission && Fixed the rollback 
version of alter view / table plans && Deleted the unnecessary mods in Tree 
view deletion 
(#17465)):external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java
       }
+
       // Check cache first
+<<<<<<< 
HEAD:iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/rest/v2/impl/RestApiServiceImpl.java
       if 
(!DataNodeSchemaCache.getInstance().getDeviceSchemaCache().getLastCache(resultMap))
 {
         IClientSession clientSession = 
SESSION_MANAGER.getCurrSessionAndUpdateIdleTime();
         TSLastDataQueryReq tsLastDataQueryReq =
             FastLastHandler.createTSLastDataQueryReq(clientSession, 
prefixPathList);
         statement = StatementGenerator.createStatement(tsLastDataQueryReq);
 
+=======
+      if (!TableDeviceSchemaCache.getInstance().getLastCache(resultMap)) {
+>>>>>>> bb0f13b78bb (Enhance the last query permission && Fixed the rollback 
version of alter view / table plans && Deleted the unnecessary mods in Tree 
view deletion 
(#17465)):external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java
         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 8a498fce2e3..fef00a36a41 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
@@ -37,6 +37,7 @@ import 
org.apache.iotdb.commons.partition.DataPartitionQueryParam;
 import org.apache.iotdb.commons.path.AlignedPath;
 import org.apache.iotdb.commons.path.MeasurementPath;
 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.AuditLogger;
 import org.apache.iotdb.db.auth.AuthorityChecker;
@@ -87,6 +88,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;
@@ -819,7 +821,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()) {
@@ -832,13 +834,26 @@ public class ClientRPCServiceImpl implements 
IClientRPCServiceWithHandler {
       final Map<PartialPath, Map<String, TimeValuePair>> resultMap = 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()
@@ -914,6 +929,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 deviceId;
       PartialPath devicePath;
@@ -941,7 +970,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());
@@ -951,7 +980,7 @@ public class ClientRPCServiceImpl implements 
IClientRPCServiceWithHandler {
         return resp;
       }
 
-      TEndPoint lastRegionLeader =
+      final TEndPoint lastRegionLeader =
           regionReplicaSets
               .get(regionReplicaSets.size() - 1)
               .dataNodeLocations
@@ -962,33 +991,42 @@ 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) {
-          PartialPath fullPath;
+
+        PathPatternTree queryTree = new PathPatternTree();
+        for (final String sensor : req.sensors) {
+          final MeasurementPath fullPath;
           if (req.isLegalPathNodes()) {
-            fullPath = devicePath.concatNode(sensor);
+            fullPath = devicePath.concatAsMeasurementPath(sensor);
           } else {
-            fullPath = devicePath.concatNode((new 
PartialPath(sensor)).getFullPath());
+            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.appendLastValue(
@@ -1016,14 +1054,6 @@ public class ClientRPCServiceImpl implements 
IClientRPCServiceWithHandler {
         }
       }
 
-      // cache miss
-      Statement s = StatementGenerator.createStatement(convert(req));
-      // permission check
-      TSStatus status = AuthorityChecker.checkAuthority(s, clientSession);
-      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 b220309df58..9f149abd531 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
@@ -170,7 +170,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 df69657f1d1..f085900a153 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
@@ -317,7 +317,7 @@ public interface ISchemaRegion {
       throws MetadataException;
 
   int fillLastQueryMap(
-      final PartialPath pattern, final Map<PartialPath, Map<String, 
TimeValuePair>> mapToFill)
+      final PartialPath pattern, final Map<PartialPath, Map<String, 
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 7f8074c61ff..a964b7de4af 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
@@ -1335,9 +1335,9 @@ public class SchemaRegionMemoryImpl implements 
ISchemaRegion {
 
   @Override
   public int fillLastQueryMap(
-      final PartialPath pattern, final Map<PartialPath, Map<String, 
TimeValuePair>> mapToFill)
+      final PartialPath pattern, final Map<PartialPath, Map<String, 
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 fd8d7c5f1b5..d4e773dd593 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
@@ -1440,7 +1440,7 @@ public class SchemaRegionPBTreeImpl implements 
ISchemaRegion {
 
   @Override
   public int fillLastQueryMap(
-      final PartialPath pattern, final Map<PartialPath, Map<String, 
TimeValuePair>> mapToFill) {
+      final PartialPath pattern, final Map<PartialPath, Map<String, 
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 63d1e4c097f..e55b79f4645 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
@@ -1085,12 +1085,11 @@ public class MTreeBelowSGMemoryImpl {
   }
 
   public int fillLastQueryMap(
-      final PartialPath prefixPath, final Map<PartialPath, Map<String, 
TimeValuePair>> mapToFill)
+      final PartialPath prefixPath, final Map<PartialPath, Map<String, 
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