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

xuekaifeng 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 a8d9e4b  ustzh complete  session unsetSchemaTemplate method (#4220)
a8d9e4b is described below

commit a8d9e4b5d7bd4deb42785612f8e5880eab22f398
Author: Hang Zhang <[email protected]>
AuthorDate: Tue Oct 26 00:09:32 2021 +0800

    ustzh complete  session unsetSchemaTemplate method (#4220)
    
    * finish Session unsetSchemaTemplate
    
    * finish server unsetSchemaTemplate
    
    * add testUnsetSchemaTemplate method
    
    * fixed import *
    
    * fixed MManager import *
    
    * fixed pr issues -v1
    
    * add MManager unit test and format code using spotless
    
    * delete template in use exception unit test
    
    * add unsetSchemaTemplate userguide
---
 docs/UserGuide/API/Programming-Java-Native-API.md  | 10 +++
 .../UserGuide/API/Programming-Java-Native-API.md   |  8 ++
 .../metadata/DifferentTemplateException.java       | 33 ++++++++
 .../metadata/NoTemplateOnMNodeException.java       | 33 ++++++++
 .../metadata/TemplateIsInUseException.java         | 33 ++++++++
 .../org/apache/iotdb/db/metadata/MManager.java     | 31 +++++++
 .../iotdb/db/metadata/logfile/MLogWriter.java      |  5 ++
 .../org/apache/iotdb/db/metadata/mtree/MTree.java  | 16 ++++
 .../apache/iotdb/db/qp/executor/PlanExecutor.java  | 13 +++
 .../org/apache/iotdb/db/qp/logical/Operator.java   |  4 +-
 .../apache/iotdb/db/qp/physical/PhysicalPlan.java  |  3 +-
 .../qp/physical/crud/UnsetSchemaTemplatePlan.java  | 96 ++++++++++++++++++++++
 .../org/apache/iotdb/db/service/TSServiceImpl.java | 22 +++++
 .../iotdb/db/metadata/MManagerBasicTest.java       | 67 +++++++++++++++
 .../java/org/apache/iotdb/rpc/TSStatusCode.java    |  3 +
 .../java/org/apache/iotdb/session/Session.java     | 15 ++++
 .../apache/iotdb/session/SessionConnection.java    | 20 +++++
 .../java/org/apache/iotdb/session/SessionTest.java | 94 +++++++++++++++++++++
 thrift/src/main/thrift/rpc.thrift                  | 10 ++-
 19 files changed, 513 insertions(+), 3 deletions(-)

diff --git a/docs/UserGuide/API/Programming-Java-Native-API.md 
b/docs/UserGuide/API/Programming-Java-Native-API.md
index 033fefe..18bae1a 100644
--- a/docs/UserGuide/API/Programming-Java-Native-API.md
+++ b/docs/UserGuide/API/Programming-Java-Native-API.md
@@ -428,6 +428,16 @@ void createSchemaTemplate
 
 ```
 
+``` 
+
+void unsetSchemaTemplate(String prefixPath, String templateName)
+
+```
+
+Unset the measurement template named 'templateName' from path 'prefixPath'. 
You should ensure that there is a template named 'templateName' set at the path 
'prefixPath'.
+
+Attention: Unsetting the template named 'templateName' from node at path 
'prefixPath' or descendant nodes which have already inserted records using 
template is **not supported**.
+
 ### Cluster information related APIs (only works in the cluster mode)
 
 Cluster information related APIs allow users get the cluster info like where a 
storage group will be 
diff --git a/docs/zh/UserGuide/API/Programming-Java-Native-API.md 
b/docs/zh/UserGuide/API/Programming-Java-Native-API.md
index c80636f..2a93e22 100644
--- a/docs/zh/UserGuide/API/Programming-Java-Native-API.md
+++ b/docs/zh/UserGuide/API/Programming-Java-Native-API.md
@@ -237,6 +237,14 @@ void createSchemaTemplate(
 void setSchemaTemplate(String templateName, String prefixPath)
 ```
 
+``` 
+void unsetSchemaTemplate(String prefixPath, String templateName)
+```
+
+* 
卸载'prefixPath'路径下的名为'templateName'的物理量模板。你需要保证给定的路径'prefixPath'下需要有名为'templateName'的物理量模板。
+
+注意:目前不支持从曾经在'prefixPath'路径及其后代节点使用模板插入数据后(即使数据已被删除)卸载模板。
+
 ### 测试接口说明
 
 * 测试 testInsertRecords,不实际写入数据,只将数据传输到 server 即返回。
diff --git 
a/server/src/main/java/org/apache/iotdb/db/exception/metadata/DifferentTemplateException.java
 
b/server/src/main/java/org/apache/iotdb/db/exception/metadata/DifferentTemplateException.java
new file mode 100644
index 0000000..49ce984
--- /dev/null
+++ 
b/server/src/main/java/org/apache/iotdb/db/exception/metadata/DifferentTemplateException.java
@@ -0,0 +1,33 @@
+/*
+ * 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.db.exception.metadata;
+
+import org.apache.iotdb.rpc.TSStatusCode;
+
+public class DifferentTemplateException extends MetadataException {
+
+  public DifferentTemplateException(String path, String templateName) {
+    super(
+        String.format("The template on " + path + " is different from " + 
templateName),
+        TSStatusCode.DIFFERENT_TEMPLATE.getStatusCode(),
+        true);
+  }
+}
diff --git 
a/server/src/main/java/org/apache/iotdb/db/exception/metadata/NoTemplateOnMNodeException.java
 
b/server/src/main/java/org/apache/iotdb/db/exception/metadata/NoTemplateOnMNodeException.java
new file mode 100644
index 0000000..0e5d4e8
--- /dev/null
+++ 
b/server/src/main/java/org/apache/iotdb/db/exception/metadata/NoTemplateOnMNodeException.java
@@ -0,0 +1,33 @@
+/*
+ * 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.db.exception.metadata;
+
+import org.apache.iotdb.rpc.TSStatusCode;
+
+public class NoTemplateOnMNodeException extends MetadataException {
+
+  public NoTemplateOnMNodeException(String path) {
+    super(
+        String.format("NO template on " + path),
+        TSStatusCode.NO_TEMPLATE_ON_MNODE.getStatusCode(),
+        true);
+  }
+}
diff --git 
a/server/src/main/java/org/apache/iotdb/db/exception/metadata/TemplateIsInUseException.java
 
b/server/src/main/java/org/apache/iotdb/db/exception/metadata/TemplateIsInUseException.java
new file mode 100644
index 0000000..923832d
--- /dev/null
+++ 
b/server/src/main/java/org/apache/iotdb/db/exception/metadata/TemplateIsInUseException.java
@@ -0,0 +1,33 @@
+/*
+ * 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.db.exception.metadata;
+
+import org.apache.iotdb.rpc.TSStatusCode;
+
+public class TemplateIsInUseException extends MetadataException {
+
+  public TemplateIsInUseException(String path) {
+    super(
+        String.format("Template is in use on " + path),
+        TSStatusCode.TEMPLATE_IS_IN_USE.getStatusCode(),
+        true);
+  }
+}
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java 
b/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java
index 153fcbf..455d1d5 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/MManager.java
@@ -26,12 +26,15 @@ import 
org.apache.iotdb.db.engine.trigger.executor.TriggerEngine;
 import org.apache.iotdb.db.exception.metadata.AliasAlreadyExistException;
 import org.apache.iotdb.db.exception.metadata.DataTypeMismatchException;
 import org.apache.iotdb.db.exception.metadata.DeleteFailedException;
+import org.apache.iotdb.db.exception.metadata.DifferentTemplateException;
 import org.apache.iotdb.db.exception.metadata.MNodeTypeMismatchException;
 import org.apache.iotdb.db.exception.metadata.MetadataException;
+import org.apache.iotdb.db.exception.metadata.NoTemplateOnMNodeException;
 import org.apache.iotdb.db.exception.metadata.PathAlreadyExistException;
 import org.apache.iotdb.db.exception.metadata.PathNotExistException;
 import org.apache.iotdb.db.exception.metadata.StorageGroupAlreadySetException;
 import org.apache.iotdb.db.exception.metadata.StorageGroupNotSetException;
+import org.apache.iotdb.db.exception.metadata.TemplateIsInUseException;
 import org.apache.iotdb.db.metadata.lastCache.LastCacheManager;
 import org.apache.iotdb.db.metadata.logfile.MLogReader;
 import org.apache.iotdb.db.metadata.logfile.MLogWriter;
@@ -55,6 +58,7 @@ import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertRowPlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertTabletPlan;
 import org.apache.iotdb.db.qp.physical.crud.SetSchemaTemplatePlan;
+import org.apache.iotdb.db.qp.physical.crud.UnsetSchemaTemplatePlan;
 import org.apache.iotdb.db.qp.physical.sys.AutoCreateDeviceMNodePlan;
 import org.apache.iotdb.db.qp.physical.sys.ChangeAliasPlan;
 import org.apache.iotdb.db.qp.physical.sys.ChangeTagOffsetPlan;
@@ -428,6 +432,9 @@ public class MManager {
         AutoCreateDeviceMNodePlan autoCreateDeviceMNodePlan = 
(AutoCreateDeviceMNodePlan) plan;
         autoCreateDeviceMNode(autoCreateDeviceMNodePlan);
         break;
+      case UNSET_SCHEMA_TEMPLATE:
+        UnsetSchemaTemplatePlan unsetSchemaTemplatePlan = 
(UnsetSchemaTemplatePlan) plan;
+        unsetSchemaTemplate(unsetSchemaTemplatePlan);
       default:
         logger.error("Unrecognizable command {}", plan.getOperatorType());
     }
@@ -2130,6 +2137,30 @@ public class MManager {
     }
   }
 
+  public synchronized void unsetSchemaTemplate(UnsetSchemaTemplatePlan plan)
+      throws MetadataException {
+    // get mnode should be atomic
+    try {
+      PartialPath path = new PartialPath(plan.getPrefixPath());
+      IMNode node = mtree.getNodeByPath(path);
+      if (node.getSchemaTemplate() == null) {
+        throw new NoTemplateOnMNodeException(plan.getPrefixPath());
+      } else if 
(!node.getSchemaTemplate().getName().equals(plan.getTemplateName())) {
+        throw new DifferentTemplateException(plan.getPrefixPath(), 
plan.getTemplateName());
+      } else if (node.isUseTemplate()) {
+        throw new TemplateIsInUseException(plan.getPrefixPath());
+      }
+      mtree.checkTemplateInUseOnLowerNode(node);
+      node.setSchemaTemplate(null);
+      // write wal
+      if (!isRecovering) {
+        logWriter.unsetSchemaTemplate(plan);
+      }
+    } catch (IOException e) {
+      throw new MetadataException(e);
+    }
+  }
+
   public void setUsingSchemaTemplate(SetUsingSchemaTemplatePlan plan) throws 
MetadataException {
     try {
       setUsingSchemaTemplate(getDeviceNode(plan.getPrefixPath()));
diff --git 
a/server/src/main/java/org/apache/iotdb/db/metadata/logfile/MLogWriter.java 
b/server/src/main/java/org/apache/iotdb/db/metadata/logfile/MLogWriter.java
index 36f3b30..d4791ba 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/logfile/MLogWriter.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/logfile/MLogWriter.java
@@ -27,6 +27,7 @@ import org.apache.iotdb.db.metadata.mnode.IStorageGroupMNode;
 import org.apache.iotdb.db.qp.physical.PhysicalPlan;
 import org.apache.iotdb.db.qp.physical.crud.CreateTemplatePlan;
 import org.apache.iotdb.db.qp.physical.crud.SetSchemaTemplatePlan;
+import org.apache.iotdb.db.qp.physical.crud.UnsetSchemaTemplatePlan;
 import org.apache.iotdb.db.qp.physical.sys.AutoCreateDeviceMNodePlan;
 import org.apache.iotdb.db.qp.physical.sys.ChangeAliasPlan;
 import org.apache.iotdb.db.qp.physical.sys.ChangeTagOffsetPlan;
@@ -172,6 +173,10 @@ public class MLogWriter implements AutoCloseable {
     putLog(plan);
   }
 
+  public void unsetSchemaTemplate(UnsetSchemaTemplatePlan plan) throws 
IOException {
+    putLog(plan);
+  }
+
   public void autoCreateDeviceMNode(AutoCreateDeviceMNodePlan plan) throws 
IOException {
     putLog(plan);
   }
diff --git a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTree.java 
b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTree.java
index 219b27d..d51e8e7 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTree.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/mtree/MTree.java
@@ -29,6 +29,7 @@ import 
org.apache.iotdb.db.exception.metadata.PathAlreadyExistException;
 import org.apache.iotdb.db.exception.metadata.PathNotExistException;
 import org.apache.iotdb.db.exception.metadata.StorageGroupAlreadySetException;
 import org.apache.iotdb.db.exception.metadata.StorageGroupNotSetException;
+import org.apache.iotdb.db.exception.metadata.TemplateIsInUseException;
 import org.apache.iotdb.db.metadata.MManager.StorageGroupFilter;
 import org.apache.iotdb.db.metadata.MetadataConstant;
 import org.apache.iotdb.db.metadata.PartialPath;
@@ -1346,6 +1347,21 @@ public class MTree implements Serializable {
       checkTemplateOnSubtree(child);
     }
   }
+
+  public void checkTemplateInUseOnLowerNode(IMNode node) throws 
TemplateIsInUseException {
+    if (node.isMeasurement()) {
+      return;
+    }
+    for (IMNode child : node.getChildren().values()) {
+      if (child.isMeasurement()) {
+        continue;
+      }
+      if (child.isUseTemplate()) {
+        throw new TemplateIsInUseException(child.getFullPath());
+      }
+      checkTemplateInUseOnLowerNode(child);
+    }
+  }
   // endregion
 
   // region TestOnly Interface
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java 
b/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java
index 638941c..fe4c59f 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/executor/PlanExecutor.java
@@ -82,6 +82,7 @@ import org.apache.iotdb.db.qp.physical.crud.QueryPlan;
 import org.apache.iotdb.db.qp.physical.crud.RawDataQueryPlan;
 import org.apache.iotdb.db.qp.physical.crud.SetSchemaTemplatePlan;
 import org.apache.iotdb.db.qp.physical.crud.UDTFPlan;
+import org.apache.iotdb.db.qp.physical.crud.UnsetSchemaTemplatePlan;
 import org.apache.iotdb.db.qp.physical.sys.AlterTimeSeriesPlan;
 import org.apache.iotdb.db.qp.physical.sys.AuthorPlan;
 import org.apache.iotdb.db.qp.physical.sys.CountPlan;
@@ -363,6 +364,8 @@ public class PlanExecutor implements IPlanExecutor {
         return createSchemaTemplate((CreateTemplatePlan) plan);
       case SET_SCHEMA_TEMPLATE:
         return setSchemaTemplate((SetSchemaTemplatePlan) plan);
+      case UNSET_SCHEMA_TEMPLATE:
+        return unsetSchemaTemplate((UnsetSchemaTemplatePlan) plan);
       case CREATE_CONTINUOUS_QUERY:
         return operateCreateContinuousQuery((CreateContinuousQueryPlan) plan);
       case DROP_CONTINUOUS_QUERY:
@@ -396,6 +399,16 @@ public class PlanExecutor implements IPlanExecutor {
     return true;
   }
 
+  private boolean unsetSchemaTemplate(UnsetSchemaTemplatePlan 
unsetSchemaTemplatePlan)
+      throws QueryProcessException {
+    try {
+      IoTDB.metaManager.unsetSchemaTemplate(unsetSchemaTemplatePlan);
+    } catch (MetadataException e) {
+      throw new QueryProcessException(e);
+    }
+    return true;
+  }
+
   private boolean operateCreateFunction(CreateFunctionPlan plan) throws 
UDFRegistrationException {
     UDFRegistrationService.getInstance().register(plan.getUdfName(), 
plan.getClassName(), true);
     return true;
diff --git a/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java 
b/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java
index 05432cb..483415e 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/logical/Operator.java
@@ -173,6 +173,8 @@ public abstract class Operator {
     SHOW_CONTINUOUS_QUERIES,
     SET_SYSTEM_MODE,
 
-    SETTLE
+    SETTLE,
+
+    UNSET_SCHEMA_TEMPLATE
   }
 }
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/physical/PhysicalPlan.java 
b/server/src/main/java/org/apache/iotdb/db/qp/physical/PhysicalPlan.java
index a8d3e31..e0371ef 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/physical/PhysicalPlan.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/physical/PhysicalPlan.java
@@ -484,7 +484,8 @@ public abstract class PhysicalPlan {
     CREATE_FUNCTION,
     DROP_FUNCTION,
     SELECT_INTO,
-    SET_SYSTEM_MODE
+    SET_SYSTEM_MODE,
+    UNSET_SCHEMA_TEMPLATE
   }
 
   public long getIndex() {
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/UnsetSchemaTemplatePlan.java
 
b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/UnsetSchemaTemplatePlan.java
new file mode 100644
index 0000000..6a4716e
--- /dev/null
+++ 
b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/UnsetSchemaTemplatePlan.java
@@ -0,0 +1,96 @@
+/*
+ * 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.db.qp.physical.crud;
+
+import org.apache.iotdb.db.metadata.PartialPath;
+import org.apache.iotdb.db.qp.logical.Operator;
+import org.apache.iotdb.db.qp.physical.PhysicalPlan;
+import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+public class UnsetSchemaTemplatePlan extends PhysicalPlan {
+
+  String prefixPath;
+  String templateName;
+
+  public UnsetSchemaTemplatePlan() {
+    super(false, Operator.OperatorType.UNSET_SCHEMA_TEMPLATE);
+  }
+
+  public UnsetSchemaTemplatePlan(String prefixPath, String templateName) {
+    super(false, Operator.OperatorType.UNSET_SCHEMA_TEMPLATE);
+    this.prefixPath = prefixPath;
+    this.templateName = templateName;
+  }
+
+  public String getPrefixPath() {
+    return prefixPath;
+  }
+
+  public void setPrefixPath(String prefixPath) {
+    this.prefixPath = prefixPath;
+  }
+
+  public String getTemplateName() {
+    return templateName;
+  }
+
+  public void setTemplateName(String templateName) {
+    this.templateName = templateName;
+  }
+
+  @Override
+  public List<PartialPath> getPaths() {
+    return null;
+  }
+
+  @Override
+  public void serialize(ByteBuffer buffer) {
+    buffer.put((byte) PhysicalPlanType.UNSET_SCHEMA_TEMPLATE.ordinal());
+
+    ReadWriteIOUtils.write(prefixPath, buffer);
+    ReadWriteIOUtils.write(templateName, buffer);
+
+    buffer.putLong(index);
+  }
+
+  @Override
+  public void deserialize(ByteBuffer buffer) {
+    prefixPath = ReadWriteIOUtils.readString(buffer);
+    templateName = ReadWriteIOUtils.readString(buffer);
+
+    this.index = buffer.getLong();
+  }
+
+  @Override
+  public void serialize(DataOutputStream stream) throws IOException {
+    stream.writeByte((byte) PhysicalPlanType.UNSET_SCHEMA_TEMPLATE.ordinal());
+
+    ReadWriteIOUtils.write(prefixPath, stream);
+    ReadWriteIOUtils.write(templateName, stream);
+
+    stream.writeLong(index);
+  }
+}
diff --git 
a/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java 
b/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java
index 3c658a9..6a8cc7e 100644
--- a/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java
+++ b/server/src/main/java/org/apache/iotdb/db/service/TSServiceImpl.java
@@ -63,6 +63,7 @@ import org.apache.iotdb.db.qp.physical.crud.SelectIntoPlan;
 import org.apache.iotdb.db.qp.physical.crud.SetSchemaTemplatePlan;
 import org.apache.iotdb.db.qp.physical.crud.UDFPlan;
 import org.apache.iotdb.db.qp.physical.crud.UDTFPlan;
+import org.apache.iotdb.db.qp.physical.crud.UnsetSchemaTemplatePlan;
 import org.apache.iotdb.db.qp.physical.sys.AuthorPlan;
 import org.apache.iotdb.db.qp.physical.sys.CreateAlignedTimeSeriesPlan;
 import org.apache.iotdb.db.qp.physical.sys.CreateMultiTimeSeriesPlan;
@@ -129,6 +130,7 @@ import 
org.apache.iotdb.service.rpc.thrift.TSSetSchemaTemplateReq;
 import org.apache.iotdb.service.rpc.thrift.TSSetTimeZoneReq;
 import org.apache.iotdb.service.rpc.thrift.TSStatus;
 import org.apache.iotdb.service.rpc.thrift.TSTracingInfo;
+import org.apache.iotdb.service.rpc.thrift.TSUnsetSchemaTemplateReq;
 import 
org.apache.iotdb.tsfile.exception.filter.QueryFilterOptimizationException;
 import org.apache.iotdb.tsfile.exception.write.UnSupportedDataTypeException;
 import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
@@ -2121,6 +2123,26 @@ public class TSServiceImpl implements TSIService.Iface {
     return status != null ? status : executeNonQueryPlan(plan);
   }
 
+  @Override
+  public TSStatus unsetSchemaTemplate(TSUnsetSchemaTemplateReq req) throws 
TException {
+    if (!checkLogin(req.getSessionId())) {
+      return getNotLoggedInStatus();
+    }
+
+    if (AUDIT_LOGGER.isDebugEnabled()) {
+      AUDIT_LOGGER.debug(
+          "Session-{} unset device template {}.{}",
+          sessionManager.getCurrSessionId(),
+          req.getPrefixPath(),
+          req.getTemplateName());
+    }
+
+    UnsetSchemaTemplatePlan plan = new UnsetSchemaTemplatePlan(req.prefixPath, 
req.templateName);
+
+    TSStatus status = checkAuthority(plan, req.getSessionId());
+    return status != null ? status : executeNonQueryPlan(plan);
+  }
+
   private TSStatus checkAuthority(PhysicalPlan plan, long sessionId) {
     List<PartialPath> paths = plan.getPaths();
     try {
diff --git 
a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerBasicTest.java 
b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerBasicTest.java
index 6bd54a1..d694c90 100644
--- a/server/src/test/java/org/apache/iotdb/db/metadata/MManagerBasicTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/metadata/MManagerBasicTest.java
@@ -30,6 +30,7 @@ import 
org.apache.iotdb.db.qp.physical.crud.CreateTemplatePlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertPlan;
 import org.apache.iotdb.db.qp.physical.crud.InsertRowPlan;
 import org.apache.iotdb.db.qp.physical.crud.SetSchemaTemplatePlan;
+import org.apache.iotdb.db.qp.physical.crud.UnsetSchemaTemplatePlan;
 import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
 import org.apache.iotdb.db.qp.physical.sys.ShowTimeSeriesPlan;
 import org.apache.iotdb.db.query.dataset.ShowTimeSeriesResult;
@@ -942,6 +943,72 @@ public class MManagerBasicTest {
   }
 
   @Test
+  public void testUnsetSchemaTemplate() throws MetadataException {
+
+    List<List<String>> measurementList = new ArrayList<>();
+    measurementList.add(Collections.singletonList("s1"));
+    measurementList.add(Collections.singletonList("s2"));
+    measurementList.add(Collections.singletonList("s3"));
+
+    List<List<TSDataType>> dataTypeList = new ArrayList<>();
+    dataTypeList.add(Collections.singletonList(TSDataType.INT64));
+    dataTypeList.add(Collections.singletonList(TSDataType.INT64));
+    dataTypeList.add(Collections.singletonList(TSDataType.INT64));
+
+    List<List<TSEncoding>> encodingList = new ArrayList<>();
+    encodingList.add(Collections.singletonList(TSEncoding.RLE));
+    encodingList.add(Collections.singletonList(TSEncoding.RLE));
+    encodingList.add(Collections.singletonList(TSEncoding.RLE));
+
+    List<CompressionType> compressionTypes = new ArrayList<>();
+    for (int i = 0; i < 3; i++) {
+      compressionTypes.add(CompressionType.SNAPPY);
+    }
+    List<String> schemaNames = new ArrayList<>();
+    schemaNames.add("s1");
+    schemaNames.add("s2");
+    schemaNames.add("s3");
+
+    CreateTemplatePlan createTemplatePlan =
+        new CreateTemplatePlan(
+            "template1",
+            schemaNames,
+            measurementList,
+            dataTypeList,
+            encodingList,
+            compressionTypes);
+    SetSchemaTemplatePlan setSchemaTemplatePlan =
+        new SetSchemaTemplatePlan("template1", "root.sg.1");
+    UnsetSchemaTemplatePlan unsetSchemaTemplatePlan =
+        new UnsetSchemaTemplatePlan("root.sg.1", "template1");
+    MManager manager = IoTDB.metaManager;
+    manager.createSchemaTemplate(createTemplatePlan);
+
+    // path does not exist test
+    try {
+      manager.unsetSchemaTemplate(unsetSchemaTemplatePlan);
+      fail("No exception thrown.");
+    } catch (Exception e) {
+      assertEquals("Path [root.sg.1] does not exist", e.getMessage());
+    }
+
+    manager.setSchemaTemplate(setSchemaTemplatePlan);
+
+    // template unset test
+    manager.unsetSchemaTemplate(unsetSchemaTemplatePlan);
+    manager.setSchemaTemplate(setSchemaTemplatePlan);
+
+    // no template on path test
+    manager.unsetSchemaTemplate(unsetSchemaTemplatePlan);
+    try {
+      manager.unsetSchemaTemplate(unsetSchemaTemplatePlan);
+      fail("No exception thrown.");
+    } catch (Exception e) {
+      assertEquals("NO template on root.sg.1", e.getMessage());
+    }
+  }
+
+  @Test
   public void testTemplateAndTimeSeriesCompatibility() throws 
MetadataException {
     CreateTemplatePlan plan = getCreateTemplatePlan();
     MManager manager = IoTDB.metaManager;
diff --git a/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java 
b/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java
index c8effe2..5c6a6f3 100644
--- a/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java
+++ b/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java
@@ -54,6 +54,9 @@ public enum TSStatusCode {
   UNDEFINED_TEMPLATE(321),
   STORAGE_GROUP_NOT_EXIST(322),
   CONTINUOUS_QUERY_ERROR(323),
+  NO_TEMPLATE_ON_MNODE(324),
+  DIFFERENT_TEMPLATE(325),
+  TEMPLATE_IS_IN_USE(326),
 
   EXECUTE_STATEMENT_ERROR(400),
   SQL_PARSE_ERROR(401),
diff --git a/session/src/main/java/org/apache/iotdb/session/Session.java 
b/session/src/main/java/org/apache/iotdb/session/Session.java
index 48833aa..d6c71cd 100644
--- a/session/src/main/java/org/apache/iotdb/session/Session.java
+++ b/session/src/main/java/org/apache/iotdb/session/Session.java
@@ -37,6 +37,7 @@ import org.apache.iotdb.service.rpc.thrift.TSInsertTabletReq;
 import org.apache.iotdb.service.rpc.thrift.TSInsertTabletsReq;
 import org.apache.iotdb.service.rpc.thrift.TSProtocolVersion;
 import org.apache.iotdb.service.rpc.thrift.TSSetSchemaTemplateReq;
+import org.apache.iotdb.service.rpc.thrift.TSUnsetSchemaTemplateReq;
 import org.apache.iotdb.session.util.SessionUtils;
 import org.apache.iotdb.session.util.ThreadUtils;
 import org.apache.iotdb.tsfile.common.conf.TSFileConfig;
@@ -1985,6 +1986,12 @@ public class Session {
     defaultSessionConnection.createSchemaTemplate(request);
   }
 
+  public void unsetSchemaTemplate(String prefixPath, String templateName)
+      throws IoTDBConnectionException, StatementExecutionException {
+    TSUnsetSchemaTemplateReq request = getTSUnsetSchemaTemplateReq(prefixPath, 
templateName);
+    defaultSessionConnection.unsetSchemaTemplate(request);
+  }
+
   private TSSetSchemaTemplateReq getTSSetSchemaTemplateReq(String 
templateName, String prefixPath) {
     TSSetSchemaTemplateReq request = new TSSetSchemaTemplateReq();
     request.setTemplateName(templateName);
@@ -2021,6 +2028,14 @@ public class Session {
     return request;
   }
 
+  private TSUnsetSchemaTemplateReq getTSUnsetSchemaTemplateReq(
+      String prefixPath, String templateName) {
+    TSUnsetSchemaTemplateReq request = new TSUnsetSchemaTemplateReq();
+    request.setPrefixPath(prefixPath);
+    request.setTemplateName(templateName);
+    return request;
+  }
+
   /**
    * @param recordsGroup connection to record map
    * @param insertConsumer insert function
diff --git 
a/session/src/main/java/org/apache/iotdb/session/SessionConnection.java 
b/session/src/main/java/org/apache/iotdb/session/SessionConnection.java
index 9f39e7e..ec899d1 100644
--- a/session/src/main/java/org/apache/iotdb/session/SessionConnection.java
+++ b/session/src/main/java/org/apache/iotdb/session/SessionConnection.java
@@ -49,6 +49,7 @@ import org.apache.iotdb.service.rpc.thrift.TSRawDataQueryReq;
 import org.apache.iotdb.service.rpc.thrift.TSSetSchemaTemplateReq;
 import org.apache.iotdb.service.rpc.thrift.TSSetTimeZoneReq;
 import org.apache.iotdb.service.rpc.thrift.TSStatus;
+import org.apache.iotdb.service.rpc.thrift.TSUnsetSchemaTemplateReq;
 import org.apache.iotdb.session.util.SessionUtils;
 
 import org.apache.thrift.TException;
@@ -819,6 +820,25 @@ public class SessionConnection {
     }
   }
 
+  protected void unsetSchemaTemplate(TSUnsetSchemaTemplateReq request)
+      throws IoTDBConnectionException, StatementExecutionException {
+    request.setSessionId(sessionId);
+    try {
+      RpcUtils.verifySuccess(client.unsetSchemaTemplate(request));
+    } catch (TException e) {
+      if (reconnect()) {
+        try {
+          request.setSessionId(sessionId);
+          RpcUtils.verifySuccess(client.unsetSchemaTemplate(request));
+        } catch (TException tException) {
+          throw new IoTDBConnectionException(tException);
+        }
+      } else {
+        throw new IoTDBConnectionException(MSG_RECONNECTION_FAIL);
+      }
+    }
+  }
+
   public boolean isEnableRedirect() {
     return enableRedirect;
   }
diff --git a/session/src/test/java/org/apache/iotdb/session/SessionTest.java 
b/session/src/test/java/org/apache/iotdb/session/SessionTest.java
index 84ef06f..0c56771 100644
--- a/session/src/test/java/org/apache/iotdb/session/SessionTest.java
+++ b/session/src/test/java/org/apache/iotdb/session/SessionTest.java
@@ -288,4 +288,98 @@ public class SessionTest {
       fail();
     }
   }
+
+  @Test
+  public void testUnsetSchemaTemplate()
+      throws IoTDBConnectionException, StatementExecutionException {
+    session = new Session("127.0.0.1", 6667, "root", "root", 
ZoneId.of("+05:00"));
+    session.open();
+
+    List<List<String>> measurementList = new ArrayList<>();
+    measurementList.add(Collections.singletonList("s1"));
+    measurementList.add(Collections.singletonList("s2"));
+    measurementList.add(Collections.singletonList("s3"));
+
+    List<List<TSDataType>> dataTypeList = new ArrayList<>();
+    dataTypeList.add(Collections.singletonList(TSDataType.INT64));
+    dataTypeList.add(Collections.singletonList(TSDataType.INT64));
+    dataTypeList.add(Collections.singletonList(TSDataType.INT64));
+
+    List<List<TSEncoding>> encodingList = new ArrayList<>();
+    encodingList.add(Collections.singletonList(TSEncoding.RLE));
+    encodingList.add(Collections.singletonList(TSEncoding.RLE));
+    encodingList.add(Collections.singletonList(TSEncoding.RLE));
+
+    List<CompressionType> compressionTypes = new ArrayList<>();
+    for (int i = 0; i < 3; i++) {
+      compressionTypes.add(CompressionType.SNAPPY);
+    }
+    List<String> schemaNames = new ArrayList<>();
+    schemaNames.add("s1");
+    schemaNames.add("s2");
+    schemaNames.add("s3");
+
+    session.createSchemaTemplate(
+        "template1", schemaNames, measurementList, dataTypeList, encodingList, 
compressionTypes);
+
+    // path does not exist test
+    try {
+      session.unsetSchemaTemplate("root.sg.1", "template1");
+      fail("No exception thrown.");
+    } catch (Exception e) {
+      assertEquals("304: Path [root.sg.1] does not exist", e.getMessage());
+    }
+
+    session.setSchemaTemplate("template1", "root.sg.1");
+
+    // template already exists test
+    try {
+      session.setSchemaTemplate("template1", "root.sg.1");
+      fail("No exception thrown.");
+    } catch (Exception e) {
+      assertEquals("303: Template already exists on root.sg.1", 
e.getMessage());
+    }
+
+    // template unset test
+    session.unsetSchemaTemplate("root.sg.1", "template1");
+
+    session.setSchemaTemplate("template1", "root.sg.1");
+
+    // no template on path test
+    session.unsetSchemaTemplate("root.sg.1", "template1");
+    try {
+      session.unsetSchemaTemplate("root.sg.1", "template1");
+      fail("No exception thrown.");
+    } catch (Exception e) {
+      assertEquals("324: NO template on root.sg.1", e.getMessage());
+    }
+
+    // template is in use test
+    session.setSchemaTemplate("template1", "root.sg.1");
+
+    String deviceId = "root.sg.1.cd";
+    List<String> measurements = new ArrayList<>();
+    List<TSDataType> types = new ArrayList<>();
+    measurements.add("s1");
+    measurements.add("s2");
+    measurements.add("s3");
+    types.add(TSDataType.INT64);
+    types.add(TSDataType.INT64);
+    types.add(TSDataType.INT64);
+
+    for (long time = 0; time < 5; time++) {
+      List<Object> values = new ArrayList<>();
+      values.add(1L);
+      values.add(2L);
+      values.add(3L);
+      session.insertRecord(deviceId, time, measurements, types, values);
+    }
+
+    try {
+      session.unsetSchemaTemplate("root.sg.1", "template1");
+      fail("No exception thrown.");
+    } catch (Exception e) {
+      assertEquals("326: Template is in use on root.sg.1.cd", e.getMessage());
+    }
+  }
 }
diff --git a/thrift/src/main/thrift/rpc.thrift 
b/thrift/src/main/thrift/rpc.thrift
index c9ed36b..f8ae06c 100644
--- a/thrift/src/main/thrift/rpc.thrift
+++ b/thrift/src/main/thrift/rpc.thrift
@@ -369,6 +369,12 @@ struct TSCreateSchemaTemplateReq {
   7: required list<i32> compressors
 }
 
+struct TSUnsetSchemaTemplateReq {
+  1: required i64 sessionId
+  2: required string prefixPath
+  3: required string templateName
+}
+
 service TSIService {
   TSOpenSessionResp openSession(1:TSOpenSessionReq req);
 
@@ -447,4 +453,6 @@ service TSIService {
   TSStatus createSchemaTemplate(1:TSCreateSchemaTemplateReq req);
 
   TSStatus setSchemaTemplate(1:TSSetSchemaTemplateReq req);
-}
+
+  TSStatus unsetSchemaTemplate(1:TSUnsetSchemaTemplateReq req);
+}
\ No newline at end of file

Reply via email to