This is an automated email from the ASF dual-hosted git repository.
qiaojialin pushed a commit to branch rel/0.13
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/rel/0.13 by this push:
new a64d0426de [To rel/0.13]Deactivation and Privilege for Schema Template
(#6417)
a64d0426de is described below
commit a64d0426de4e0786b3b8d756ddef001b3573eabb
Author: ZhaoXin <[email protected]>
AuthorDate: Tue Jun 28 10:41:23 2022 +0800
[To rel/0.13]Deactivation and Privilege for Schema Template (#6417)
---
.../org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 | 7 +-
.../antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4 | 12 ++
docs/UserGuide/API/Programming-Java-Native-API.md | 24 ++-
.../Administration-Management/Administration.md | 4 +-
docs/UserGuide/Data-Concept/Schema-Template.md | 2 +
docs/UserGuide/Operate-Metadata/Template.md | 14 +-
.../UserGuide/API/Programming-Java-Native-API.md | 23 ++-
.../Administration-Management/Administration.md | 4 +-
docs/zh/UserGuide/Data-Concept/Schema-Template.md | 16 +-
docs/zh/UserGuide/Operate-Metadata/Template.md | 15 +-
.../db/integration/IoTDBSchemaTemplateIT.java | 83 +++++++++
.../apache/iotdb/session/template/TemplateUT.java | 207 +++++++++++++++++++++
.../org/apache/iotdb/db/auth/AuthorityChecker.java | 10 +
.../apache/iotdb/db/auth/entity/PrivilegeType.java | 7 +-
.../org/apache/iotdb/db/metadata/MManager.java | 72 ++++++-
.../iotdb/db/metadata/logfile/MLogTxtWriter.java | 11 ++
.../iotdb/db/metadata/logfile/MLogWriter.java | 5 +
.../db/metadata/logfile/MetadataOperationType.java | 1 +
.../org/apache/iotdb/db/metadata/mtree/MTree.java | 47 ++++-
.../iotdb/db/metadata/template/Template.java | 2 +-
.../apache/iotdb/db/qp/constant/SQLConstant.java | 2 +
.../apache/iotdb/db/qp/executor/PlanExecutor.java | 55 ++++++
.../org/apache/iotdb/db/qp/logical/Operator.java | 4 +-
.../qp/logical/sys/DeactivateTemplateOperator.java | 60 ++++++
.../apache/iotdb/db/qp/physical/PhysicalPlan.java | 7 +-
.../db/qp/physical/sys/ActivateTemplatePlan.java | 6 +
.../db/qp/physical/sys/DeactivateTemplatePlan.java | 116 ++++++++++++
.../iotdb/db/qp/physical/sys/SetTemplatePlan.java | 10 +
.../db/qp/physical/sys/UnsetTemplatePlan.java | 10 +
.../apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java | 12 ++
.../db/service/thrift/impl/TSServiceImpl.java | 32 +++-
.../org/apache/iotdb/db/tools/mlog/MLogParser.java | 4 +
.../java/org/apache/iotdb/db/utils/AuthUtils.java | 1 +
.../org/apache/iotdb/db/metadata/TemplateTest.java | 146 +++++++++++++++
.../iotdb/db/qp/physical/InsertRowPlanTest.java | 40 ++++
.../java/org/apache/iotdb/session/Session.java | 6 +
.../apache/iotdb/session/SessionConnection.java | 17 ++
.../org/apache/iotdb/session/pool/SessionPool.java | 19 ++
thrift/src/main/thrift/rpc.thrift | 2 +
39 files changed, 1071 insertions(+), 44 deletions(-)
diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
index 73b4b0ae09..640b64575e 100644
--- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
+++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4
@@ -36,7 +36,7 @@ statement
ddlStatement
: setStorageGroup | createStorageGroup | createTimeseries
- | createSchemaTemplate | createTimeseriesOfSchemaTemplate
+ | createSchemaTemplate | createTimeseriesOfSchemaTemplate |
deactivateSchemaTemplate
| createFunction | createTrigger | createContinuousQuery | createSnapshot
| alterTimeseries | deleteStorageGroup | deleteTimeseries | deletePartition
| dropFunction | dropTrigger | dropContinuousQuery | dropSchemaTemplate
@@ -104,6 +104,11 @@ createTimeseriesOfSchemaTemplate
: CREATE TIMESERIES OF SCHEMA? TEMPLATE ON prefixPath
;
+// Inverse procedure of Create Timeseries Of Schema Template
+deactivateSchemaTemplate
+ : DEACTIVATE SCHEMA? TEMPLATE templateName=identifier FROM prefixPath
+ ;
+
// Create Function
createFunction
: CREATE FUNCTION udfName=identifier AS className=STRING_LITERAL
diff --git a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
index 89a4603ed0..23f8990e72 100644
--- a/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
+++ b/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4
@@ -498,6 +498,10 @@ TEMPLATES
: T E M P L A T E S
;
+DEACTIVATE
+ : D E A C T I V A T E
+ ;
+
TIME
: T I M E
;
@@ -697,6 +701,7 @@ PRIVILEGE_VALUE
| CREATE_ROLE | DELETE_ROLE | LIST_ROLE | GRANT_ROLE_PRIVILEGE |
REVOKE_ROLE_PRIVILEGE
| CREATE_FUNCTION | DROP_FUNCTION | CREATE_TRIGGER | DROP_TRIGGER |
START_TRIGGER | STOP_TRIGGER
| CREATE_CONTINUOUS_QUERY | DROP_CONTINUOUS_QUERY
+ | APPLY_TEMPLATE | UPDATE_TEMPLATE
;
SET_STORAGE_GROUP
@@ -803,6 +808,13 @@ DROP_CONTINUOUS_QUERY
: D R O P '_' C O N T I N U O U S '_' Q U E R Y
;
+APPLY_TEMPLATE
+ : A P P L Y '_' T E M P L A T E
+ ;
+
+UPDATE_TEMPLATE
+ : U P D A T E '_' T E M P L A T E
+ ;
/**
* 3. Operators
diff --git a/docs/UserGuide/API/Programming-Java-Native-API.md
b/docs/UserGuide/API/Programming-Java-Native-API.md
index 260ef3c76a..2f9d7e97f3 100644
--- a/docs/UserGuide/API/Programming-Java-Native-API.md
+++ b/docs/UserGuide/API/Programming-Java-Native-API.md
@@ -229,9 +229,9 @@ After measurement template created, you can edit the
template with belowed APIs.
**1. templates had been set could not be pruned**
-**2. templates will be activated until data points insert into correspoding
measurements**
+**2. templates will be activated on one node by data points insertion of
measurements within the template, or interface
`createTimeseriesOfSchemaTemplate`**
-**3. templates will not be shown by showtimeseries before activating**
+**3. templates will not be shown by showtimeseries before activated**
```java
// Add aligned measurements to a template
@@ -286,18 +286,18 @@ public List<String> showMeasurementsInTemplate(String
templateName);
public List<String> showMeasurementsInTemplate(String templateName, String
pattern);
```
-To implement schema template, you can set the measurement template named
'templateName' at path 'prefixPath'.
+To implement schema template, you can set the template named `templateName` at
path `prefixPath`.
**Please notice that, we strongly recommend not setting templates on the nodes
above the storage group to accommodate future updates and collaboration between
modules.**
``` java
-void setSchemaTemplate(String templateName, String prefixPath)
+void setSchemaTemplate(String templateName, String prefixPath);
```
-Before setting template, you should firstly create the template using
+Before setting template, you should first create the template using
```java
-void createSchemaTemplate(Template template)
+void createSchemaTemplate(Template template);
```
After setting template to a certain path, you can query for info about
template using belowed interface in session:
@@ -320,9 +320,17 @@ void unsetSchemaTemplate(String prefixPath, String
templateName);
public void dropSchemaTemplate(String templateName);
```
-Unset the measurement template named 'templateName' from path 'prefixPath'.
When you issue this interface, you should assure that there is a template named
'templateName' set at the path 'prefixPath'.
+Unset the measurement template named `templateName` from path `prefixPath`.
When you issue this interface, you should assure that there is such a template
set at the path.
-Attention: Unsetting the template named 'templateName' from node at path
'prefixPath' or descendant nodes which have already inserted records using
template is **not supported**.
+If the template had been activated on one node, you should deactivate from it
using the interface:
+
+```java
+public void deactivateTemplateOn(String templateName, String prefixPath);
+```
+
+The passing in `prefixPath` is a literal path without wildcard(`*`or`**`), or
a PathPattern to denote paths match the pattern.
+
+The deactivation of the template will delete the data of the timeseries which
is under the path of concatenation of path of the node and the measurements
inside the activatede template.
### Data Manipulation Interface (DML Interface)
diff --git a/docs/UserGuide/Administration-Management/Administration.md
b/docs/UserGuide/Administration-Management/Administration.md
index 24e97f58d6..323a46b69f 100644
--- a/docs/UserGuide/Administration-Management/Administration.md
+++ b/docs/UserGuide/Administration-Management/Administration.md
@@ -289,7 +289,7 @@ At the same time, changes to roles are immediately
reflected on all users who ow
|CREATE\_TIMESERIES|create timeseries; path dependent|
|INSERT\_TIMESERIES|insert data; path dependent|
|READ\_TIMESERIES|query data; path dependent|
-|DELETE\_TIMESERIES|delete data or timeseries; path dependent|
+|DELETE\_TIMESERIES|delete data or timeseries, deactivate template; path
dependent|
|DELETE\_STORAGE\_GROUP|delete storage groups; path dependent|
|CREATE\_USER|create users; path independent|
|DELETE\_USER|delete users; path independent|
@@ -312,6 +312,8 @@ At the same time, changes to roles are immediately
reflected on all users who ow
|STOP_TRIGGER|stop triggers; path dependent|
|CREATE_CONTINUOUS_QUERY|create continuous queries; path independent|
|DROP_CONTINUOUS_QUERY|drop continuous queries; path independent|
+|UPDATE_TEMPLATE|create, drop, append and prune schema template; path
independent|
+|APPLY_TEMPLATE|set, unset and activate schema template; path dependent|
### Username Restrictions
diff --git a/docs/UserGuide/Data-Concept/Schema-Template.md
b/docs/UserGuide/Data-Concept/Schema-Template.md
index abdc5c5c3f..9d589980ab 100644
--- a/docs/UserGuide/Data-Concept/Schema-Template.md
+++ b/docs/UserGuide/Data-Concept/Schema-Template.md
@@ -39,6 +39,8 @@ In the actual scenario, many entities collect the same
measurements, that is, th
Currently you can only set one schema template on a specific path. If there's
one schema template on one node, it will be forbidden to set any schema
template on the ancestors or descendants of this node. An entity will use it's
own schema template or ancestor's schema template.
+When one node is using the template had been set on to it or its ancestor, it
is compulsory to deactivate template on this node before to unset or drop it.
Deactivate the template on one node will delete data of the timeseries which is
presented by the combination of path of the node and measurements inside the
template.
+
**Please notice that, we strongly recommend not setting templates on the nodes
above the storage group to accommodate future updates and collaboration between
modules.**
In the following chapters of data definition language, data operation language
and Java Native Interface, various operations related to schema template will
be introduced one by one.
diff --git a/docs/UserGuide/Operate-Metadata/Template.md
b/docs/UserGuide/Operate-Metadata/Template.md
index a18b1f8e20..76eb1b98ee 100644
--- a/docs/UserGuide/Operate-Metadata/Template.md
+++ b/docs/UserGuide/Operate-Metadata/Template.md
@@ -171,7 +171,17 @@ The execution result is as follows:
+-----------+
```
-## Uset Schema Template
+## Deactivate SchemaTemplate
+
+If any data points had been inserted into the timeseries concatenated by the
path of the node and measurements inside activated template, or `create
timeseries of schema template` had been issued, you should deactivate template
on nodes before unset tempalte upon them.
+
+```shell
+IoTDB> deactivate schema template t1 from root.sg1.d1
+```
+
+This statement will detele corresponding data points as well.
+
+## Unset Schema Template
The SQL Statement for unsetting schema template is as follow:
@@ -179,8 +189,6 @@ The SQL Statement for unsetting schema template is as
follow:
IoTDB> unset schema template t1 from root.sg1.d1
```
-**Attention**: Unsetting the template from entities, which have already
inserted records using the template, is not supported.
-
## Drop Schema Template
The SQL Statement for dropping schema template is as follow:
diff --git a/docs/zh/UserGuide/API/Programming-Java-Native-API.md
b/docs/zh/UserGuide/API/Programming-Java-Native-API.md
index 1f7e378504..3747639ab2 100644
--- a/docs/zh/UserGuide/API/Programming-Java-Native-API.md
+++ b/docs/zh/UserGuide/API/Programming-Java-Native-API.md
@@ -174,7 +174,7 @@ boolean checkTimeseriesExists(String path)
#### 元数据模版
-* 创建元数据模板,可以通过先后创建 Template、MeasurementNode
的对象,描述模板内物理量结构与类型、编码方式、压缩方式等信息,并通过以下接口创建模板
+*
创建元数据模板,可以通过先后创建`Template`、`MeasurementNode`的对象,描述模板内物理量结构与类型、编码方式、压缩方式等信息,并通过以下接口创建模板
```java
public void createSchemaTemplate(Template template);
@@ -207,7 +207,7 @@ Class MeasurementNode extends Node {
}
```
-通过上述类的实例描述模板时,Template 内应当仅能包含单层的 MeasurementNode,具体可以参见如下示例:
+通过上述类的实例描述模板时,`Template`内应当仅能包含单层的`MeasurementNode`,具体可以参见如下示例:
```java
MeasurementNode nodeX = new MeasurementNode("x", TSDataType.FLOAT,
TSEncoding.RLE, CompressionType.SNAPPY);
@@ -278,7 +278,7 @@ public List<String> showMeasurementsInTemplate(String
templateName);
public List<String> showMeasurementsInTemplate(String templateName, String
pattern);
```
-*
将名为'templateName'的元数据模板挂载到'prefixPath'路径下,在执行这一步之前,你需要创建名为'templateName'的元数据模板
+*
将名为`templateName`的元数据模板挂载到'prefixPath'路径下,在执行这一步之前,你需要创建名为`templateName`的元数据模板
* **请注意,我们强烈建议您将模板设置在存储组或存储组下层的节点中,以更好地适配未来版本更新及各模块的协作**
``` java
@@ -306,10 +306,21 @@ void unsetSchemaTemplate(String prefixPath, String
templateName);
public void dropSchemaTemplate(String templateName);
```
-* 请注意,如果一个子树中有多个孩子节点需要使用模板,可以在其共同父母节点上使用 setSchemaTemplate
。而只有在已有数据点插入模板对应的物理量时,模板才会被设置为激活状态,进而被 show timeseries 等查询检测到。
-*
卸载'prefixPath'路径下的名为'templateName'的元数据模板。你需要保证给定的路径'prefixPath'下需要有名为'templateName'的元数据模板。
+* 请注意,如果一个子树中有多个孩子节点需要使用模板,可以在其共同父母节点上使用 `setSchemaTemplate`
。而只有在已有数据点插入模板对应的物理量,或使用以下接口激活模板,模板才会被设置为激活状态,进而被 `show timeseries` 等查询访问到。
-注意:目前不支持从曾经在'prefixPath'路径及其后代节点使用模板插入数据后(即使数据已被删除)卸载模板。
+```java
+public void createTimeseriesOfTemplateOnPath(String path);
+```
+
+*
卸载'prefixPath'路径下的名为`templateName`的元数据模板。你需要保证给定的路径`prefixPath`下需要有名为`templateName`的元数据模板。
+*
如果在挂载模板后,曾经在`prefixPath`路径及其后代节点使用模板插入数据后,或者使用了激活模板命令,那么在卸载模板之前,还要对所有已激活模板的节点使用以下接口解除模板:
+
+```java
+public void deactivateTemplateOn(String templateName, String prefixPath);
+```
+
+* 以上解除模板接口中,参数`prefixPath`如果含有通配符(`*`或`**`)则按 PathPattern
匹配目标路径,否则仅表达其字面量对应的路径。
+* 解除模板接口会删除对应节点按照模板中的序列写入的数据。
### 数据操作接口 DML
diff --git a/docs/zh/UserGuide/Administration-Management/Administration.md
b/docs/zh/UserGuide/Administration-Management/Administration.md
index 904863e438..c50fabcfa7 100644
--- a/docs/zh/UserGuide/Administration-Management/Administration.md
+++ b/docs/zh/UserGuide/Administration-Management/Administration.md
@@ -294,7 +294,7 @@ Eg: IoTDB > ALTER USER tempuser SET PASSWORD 'newpwd';
|CREATE\_TIMESERIES|创建时间序列。路径相关|
|INSERT\_TIMESERIES|插入数据。路径相关|
|READ\_TIMESERIES|查询数据。路径相关|
-|DELETE\_TIMESERIES|删除数据或时间序列。路径相关|
+|DELETE\_TIMESERIES|删除数据或时间序列,解除模板。路径相关|
|DELETE\_STORAGE\_GROUP|删除存储组。路径相关|
|CREATE\_USER|创建用户。路径无关|
|DELETE\_USER|删除用户。路径无关|
@@ -317,6 +317,8 @@ Eg: IoTDB > ALTER USER tempuser SET PASSWORD 'newpwd';
|STOP_TRIGGER|停止触发器。路径相关|
|CREATE_CONTINUOUS_QUERY|创建连续查询。路径无关|
|DROP_CONTINUOUS_QUERY|卸载连续查询。路径无关|
+|UPDATE_TEMPLATE|创建、删除、修改模板。路径无关。|
+|APPLY_TEMPLATE|挂载、卸载、激活模板。路径相关。|
### 用户名限制
diff --git a/docs/zh/UserGuide/Data-Concept/Schema-Template.md
b/docs/zh/UserGuide/Data-Concept/Schema-Template.md
index 353643c3d6..3da48f7c76 100644
--- a/docs/zh/UserGuide/Data-Concept/Schema-Template.md
+++ b/docs/zh/UserGuide/Data-Concept/Schema-Template.md
@@ -87,7 +87,7 @@ Class MeasurementNode extends Node {
}
```
-* 构造元数据模板
+* 构造与挂载元数据模板
构造上图中的元数据模板,并挂载到对应节点,可参考如下代码。**请注意,我们强烈建议您将模板设置在存储组或存储组下层的节点中,以更好地适配未来地更新及各模块的协作。**
@@ -107,4 +107,16 @@ createSchemaTemplate(template);
setSchemaTemplate("template", "root.Beijing");
```
-挂载元数据模板后,即可进行数据的写入。如按上述代码创建并挂载模板,并在 root.Beijing 路径上设置了存储组后,即可写入例如
root.Beijing.petro_vehicle.velocity 等时间序列数据,系统将自动创建 petro_vehicle
节点,并设置其“正在使用模板”,对写入数据应用模板中为 velocity 定义的元数据信息。
+**挂载元数据模板后,即可向挂载节点或该节点的子孙节点,按照模板的模式进行数据写入**。例如,按上述代码创建并挂载模板,并在 root.Beijing
路径上设置了存储组后,即可写入例如 root.Beijing.petro_vehicle.velocity 等时间序列数据,系统将自动创建
petro_vehicle 节点,并设置其“正在使用模板”,对写入数据应用模板中为 velocity 定义的元数据信息。
+
+* 修改、激活、解除、卸载与删除元数据模板
+
+在元数据模板相关的操作中,除了上文中提到的创建、挂载,还有一些高级功能可以使用。具体细节可以参考[编程接口说明](../API/Programming-Java-Native-API.md)和[SQL命令说明](../Operate-Metadata/Template.md),在此仅对其主要概念进行简要介绍。
+
+创建元数据模板后,还可以增加或删除模板中的节点。需要注意的是,一旦模板被挂载,在卸载模板之前就不再允许从模板中删除节点。
+
+对于挂载了模板的节点或其子孙节点,可以通过相应接口激活模板。**对挂载模板与激活模板的状态进行区分,是为了服务一种常见的场景**:在 Apache
IoTDB 元数据模型 MTree
中,经常需要在数量众多的节点上“应用”元数据模板,而这些节点一般拥有共同的祖先节点。因此,可以在其共同祖先节点**挂载**模板,而不必对其大量的孩子节点进行挂载操作。对于需要“应用”模板的节点,则应该使用**激活模板**的操作。
+
+解除与卸载模板,分别是激活与挂载模板的逆过程。**其中,对一个节点解除模板还会删除该节点在模板中的序列写入的数据。**需要注意的是,如果一个挂载了模板的节点或其子孙节点,当前已经激活了模板,那么在解除激活之前,该节点就不能卸载模板。类似地,如果有任意一个节点挂载了模板,那么在其卸载之前,模板就不能被删除。
+
+上述功能均有对应权限进行控制,具体可以参见[权限管理](../Administration-Management/Administration.md)。
diff --git a/docs/zh/UserGuide/Operate-Metadata/Template.md
b/docs/zh/UserGuide/Operate-Metadata/Template.md
index 90d58332a3..93e1218f2d 100644
--- a/docs/zh/UserGuide/Operate-Metadata/Template.md
+++ b/docs/zh/UserGuide/Operate-Metadata/Template.md
@@ -171,6 +171,16 @@ IoTDB> show paths using schema template t1
+-----------+
```
+## 解除元数据模板
+
+对于挂载了元数据模板的节点或其孩子节点,如果:1)曾按模板中的序列写入了数据,或2)使用了 `create timeseries of schema
template`,则在使用以下命令之前,不能够卸载或删除元数据模板:
+
+```shell
+IoTDB> deactivate schema template t1 from root.sg.d1
+```
+
+**注意**:这一操作会删除对应节点下按照模板中的序列写入的数据。
+
## 卸载元数据模板
卸载元数据模板的 SQL 语句如下所示:
@@ -179,8 +189,6 @@ IoTDB> show paths using schema template t1
IoTDB> unset schema template t1 from root.sg1.d1
```
-**注意**:目前不支持从曾经使用模板插入数据后(即使数据已被删除)的实体中卸载模板。
-
## 删除元数据模板
删除元数据模板的 SQL 语句如下所示:
@@ -189,4 +197,5 @@ IoTDB> unset schema template t1 from root.sg1.d1
IoTDB> drop schema template t1
```
-**注意**:不支持删除已经挂载的模板。
+**注意**:不能删除尚未卸载的模板。
+
diff --git
a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBSchemaTemplateIT.java
b/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBSchemaTemplateIT.java
index fd0856d074..8e507dab17 100644
---
a/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBSchemaTemplateIT.java
+++
b/integration/src/test/java/org/apache/iotdb/db/integration/IoTDBSchemaTemplateIT.java
@@ -316,6 +316,89 @@ public class IoTDBSchemaTemplateIT {
Assert.assertFalse(resultSet.next());
}
+ @Test
+ public void testDeactivateSchemaTemplate() throws SQLException {
+ statement.execute("SET SCHEMA TEMPLATE t1 TO root.sg1.v1");
+ statement.execute("CREATE TIMESERIES OF SCHEMA TEMPLATE ON root.sg1.v1");
+ statement.execute("CREATE TIMESERIES OF SCHEMA TEMPLATE ON
root.sg1.v1.dd1");
+ statement.execute("CREATE TIMESERIES OF SCHEMA TEMPLATE ON
root.sg1.v1.dd2");
+ statement.execute("CREATE TIMESERIES OF SCHEMA TEMPLATE ON
root.sg1.v1.x1.dd2");
+
+ statement.execute("SHOW PATHS USING SCHEMA TEMPLATE t1");
+ String[] expectedResult =
+ new String[] {"root.sg1.v1", "root.sg1.v1.dd1", "root.sg1.v1.dd2",
"root.sg1.v1.x1.dd2"};
+ Set<String> expectedResultSet = new
HashSet<>(Arrays.asList(expectedResult));
+ try (ResultSet resultSet = statement.getResultSet()) {
+ while (resultSet.next()) {
+
Assert.assertTrue(expectedResultSet.contains(resultSet.getString("child
paths")));
+ expectedResultSet.remove(resultSet.getString("child paths"));
+ }
+ }
+ Assert.assertEquals(0, expectedResultSet.size());
+
+ statement.execute("DEACTIVATE SCHEMA TEMPLATE t1 FROM root.sg1.v1.dd1");
+ statement.execute("SHOW PATHS USING SCHEMA TEMPLATE t1");
+ expectedResult = new String[] {"root.sg1.v1", "root.sg1.v1.dd2",
"root.sg1.v1.x1.dd2"};
+ expectedResultSet = new HashSet<>(Arrays.asList(expectedResult));
+ try (ResultSet resultSet = statement.getResultSet()) {
+ while (resultSet.next()) {
+
Assert.assertTrue(expectedResultSet.contains(resultSet.getString("child
paths")));
+ expectedResultSet.remove(resultSet.getString("child paths"));
+ }
+ }
+ Assert.assertEquals(0, expectedResultSet.size());
+
+ statement.execute("DEACTIVATE SCHEMA TEMPLATE t1 FROM root.sg1.v1.*");
+ statement.execute("SHOW PATHS USING SCHEMA TEMPLATE t1");
+ expectedResult = new String[] {"root.sg1.v1", "root.sg1.v1.x1.dd2"};
+ expectedResultSet = new HashSet<>(Arrays.asList(expectedResult));
+ try (ResultSet resultSet = statement.getResultSet()) {
+ while (resultSet.next()) {
+
Assert.assertTrue(expectedResultSet.contains(resultSet.getString("child
paths")));
+ expectedResultSet.remove(resultSet.getString("child paths"));
+ }
+ }
+ Assert.assertEquals(0, expectedResultSet.size());
+
+ statement.execute("DEACTIVATE SCHEMA TEMPLATE t1 FROM root.sg1.v1.**");
+ statement.execute("SHOW PATHS USING SCHEMA TEMPLATE t1");
+ expectedResult = new String[] {"root.sg1.v1"};
+ expectedResultSet = new HashSet<>(Arrays.asList(expectedResult));
+ try (ResultSet resultSet = statement.getResultSet()) {
+ while (resultSet.next()) {
+
Assert.assertTrue(expectedResultSet.contains(resultSet.getString("child
paths")));
+ expectedResultSet.remove(resultSet.getString("child paths"));
+ }
+ }
+ Assert.assertEquals(0, expectedResultSet.size());
+
+ statement.execute("DEACTIVATE SCHEMA TEMPLATE t1 FROM root.sg1.v1");
+ statement.execute("SHOW PATHS USING SCHEMA TEMPLATE t1");
+ expectedResult = new String[] {};
+ expectedResultSet = new HashSet<>(Arrays.asList(expectedResult));
+ try (ResultSet resultSet = statement.getResultSet()) {
+ while (resultSet.next()) {
+
Assert.assertTrue(expectedResultSet.contains(resultSet.getString("child
paths")));
+ expectedResultSet.remove(resultSet.getString("child paths"));
+ }
+ }
+ Assert.assertEquals(0, expectedResultSet.size());
+
+ statement.execute("UNSET SCHEMA TEMPLATE t1 FROM root.sg1.v1");
+ statement.execute("DROP SCHEMA TEMPLATE t1");
+ statement.execute("SHOW SCHEMA TEMPLATES");
+
+ expectedResult = new String[] {"t2"};
+ expectedResultSet = new HashSet<>(Arrays.asList(expectedResult));
+ try (ResultSet resultSet = statement.getResultSet()) {
+ while (resultSet.next()) {
+
Assert.assertTrue(expectedResultSet.contains(resultSet.getString("template
name")));
+ expectedResultSet.remove(resultSet.getString("template name"));
+ }
+ }
+ Assert.assertEquals(0, expectedResultSet.size());
+ }
+
private void prepareTemplate() throws SQLException {
// create storage group
statement.execute("CREATE STORAGE GROUP root.sg1");
diff --git
a/integration/src/test/java/org/apache/iotdb/session/template/TemplateUT.java
b/integration/src/test/java/org/apache/iotdb/session/template/TemplateUT.java
index 93a2f66833..9adcbbdc4e 100644
---
a/integration/src/test/java/org/apache/iotdb/session/template/TemplateUT.java
+++
b/integration/src/test/java/org/apache/iotdb/session/template/TemplateUT.java
@@ -22,6 +22,7 @@ import org.apache.iotdb.db.conf.IoTDBConstant;
import org.apache.iotdb.db.exception.metadata.MetadataException;
import org.apache.iotdb.db.qp.physical.sys.CreateTemplatePlan;
import org.apache.iotdb.db.utils.EnvironmentUtils;
+import org.apache.iotdb.rpc.BatchExecutionException;
import org.apache.iotdb.rpc.IoTDBConnectionException;
import org.apache.iotdb.rpc.StatementExecutionException;
import org.apache.iotdb.session.Session;
@@ -396,6 +397,212 @@ public class TemplateUT {
}
}
+ @Test
+ public void testUnsetTemplate()
+ throws StatementExecutionException, IoTDBConnectionException,
IOException {
+ Template temp1 = getTemplate("template1");
+ session.createSchemaTemplate(temp1);
+ session.setSchemaTemplate("template1", "root.sg.v1");
+ session.createTimeseriesOfTemplateOnPath("root.sg.v1.l1.d1");
+
+ try {
+ session.executeNonQueryStatement("delete timeseries root.sg.v1.l1.d1.x");
+ fail();
+ } catch (BatchExecutionException e) {
+ }
+
+ // wildcard usage on prefix
+ session.deactivateTemplateOn("template1", "root");
+ assertEquals(1, session.showPathsTemplateUsingOn("template1").size());
+
+ session.deactivateTemplateOn("template1", "root.*");
+ assertEquals(1, session.showPathsTemplateUsingOn("template1").size());
+
+ session.deactivateTemplateOn("template1", "root.**");
+ assertEquals(0, session.showPathsTemplateUsingOn("template1").size());
+
+ session.createTimeseriesOfTemplateOnPath("root.sg.v1.l1.d1");
+ assertEquals(1, session.showPathsTemplateUsingOn("template1").size());
+
+ session.deactivateTemplateOn("template1", "root.sg.v1.l1.d1.*");
+ assertEquals(1, session.showPathsTemplateUsingOn("template1").size());
+
+ session.deactivateTemplateOn("template1", "root.sg.v1.l1.d1.**");
+ assertEquals(1, session.showPathsTemplateUsingOn("template1").size());
+
+ session.deactivateTemplateOn("template1", "root.sg.v1.l1.d1");
+ assertEquals(0, session.showPathsTemplateUsingOn("template1").size());
+
+ session.deactivateTemplateOn("template1", "root.sg.v1.l1.d1");
+ session.unsetSchemaTemplate("root.sg.v1", "template1");
+ assertEquals(0, session.showPathsTemplateSetOn("template1").size());
+ session.dropSchemaTemplate("template1");
+ assertEquals(0, session.showAllTemplates().size());
+
+ // data delete and rewrite
+ session.createSchemaTemplate(temp1);
+ session.setSchemaTemplate("template1", "root.sg.v1");
+ session.createTimeseriesOfTemplateOnPath("root.sg.v1");
+ session.insertAlignedRecord(
+ "root.sg.v1", 11L, Collections.singletonList("x"),
Collections.singletonList("1.1"));
+ SessionDataSet sds = session.executeQueryStatement("select * from
root.sg.v1");
+ int cnt = 0;
+ while (sds.hasNext()) {
+ cnt++;
+ sds.next();
+ }
+ assertEquals(1, cnt);
+ session.deactivateTemplateOn("template1", "root.**");
+
+ sds = session.executeQueryStatement("select * from root.sg.v1");
+ cnt = 0;
+ while (sds.hasNext()) {
+ cnt++;
+ sds.next();
+ }
+ assertEquals(0, cnt);
+
+ try {
+ session.insertAlignedRecord(
+ "root.sg.v1", 999L, Collections.singletonList("x"),
Collections.singletonList("abcd"));
+ fail();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ try {
+ session.insertRecord(
+ "root.sg.v1", 999L, Collections.singletonList("x"),
Collections.singletonList("abcd"));
+ fail();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ session.deactivateTemplateOn("template1", "root.**");
+ session.unsetSchemaTemplate("root.sg.v1", "template1");
+ session.insertAlignedRecord(
+ "root.sg.v1", 911L, Collections.singletonList("x"),
Collections.singletonList("abcd"));
+
+ sds = session.executeQueryStatement("select * from root.sg.v1");
+ cnt = 0;
+ while (sds.hasNext()) {
+ cnt++;
+ assertEquals("abcd", sds.next().getFields().get(0).toString());
+ }
+ assertEquals(1, cnt);
+ }
+
+ @Test
+ public void testTemplatePrivilege() throws Exception {
+ session.executeNonQueryStatement("CREATE USER tpl_user 'tpl_pwd'");
+ Session nSession = new Session("127.0.0.1", 6667, "tpl_user", "tpl_pwd",
ZoneId.of("+05:00"));
+ nSession.open();
+ try {
+ nSession.createSchemaTemplate(getTemplate("t1"));
+ } catch (Exception e) {
+ assertEquals("602: No permissions for this operation CREATE_TEMPLATE",
e.getMessage());
+ }
+
+ session.executeNonQueryStatement(
+ "grant user tpl_user privileges UPDATE_TEMPLATE on root.irrelevant");
+ nSession.createSchemaTemplate(getTemplate("t1"));
+ nSession.createSchemaTemplate(getTemplate("t2"));
+ assertEquals(2, nSession.showAllTemplates().size());
+ nSession.dropSchemaTemplate("t2");
+ assertEquals(1, nSession.showAllTemplates().size());
+
+ try {
+ nSession.setSchemaTemplate("t1", "root.sg2.d1");
+ } catch (Exception e) {
+ assertEquals("602: No permissions for this operation SET_TEMPLATE",
e.getMessage());
+ }
+
+ session.executeNonQueryStatement("grant user tpl_user privileges
APPLY_TEMPLATE on root.sg1");
+ try {
+ nSession.setSchemaTemplate("t1", "root.sg2.d1");
+ } catch (Exception e) {
+ assertEquals("602: No permissions for this operation SET_TEMPLATE",
e.getMessage());
+ }
+
+ session.executeNonQueryStatement("grant user tpl_user privileges
APPLY_TEMPLATE on root.sg2");
+ nSession.setSchemaTemplate("t1", "root.sg1.d1");
+ nSession.setSchemaTemplate("t1", "root.sg2.d1");
+ nSession.createTimeseriesOfTemplateOnPath("root.sg1.d1.v1");
+ nSession.createTimeseriesOfTemplateOnPath("root.sg2.d1.v1");
+
+ try {
+ nSession.deactivateTemplateOn("t1", "root.sg1.d1.*");
+ } catch (Exception e) {
+ assertEquals("602: No permissions for this operation
DEACTIVATE_TEMPLATE", e.getMessage());
+ }
+
+ session.close();
+ nSession.close();
+ EnvironmentUtils.restartDaemon();
+
+ session = new Session("127.0.0.1", 6667, "root", "root",
ZoneId.of("+05:00"));
+ nSession = new Session("127.0.0.1", 6667, "tpl_user", "tpl_pwd",
ZoneId.of("+05:00"));
+ session.open();
+ nSession.open();
+ assertEquals(2, nSession.showPathsTemplateUsingOn("t1").size());
+
+ session.executeNonQueryStatement(
+ "grant user tpl_user privileges DELETE_TIMESERIES on root.sg2");
+ nSession.deactivateTemplateOn("t1", "root.sg2.**");
+ assertEquals(1, nSession.showPathsTemplateUsingOn("t1").size());
+
+ try {
+ nSession.deactivateTemplateOn("t1", "root.sg1.d1.*");
+ } catch (Exception e) {
+ assertEquals("602: No permissions for this operation
DEACTIVATE_TEMPLATE", e.getMessage());
+ }
+
+ session.executeNonQueryStatement(
+ "grant user tpl_user privileges DELETE_TIMESERIES on root.sg1");
+ nSession.deactivateTemplateOn("t1", "root.sg1.**");
+ assertEquals(0, nSession.showPathsTemplateUsingOn("t1").size());
+ nSession.unsetSchemaTemplate("root.sg1.d1", "t1");
+ nSession.unsetSchemaTemplate("root.sg2.d1", "t1");
+ nSession.dropSchemaTemplate("t1");
+ assertEquals(0, nSession.showAllTemplates().size());
+
+ session.close();
+ nSession.close();
+ EnvironmentUtils.restartDaemon();
+
+ session = new Session("127.0.0.1", 6667, "root", "root",
ZoneId.of("+05:00"));
+ nSession = new Session("127.0.0.1", 6667, "tpl_user", "tpl_pwd",
ZoneId.of("+05:00"));
+ session.open();
+ nSession.open();
+ assertEquals(0, nSession.showAllTemplates().size());
+
+ nSession.close();
+ }
+
+ @Test
+ public void testUnsetTemplateSQL()
+ throws StatementExecutionException, IoTDBConnectionException,
IOException {
+ session.createSchemaTemplate(getTemplate("template1"));
+ session.setSchemaTemplate("template1", "root.sg.v1");
+ session.createTimeseriesOfTemplateOnPath("root.sg.v1.dd1");
+ session.executeNonQueryStatement("deactivate schema template template1
from root.sg.v1.dd1");
+ assertEquals(0, session.showPathsTemplateUsingOn("template1").size());
+
+ session.createTimeseriesOfTemplateOnPath("root.sg.v1.dd2");
+ session.createTimeseriesOfTemplateOnPath("root.sg.v1.dd3");
+ session.createTimeseriesOfTemplateOnPath("root.sg.v1.g1.d1");
+ assertEquals(3, session.showPathsTemplateUsingOn("template1").size());
+
+ session.executeNonQueryStatement("deactivate schema template template1
from root.sg.v1.*");
+ assertEquals(1, session.showPathsTemplateUsingOn("template1").size());
+
+ session.executeNonQueryStatement("deactivate schema template template1
from root.sg.v1.**");
+ assertEquals(0, session.showPathsTemplateUsingOn("template1").size());
+ session.unsetSchemaTemplate("root.sg.v1", "template1");
+ session.dropSchemaTemplate("template1");
+ assertEquals(0, session.showAllTemplates().size());
+ }
+
@Test
public void testActivateTemplate()
throws StatementExecutionException, IoTDBConnectionException,
IOException {
diff --git
a/server/src/main/java/org/apache/iotdb/db/auth/AuthorityChecker.java
b/server/src/main/java/org/apache/iotdb/db/auth/AuthorityChecker.java
index 6a144118bc..6abf4e7088 100644
--- a/server/src/main/java/org/apache/iotdb/db/auth/AuthorityChecker.java
+++ b/server/src/main/java/org/apache/iotdb/db/auth/AuthorityChecker.java
@@ -123,6 +123,7 @@ public class AuthorityChecker {
case CREATE_ALIGNED_TIMESERIES:
return PrivilegeType.CREATE_TIMESERIES.ordinal();
case DELETE_TIMESERIES:
+ case DEACTIVATE_TEMPLATE:
case DELETE:
case DROP_INDEX:
return PrivilegeType.DELETE_TIMESERIES.ordinal();
@@ -170,6 +171,15 @@ public class AuthorityChecker {
return PrivilegeType.CREATE_CONTINUOUS_QUERY.ordinal();
case DROP_CONTINUOUS_QUERY:
return PrivilegeType.DROP_CONTINUOUS_QUERY.ordinal();
+ case CREATE_TEMPLATE:
+ case APPEND_TEMPLATE:
+ case DROP_TEMPLATE:
+ case PRUNE_TEMPLATE:
+ return PrivilegeType.UPDATE_TEMPLATE.ordinal();
+ case ACTIVATE_TEMPLATE:
+ case SET_TEMPLATE:
+ case UNSET_TEMPLATE:
+ return PrivilegeType.APPLY_TEMPLATE.ordinal();
default:
logger.error("Unrecognizable operator type ({}) for
AuthorityChecker.", type);
return -1;
diff --git
a/server/src/main/java/org/apache/iotdb/db/auth/entity/PrivilegeType.java
b/server/src/main/java/org/apache/iotdb/db/auth/entity/PrivilegeType.java
index 262183424c..ce233da788 100644
--- a/server/src/main/java/org/apache/iotdb/db/auth/entity/PrivilegeType.java
+++ b/server/src/main/java/org/apache/iotdb/db/auth/entity/PrivilegeType.java
@@ -48,7 +48,9 @@ public enum PrivilegeType {
STOP_TRIGGER,
CREATE_CONTINUOUS_QUERY,
DROP_CONTINUOUS_QUERY,
- ALL;
+ ALL,
+ UPDATE_TEMPLATE,
+ APPLY_TEMPLATE;
/**
* Some privileges need a seriesPath as parameter, while others do not. This
method returns which
@@ -59,6 +61,7 @@ public enum PrivilegeType {
*/
public static boolean isPathRelevant(int type) {
return type <= DELETE_TIMESERIES.ordinal()
- || (CREATE_TRIGGER.ordinal() <= type && type <=
STOP_TRIGGER.ordinal());
+ || (CREATE_TRIGGER.ordinal() <= type && type <= STOP_TRIGGER.ordinal())
+ || type == APPLY_TEMPLATE.ordinal();
}
}
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 1784e782f7..dfea8addf6 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
@@ -67,6 +67,7 @@ import
org.apache.iotdb.db.qp.physical.sys.ChangeTagOffsetPlan;
import org.apache.iotdb.db.qp.physical.sys.CreateAlignedTimeSeriesPlan;
import org.apache.iotdb.db.qp.physical.sys.CreateTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
+import org.apache.iotdb.db.qp.physical.sys.DeactivateTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.DeleteStorageGroupPlan;
import org.apache.iotdb.db.qp.physical.sys.DeleteTimeSeriesPlan;
import org.apache.iotdb.db.qp.physical.sys.DropTemplatePlan;
@@ -122,6 +123,7 @@ import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Collectors;
import static org.apache.iotdb.db.conf.IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD;
import static
org.apache.iotdb.db.utils.EncodingInferenceUtils.getDefaultEncoding;
@@ -524,6 +526,16 @@ public class MManager {
ActivateTemplatePlan activateTemplatePlan = (ActivateTemplatePlan)
plan;
setUsingSchemaTemplate(activateTemplatePlan);
break;
+ case DEACTIVATE_TEMPLATE:
+ DeactivateTemplatePlan deactivateTemplatePlan =
(DeactivateTemplatePlan) plan;
+ deactivateTemplatePlan.setPaths(
+ new ArrayList<>(
+ getPathsUsingTemplateUnderPrefix(
+ deactivateTemplatePlan.getTemplateName(),
+ deactivateTemplatePlan.getPrefixPath().getFullPath(),
+ false)));
+ deactivateSchemaTemplate(deactivateTemplatePlan);
+ break;
case AUTO_CREATE_DEVICE_MNODE:
AutoCreateDeviceMNodePlan autoCreateDeviceMNodePlan =
(AutoCreateDeviceMNodePlan) plan;
autoCreateDeviceMNode(autoCreateDeviceMNodePlan);
@@ -2279,10 +2291,29 @@ public class MManager {
: new
HashSet<>(mtree.getPathsSetOnTemplate(templateManager.getTemplate(templateName)));
}
+ /** A shortcut mainly for viewing paths using template. */
public Set<String> getPathsUsingTemplate(String templateName) throws
MetadataException {
return templateName.equals(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD)
- ? new HashSet<>(mtree.getPathsUsingTemplate(null))
- : new
HashSet<>(mtree.getPathsUsingTemplate(templateManager.getTemplate(templateName)));
+ ? new HashSet<>(mtree.getPathsUsingTemplateUnderPrefix(null, null,
true))
+ .stream().map(PartialPath::getFullPath).collect(Collectors.toSet())
+ : new HashSet<>(
+ mtree.getPathsUsingTemplateUnderPrefix(
+ templateManager.getTemplate(templateName), null, true))
+
.stream().map(PartialPath::getFullPath).collect(Collectors.toSet());
+ }
+
+ /**
+ * Complete filter of paths using template, detail at {@link
+ * MTree#getPathsUsingTemplateUnderPrefix}
+ */
+ public Set<PartialPath> getPathsUsingTemplateUnderPrefix(
+ String templateName, String prefix, boolean prefixMatch) throws
MetadataException {
+ return templateName.equals(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD)
+ ? new HashSet<>(
+ mtree.getPathsUsingTemplateUnderPrefix(null, new
PartialPath(prefix), prefixMatch))
+ : new HashSet<>(
+ mtree.getPathsUsingTemplateUnderPrefix(
+ templateManager.getTemplate(templateName), new
PartialPath(prefix), prefixMatch));
}
public void dropSchemaTemplate(DropTemplatePlan plan) throws
MetadataException {
@@ -2380,6 +2411,43 @@ public class MManager {
}
}
+ public void deactivateSchemaTemplate(DeactivateTemplatePlan plan) throws
MetadataException {
+ if (plan.getPaths() == null || plan.getPaths().size() == 0) {
+ logger.warn(
+ "No actual paths to deactivate with template [{}] on prefix [{}].",
+ plan.getTemplateName(),
+ plan.getPrefixPath().getFullPath());
+ return;
+ }
+
+ IMNode node;
+ for (PartialPath path : plan.getPaths()) {
+ node = mtree.getNodeByPath(path);
+
+ if (node.isMeasurement()) {
+ throw new MetadataException(
+ String.format(
+ "[%s] cannot be applied to deactivate template as a
measurement.",
+ path.getFullPath()));
+ }
+
+ node.setUseTemplate(false);
+ // clear caches within MManger
+ mNodeCache.invalidate(node);
+ if (node.isEntity()) {
+ node.getAsEntityMNode().getTemplateLastCaches().clear();
+ }
+ }
+
+ if (!isRecovering) {
+ try {
+ logWriter.deactivateSchemaTemplate(plan);
+ } catch (IOException e) {
+ throw new MetadataException(e);
+ }
+ }
+ }
+
IMNode setUsingSchemaTemplate(IMNode node) throws MetadataException {
// check whether any template has been set on designated path
if (node.getUpperTemplate() == null) {
diff --git
a/server/src/main/java/org/apache/iotdb/db/metadata/logfile/MLogTxtWriter.java
b/server/src/main/java/org/apache/iotdb/db/metadata/logfile/MLogTxtWriter.java
index c9660562df..7b7438df57 100644
---
a/server/src/main/java/org/apache/iotdb/db/metadata/logfile/MLogTxtWriter.java
+++
b/server/src/main/java/org/apache/iotdb/db/metadata/logfile/MLogTxtWriter.java
@@ -26,6 +26,7 @@ import
org.apache.iotdb.db.qp.physical.sys.CreateAlignedTimeSeriesPlan;
import org.apache.iotdb.db.qp.physical.sys.CreateContinuousQueryPlan;
import org.apache.iotdb.db.qp.physical.sys.CreateTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
+import org.apache.iotdb.db.qp.physical.sys.DeactivateTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.DropContinuousQueryPlan;
import org.apache.iotdb.db.qp.physical.sys.DropTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.MNodePlan;
@@ -369,6 +370,16 @@ public class MLogTxtWriter implements AutoCloseable {
lineNumber.incrementAndGet();
}
+ public void deactivateTemplate(DeactivateTemplatePlan plan) throws
IOException {
+ StringBuilder buf = new
StringBuilder((MetadataOperationType.UNSET_USING_TEMPLATE));
+ buf.append(",");
+ buf.append(plan.getPrefixPath().getFullPath());
+ buf.append(LINE_SEPARATOR);
+ ByteBuffer buff = ByteBuffer.wrap(buf.toString().getBytes());
+ channel.write(buff);
+ lineNumber.incrementAndGet();
+ }
+
public void createSchemaTemplate(CreateTemplatePlan plan) throws IOException
{
// CreateTemplatePlan txt Log be like:
//
OperationType,templateName[,measurementPath,isAlign,dataType,encoding,compressor]
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 789be2f8c2..15aa3a704c 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
@@ -34,6 +34,7 @@ import
org.apache.iotdb.db.qp.physical.sys.ChangeTagOffsetPlan;
import org.apache.iotdb.db.qp.physical.sys.CreateAlignedTimeSeriesPlan;
import org.apache.iotdb.db.qp.physical.sys.CreateTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
+import org.apache.iotdb.db.qp.physical.sys.DeactivateTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.DeleteStorageGroupPlan;
import org.apache.iotdb.db.qp.physical.sys.DeleteTimeSeriesPlan;
import org.apache.iotdb.db.qp.physical.sys.DropTemplatePlan;
@@ -222,6 +223,10 @@ public class MLogWriter implements AutoCloseable {
putLog(plan);
}
+ public void deactivateSchemaTemplate(DeactivateTemplatePlan plan) throws
IOException {
+ putLog(plan);
+ }
+
public synchronized void clear() throws IOException {
sync();
logWriter.close();
diff --git
a/server/src/main/java/org/apache/iotdb/db/metadata/logfile/MetadataOperationType.java
b/server/src/main/java/org/apache/iotdb/db/metadata/logfile/MetadataOperationType.java
index 672a4ec5d7..8b2e1662b2 100644
---
a/server/src/main/java/org/apache/iotdb/db/metadata/logfile/MetadataOperationType.java
+++
b/server/src/main/java/org/apache/iotdb/db/metadata/logfile/MetadataOperationType.java
@@ -42,6 +42,7 @@ public class MetadataOperationType {
public static final String SET_TEMPLATE = "6";
public static final String UNSET_TEMPLATE = "69";
public static final String SET_USING_TEMPLATE = "61";
+ public static final String UNSET_USING_TEMPLATE = "62";
public static final String APPEND_TEMPLATE = "51";
public static final String PRUNE_TEMPLATE = "52";
public static final String DROP_TEMPLATE = "59";
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 dac5640dee..3b986e2924 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
@@ -107,6 +107,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
import static java.util.stream.Collectors.toList;
+import static org.apache.iotdb.db.conf.IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD;
import static org.apache.iotdb.db.conf.IoTDBConstant.ONE_LEVEL_PATH_WILDCARD;
import static
org.apache.iotdb.db.metadata.lastCache.LastCacheManager.getLastTimeStamp;
@@ -1779,11 +1780,8 @@ public class MTree implements Serializable {
protected boolean processFullMatchedMNode(IMNode node, int idx,
int level)
throws MetadataException {
// shall not traverse nodes inside template
- if (!node.getPartialPath().equals(getCurrentPartialPath(node))) {
- return true;
- }
-
- if (node.isMeasurement()) {
+ if (node.isMeasurement()
+ ||
!node.getPartialPath().equals(getCurrentPartialPath(node))) {
return true;
}
@@ -1806,13 +1804,44 @@ public class MTree implements Serializable {
return resSet;
}
- public List<String> getPathsUsingTemplate(Template template) throws
MetadataException {
+ /**
+ * Notice that wildcards do not semantically equal prefix match. E.g.,
prefix match for a.b.c
+ * always includes itself, while neither one level nor multi level wildcard
does so.
+ *
+ * <p>When it comes to delete one time series, it is necessary to make a
more cautious filtering
+ * which requires explicit designation by wildcards, unlike viewing some
paths about.
+ *
+ * <p><b>Incidentally, ANY wildcard in prefix will DISABLE prefix mode.</b>
And a combination of
+ * non-wildcard prefix and disabled prefix mode implies an exact match.
+ *
+ * @return may include prefix itself if prefixMode is true, otherwise
exclude itself
+ */
+ public List<PartialPath> getPathsUsingTemplateUnderPrefix(
+ Template template, PartialPath prefix, boolean prefixMode) throws
MetadataException {
+ // enable prefix match by default, disabled if contains any wildcard
+ boolean containWildcard =
+ prefix != null
+ &&
(Arrays.asList(prefix.getNodes()).contains(ONE_LEVEL_PATH_WILDCARD)
+ ||
Arrays.asList(prefix.getNodes()).contains(MULTI_LEVEL_PATH_WILDCARD));
+
String templateName = template == null ? ONE_LEVEL_PATH_WILDCARD :
template.getName();
Set<PartialPath> initPath =
template == null
? Collections.singleton(new PartialPath("root"))
: template.getRelatedStorageGroup();
- List<String> result = new ArrayList<>();
+ List<PartialPath> result = new ArrayList<>();
+
+ // start with given prefix if any related sg matches or set initPath null
if not
+ if (prefix != null) {
+ initPath =
+ initPath.stream().anyMatch(p -> p.matchPrefixPath(prefix) ||
prefix.matchPrefixPath(p))
+ ? Collections.singleton(prefix)
+ : null;
+ }
+
+ if (initPath == null || initPath.size() == 0) {
+ return Collections.emptyList();
+ }
for (PartialPath sgPath : initPath) {
CollectorTraverser<Set<String>> usingTemplatePaths =
@@ -1841,13 +1870,13 @@ public class MTree implements Serializable {
// descendants of this node may be using template too
if (node.isUseTemplate()) {
- result.add(node.getFullPath());
+ result.add(node.getPartialPath());
}
}
return false;
}
};
- usingTemplatePaths.setPrefixMatch(true);
+ usingTemplatePaths.setPrefixMatch(!containWildcard && prefixMode);
usingTemplatePaths.traverse();
}
return result;
diff --git
a/server/src/main/java/org/apache/iotdb/db/metadata/template/Template.java
b/server/src/main/java/org/apache/iotdb/db/metadata/template/Template.java
index abcf3aa3ab..c92663177b 100644
--- a/server/src/main/java/org/apache/iotdb/db/metadata/template/Template.java
+++ b/server/src/main/java/org/apache/iotdb/db/metadata/template/Template.java
@@ -410,7 +410,7 @@ public class Template {
}
public Set<PartialPath> getRelatedStorageGroup() {
- return relatedStorageGroup;
+ return new HashSet<>(relatedStorageGroup);
}
public boolean markStorageGroup(IMNode setNode) {
diff --git
a/server/src/main/java/org/apache/iotdb/db/qp/constant/SQLConstant.java
b/server/src/main/java/org/apache/iotdb/db/qp/constant/SQLConstant.java
index cbae289964..b137ddd9b2 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/constant/SQLConstant.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/constant/SQLConstant.java
@@ -197,6 +197,7 @@ public class SQLConstant {
public static final int TOK_SCHEMA_TEMPLATE_SHOW_NODES = 120;
public static final int TOK_SCHEMA_TEMPLATE_SHOW_PATHS_SET = 121;
public static final int TOK_SCHEMA_TEMPLATE_SHOW_PATHS_USING = 122;
+ public static final int TOK_SCHEMA_TEMPLATE_DEACTIVATE = 124;
public static final int TOK_SHOW_QUERY_RESOURCE = 123;
@@ -284,6 +285,7 @@ public class SQLConstant {
tokenNames.put(TOK_SCHEMA_TEMPLATE_SHOW_NODES,
"TOK_SCHEMA_TEMPLATE_SHOW_NODES");
tokenNames.put(TOK_SCHEMA_TEMPLATE_SHOW_PATHS_SET,
"TOK_SCHEMA_TEMPLATE_SHOW_PATHS_SET");
tokenNames.put(TOK_SCHEMA_TEMPLATE_SHOW_PATHS_USING,
"TOK_SCHEMA_TEMPLATE_SHOW_PATHS_USING");
+ tokenNames.put(TOK_SCHEMA_TEMPLATE_DEACTIVATE,
"TOK_SCHEMA_TEMPLATE_DEACTIVATE");
tokenNames.put(TOK_SHOW_QUERY_RESOURCE, "TOK_SHOW_QUERY_RESOURCE");
}
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 b6c12ac352..274d11b77c 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
@@ -95,6 +95,7 @@ import org.apache.iotdb.db.qp.physical.sys.CreateTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
import org.apache.iotdb.db.qp.physical.sys.CreateTriggerPlan;
import org.apache.iotdb.db.qp.physical.sys.DataAuthPlan;
+import org.apache.iotdb.db.qp.physical.sys.DeactivateTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.DeleteStorageGroupPlan;
import org.apache.iotdb.db.qp.physical.sys.DeleteTimeSeriesPlan;
import org.apache.iotdb.db.qp.physical.sys.DropContinuousQueryPlan;
@@ -393,6 +394,8 @@ public class PlanExecutor implements IPlanExecutor {
return setTemplate((SetTemplatePlan) plan);
case ACTIVATE_TEMPLATE:
return activateTemplate((ActivateTemplatePlan) plan);
+ case DEACTIVATE_TEMPLATE:
+ return deactivateTemplate((DeactivateTemplatePlan) plan);
case UNSET_TEMPLATE:
return unsetTemplate((UnsetTemplatePlan) plan);
case CREATE_CONTINUOUS_QUERY:
@@ -466,6 +469,58 @@ public class PlanExecutor implements IPlanExecutor {
return true;
}
+ private boolean deactivateTemplate(DeactivateTemplatePlan
deactivateTemplatePlan)
+ throws QueryProcessException {
+ try {
+ // get all measurement paths
+ List<PartialPath> pathToDeactivate =
+ new ArrayList<>(
+ IoTDB.metaManager.getPathsUsingTemplateUnderPrefix(
+ deactivateTemplatePlan.getTemplateName(),
+ deactivateTemplatePlan.getPrefixPath().getFullPath(),
+ false));
+ deactivateTemplatePlan.setPaths(pathToDeactivate);
+ List<String> measurementsInnerPaths =
+
IoTDB.metaManager.getMeasurementsInTemplate(deactivateTemplatePlan.getTemplateName(),
"");
+
+ // not with stream for the exception in constructor of PartialPath
+ List<PartialPath> innerPartialPath = new ArrayList<>();
+ for (String path : measurementsInnerPaths) {
+ innerPartialPath.add(new PartialPath(path));
+ }
+
+ // List<PartialPath> pathToDeactivate =
deactivateTemplatePlan.getPaths();
+ List<PartialPath> pathToDelete =
+ new ArrayList<>(innerPartialPath.size() * pathToDeactivate.size());
+
+ for (PartialPath prePath : pathToDeactivate) {
+ for (PartialPath sufPath : innerPartialPath) {
+ pathToDelete.add(prePath.concatPath(sufPath));
+ }
+ }
+
+ // delete related data
+ AUDIT_LOGGER.info("delete timeseries {}", pathToDelete);
+ DeleteTimeSeriesPlan dtsp = new DeleteTimeSeriesPlan(pathToDelete);
+ for (PartialPath path : pathToDelete) {
+ StorageEngine.getInstance()
+ .deleteTimeseries(path, dtsp.getIndex(),
dtsp.getPartitionFilter());
+ }
+ StorageEngine.getInstance().syncCloseAllProcessor();
+
+ IoTDB.metaManager.deactivateSchemaTemplate(deactivateTemplatePlan);
+ } catch (StorageEngineException e) {
+ logger.error(
+ "Deactivation of template [{}] failed since one of its time series
is failed to delete.",
+ deactivateTemplatePlan.getTemplateName());
+ logger.error(e.getMessage());
+ throw new QueryProcessException(e);
+ } catch (MetadataException e) {
+ throw new QueryProcessException(e);
+ }
+ return true;
+ }
+
private boolean unsetTemplate(UnsetTemplatePlan unsetTemplatePlan) throws
QueryProcessException {
try {
IoTDB.metaManager.unsetSchemaTemplate(unsetTemplatePlan);
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 de439e989b..677eadcb51 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
@@ -194,6 +194,8 @@ public abstract class Operator {
APPEND_TEMPLATE,
DROP_TEMPLATE,
- SHOW_QUERY_RESOURCE
+ SHOW_QUERY_RESOURCE,
+
+ DEACTIVATE_TEMPLATE
}
}
diff --git
a/server/src/main/java/org/apache/iotdb/db/qp/logical/sys/DeactivateTemplateOperator.java
b/server/src/main/java/org/apache/iotdb/db/qp/logical/sys/DeactivateTemplateOperator.java
new file mode 100644
index 0000000000..2aee0c995b
--- /dev/null
+++
b/server/src/main/java/org/apache/iotdb/db/qp/logical/sys/DeactivateTemplateOperator.java
@@ -0,0 +1,60 @@
+/*
+ * 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.logical.sys;
+
+import org.apache.iotdb.db.exception.query.QueryProcessException;
+import org.apache.iotdb.db.metadata.path.PartialPath;
+import org.apache.iotdb.db.qp.logical.Operator;
+import org.apache.iotdb.db.qp.physical.PhysicalPlan;
+import org.apache.iotdb.db.qp.physical.sys.DeactivateTemplatePlan;
+import org.apache.iotdb.db.qp.strategy.PhysicalGenerator;
+
+public class DeactivateTemplateOperator extends Operator {
+
+ private String templateName;
+ private PartialPath prefixPath;
+
+ public DeactivateTemplateOperator(int tokenIntType) {
+ super(tokenIntType);
+ operatorType = OperatorType.DEACTIVATE_TEMPLATE;
+ }
+
+ public String getTemplateName() {
+ return templateName;
+ }
+
+ public void setTemplateName(String templateName) {
+ this.templateName = templateName;
+ }
+
+ public PartialPath getPrefixPath() {
+ return prefixPath;
+ }
+
+ public void setPrefixPath(PartialPath prefixPath) {
+ this.prefixPath = prefixPath;
+ }
+
+ @Override
+ public PhysicalPlan generatePhysicalPlan(PhysicalGenerator generator)
+ throws QueryProcessException {
+ return new DeactivateTemplatePlan(templateName, prefixPath);
+ }
+}
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 0267b030b4..2857c45752 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
@@ -48,6 +48,7 @@ import org.apache.iotdb.db.qp.physical.sys.CreateTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
import org.apache.iotdb.db.qp.physical.sys.CreateTriggerPlan;
import org.apache.iotdb.db.qp.physical.sys.DataAuthPlan;
+import org.apache.iotdb.db.qp.physical.sys.DeactivateTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.DeleteStorageGroupPlan;
import org.apache.iotdb.db.qp.physical.sys.DeleteTimeSeriesPlan;
import org.apache.iotdb.db.qp.physical.sys.DropContinuousQueryPlan;
@@ -457,6 +458,9 @@ public abstract class PhysicalPlan {
case ACTIVATE_TEMPLATE:
plan = new ActivateTemplatePlan();
break;
+ case DEACTIVATE_TEMPLATE:
+ plan = new DeactivateTemplatePlan();
+ break;
case AUTO_CREATE_DEVICE_MNODE:
plan = new AutoCreateDeviceMNodePlan();
break;
@@ -557,7 +561,8 @@ public abstract class PhysicalPlan {
UNSET_TEMPLATE,
APPEND_TEMPLATE,
PRUNE_TEMPLATE,
- DROP_TEMPLATE
+ DROP_TEMPLATE,
+ DEACTIVATE_TEMPLATE
}
public long getIndex() {
diff --git
a/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/ActivateTemplatePlan.java
b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/ActivateTemplatePlan.java
index 92878f285a..773b87f87b 100644
---
a/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/ActivateTemplatePlan.java
+++
b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/ActivateTemplatePlan.java
@@ -31,6 +31,7 @@ import org.slf4j.LoggerFactory;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.util.Collections;
import java.util.List;
public class ActivateTemplatePlan extends PhysicalPlan {
@@ -47,6 +48,11 @@ public class ActivateTemplatePlan extends PhysicalPlan {
this.prefixPath = prefixPath;
}
+ @Override
+ public List<? extends PartialPath> getAuthPaths() {
+ return Collections.singletonList(prefixPath);
+ }
+
@Override
public List<PartialPath> getPaths() {
return null;
diff --git
a/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/DeactivateTemplatePlan.java
b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/DeactivateTemplatePlan.java
new file mode 100644
index 0000000000..52b823218f
--- /dev/null
+++
b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/DeactivateTemplatePlan.java
@@ -0,0 +1,116 @@
+/*
+ * 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.sys;
+
+import org.apache.iotdb.db.exception.metadata.IllegalPathException;
+import org.apache.iotdb.db.metadata.path.PartialPath;
+import org.apache.iotdb.db.qp.logical.Operator.OperatorType;
+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.Collections;
+import java.util.List;
+
+public class DeactivateTemplatePlan extends PhysicalPlan {
+
+ String templateName;
+ PartialPath prefixPath;
+ transient List<PartialPath> pathToDeactivate;
+
+ public DeactivateTemplatePlan() {
+ super(OperatorType.DEACTIVATE_TEMPLATE);
+ }
+
+ /**
+ * Inverse process of {@link ActivateTemplatePlan}, may delete time series
data as side effect.
+ *
+ * <p><b>Before this plan being executed, it is compulsory to set {@link
#pathToDeactivate} with
+ * {@linkplain
org.apache.iotdb.db.metadata.MManager#getPathsUsingTemplateUnderPrefix},
otherwise
+ * it may deactivate nothing.</b>
+ *
+ * @param templateName template to delete.
+ * @param prefixPath prefix of paths expected to set NOT using template, in
pattern manner with
+ * wildcard.
+ */
+ public DeactivateTemplatePlan(String templateName, PartialPath prefixPath) {
+ super(OperatorType.DEACTIVATE_TEMPLATE);
+ this.templateName = templateName;
+ this.prefixPath = prefixPath;
+ this.pathToDeactivate = null;
+ }
+
+ // shortcut for uts
+ public DeactivateTemplatePlan(String templateName, String prefixPath)
+ throws IllegalPathException {
+ super(OperatorType.DEACTIVATE_TEMPLATE);
+ this.templateName = templateName;
+ this.prefixPath = new PartialPath(prefixPath);
+ this.pathToDeactivate = null;
+ }
+
+ @Override
+ public List<PartialPath> getPaths() {
+ return pathToDeactivate;
+ }
+
+ @Override
+ public void setPaths(List<PartialPath> paths) {
+ this.pathToDeactivate = paths;
+ }
+
+ @Override
+ public List<? extends PartialPath> getAuthPaths() {
+ return Collections.singletonList(prefixPath);
+ }
+
+ public PartialPath getPrefixPath() {
+ return prefixPath;
+ }
+
+ public String getTemplateName() {
+ return templateName;
+ }
+
+ @Override
+ public void serializeImpl(ByteBuffer buffer) {
+ buffer.put((byte) PhysicalPlanType.DEACTIVATE_TEMPLATE.ordinal());
+ ReadWriteIOUtils.write(templateName, buffer);
+ ReadWriteIOUtils.write(prefixPath.getFullPath(), buffer);
+ buffer.putLong(index);
+ }
+
+ @Override
+ public void deserialize(ByteBuffer buffer) throws IllegalPathException {
+ templateName = readString(buffer);
+ prefixPath = new PartialPath(readString(buffer));
+ index = buffer.getLong();
+ }
+
+ @Override
+ public void serialize(DataOutputStream stream) throws IOException {
+ stream.writeByte((byte) PhysicalPlanType.DEACTIVATE_TEMPLATE.ordinal());
+ ReadWriteIOUtils.write(templateName, stream);
+ ReadWriteIOUtils.write(prefixPath.getFullPath(), stream);
+ stream.writeLong(index);
+ }
+}
diff --git
a/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/SetTemplatePlan.java
b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/SetTemplatePlan.java
index 379f00e526..12714d695a 100644
---
a/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/SetTemplatePlan.java
+++
b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/SetTemplatePlan.java
@@ -30,6 +30,7 @@ import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.util.Collections;
import java.util.List;
public class SetTemplatePlan extends PhysicalPlan {
@@ -72,6 +73,15 @@ public class SetTemplatePlan extends PhysicalPlan {
this.prefixPath = prefixPath;
}
+ @Override
+ public List<? extends PartialPath> getAuthPaths() {
+ try {
+ return Collections.singletonList(new PartialPath(prefixPath));
+ } catch (IllegalPathException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
@Override
public List<PartialPath> getPaths() {
return null;
diff --git
a/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/UnsetTemplatePlan.java
b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/UnsetTemplatePlan.java
index a7439da6ee..420ba52998 100644
---
a/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/UnsetTemplatePlan.java
+++
b/server/src/main/java/org/apache/iotdb/db/qp/physical/sys/UnsetTemplatePlan.java
@@ -31,6 +31,7 @@ import org.apache.iotdb.tsfile.utils.ReadWriteIOUtils;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.util.Collections;
import java.util.List;
public class UnsetTemplatePlan extends PhysicalPlan {
@@ -74,6 +75,15 @@ public class UnsetTemplatePlan extends PhysicalPlan {
this.templateName = templateName;
}
+ @Override
+ public List<? extends PartialPath> getAuthPaths() {
+ try {
+ return Collections.singletonList(new PartialPath(prefixPath));
+ } catch (IllegalPathException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
@Override
public List<PartialPath> getPaths() {
return null;
diff --git
a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
index 48af4d9028..f9367993b0 100644
--- a/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
+++ b/server/src/main/java/org/apache/iotdb/db/qp/sql/IoTDBSqlVisitor.java
@@ -404,6 +404,18 @@ public class IoTDBSqlVisitor extends
IoTDBSqlParserBaseVisitor<Operator> {
return operator;
}
+ // Inverse procedure of createTimeseriesOfSchemaTemplate
+
+ @Override
+ public Operator visitDeactivateSchemaTemplate(
+ IoTDBSqlParser.DeactivateSchemaTemplateContext ctx) {
+ DeactivateTemplateOperator operator =
+ new
DeactivateTemplateOperator(SQLConstant.TOK_SCHEMA_TEMPLATE_DEACTIVATE);
+ operator.setPrefixPath(parsePrefixPath(ctx.prefixPath()));
+ operator.setTemplateName(parseIdentifier(ctx.templateName.getText()));
+ return operator;
+ }
+
// Create Function
@Override
diff --git
a/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/TSServiceImpl.java
b/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/TSServiceImpl.java
index bc40c5010c..7e3ee0b5e0 100644
---
a/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/TSServiceImpl.java
+++
b/server/src/main/java/org/apache/iotdb/db/service/thrift/impl/TSServiceImpl.java
@@ -53,6 +53,7 @@ import
org.apache.iotdb.db.qp.physical.sys.CreateAlignedTimeSeriesPlan;
import org.apache.iotdb.db.qp.physical.sys.CreateMultiTimeSeriesPlan;
import org.apache.iotdb.db.qp.physical.sys.CreateTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
+import org.apache.iotdb.db.qp.physical.sys.DeactivateTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.DeleteStorageGroupPlan;
import org.apache.iotdb.db.qp.physical.sys.DeleteTimeSeriesPlan;
import org.apache.iotdb.db.qp.physical.sys.DropTemplatePlan;
@@ -1966,8 +1967,8 @@ public class TSServiceImpl implements TSIService.Iface {
@Override
public TSQueryTemplateResp querySchemaTemplate(TSQueryTemplateReq req) {
+ TSQueryTemplateResp resp = new TSQueryTemplateResp();
try {
- TSQueryTemplateResp resp = new TSQueryTemplateResp();
String path;
switch (TemplateQueryType.values()[req.getQueryType()]) {
case COUNT_MEASUREMENTS:
@@ -2005,11 +2006,11 @@ public class TSServiceImpl implements TSIService.Iface {
break;
}
resp.setStatus(RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS, "Execute
successfully"));
- return resp;
} catch (MetadataException e) {
+ resp.setStatus(RpcUtils.getStatus(TSStatusCode.METADATA_ERROR,
e.getMessage()));
LOGGER.error("fail to query schema template because: " + e);
}
- return null;
+ return resp;
}
@Override
@@ -2058,6 +2059,31 @@ public class TSServiceImpl implements TSIService.Iface {
}
}
+ @Override
+ public TSStatus unsetUsingTemplate(long sessionId, String templateName,
String prefixPath)
+ throws TException {
+ if (!serviceProvider.checkLogin(sessionId)) {
+ return getNotLoggedInStatus();
+ }
+
+ if (AUDIT_LOGGER.isDebugEnabled()) {
+ AUDIT_LOGGER.debug(
+ "Session-{} unset using schema template {} on {}",
+ SESSION_MANAGER.getCurrSessionId(),
+ templateName,
+ prefixPath);
+ }
+
+ try {
+ DeactivateTemplatePlan plan =
+ new DeactivateTemplatePlan(templateName, new
PartialPath(prefixPath));
+ TSStatus status = serviceProvider.checkAuthority(plan, sessionId);
+ return status != null ? status : executeNonQueryPlan(plan);
+ } catch (MetadataException e) {
+ return onIoTDBException(e, OperationType.EXECUTE_STATEMENT,
e.getErrorCode());
+ }
+ }
+
@Override
public TSStatus setUsingTemplate(TSSetUsingTemplateReq req) throws
TException {
if (!serviceProvider.checkLogin(req.getSessionId())) {
diff --git
a/server/src/main/java/org/apache/iotdb/db/tools/mlog/MLogParser.java
b/server/src/main/java/org/apache/iotdb/db/tools/mlog/MLogParser.java
index 773ae2c67c..ee310272c0 100644
--- a/server/src/main/java/org/apache/iotdb/db/tools/mlog/MLogParser.java
+++ b/server/src/main/java/org/apache/iotdb/db/tools/mlog/MLogParser.java
@@ -31,6 +31,7 @@ import
org.apache.iotdb.db.qp.physical.sys.CreateAlignedTimeSeriesPlan;
import org.apache.iotdb.db.qp.physical.sys.CreateContinuousQueryPlan;
import org.apache.iotdb.db.qp.physical.sys.CreateTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
+import org.apache.iotdb.db.qp.physical.sys.DeactivateTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.DropContinuousQueryPlan;
import org.apache.iotdb.db.qp.physical.sys.DropTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.MNodePlan;
@@ -238,6 +239,9 @@ public class MLogParser {
case ACTIVATE_TEMPLATE:
mLogTxtWriter.setUsingTemplate((ActivateTemplatePlan) plan);
break;
+ case DEACTIVATE_TEMPLATE:
+ mLogTxtWriter.deactivateTemplate((DeactivateTemplatePlan) plan);
+ break;
case AUTO_CREATE_DEVICE_MNODE:
mLogTxtWriter.autoCreateDeviceNode(
((AutoCreateDeviceMNodePlan) plan).getPath().getFullPath());
diff --git a/server/src/main/java/org/apache/iotdb/db/utils/AuthUtils.java
b/server/src/main/java/org/apache/iotdb/db/utils/AuthUtils.java
index b655636446..16e851bad3 100644
--- a/server/src/main/java/org/apache/iotdb/db/utils/AuthUtils.java
+++ b/server/src/main/java/org/apache/iotdb/db/utils/AuthUtils.java
@@ -141,6 +141,7 @@ public class AuthUtils {
case DROP_TRIGGER:
case START_TRIGGER:
case STOP_TRIGGER:
+ case APPLY_TEMPLATE:
return;
default:
throw new AuthException(
diff --git
a/server/src/test/java/org/apache/iotdb/db/metadata/TemplateTest.java
b/server/src/test/java/org/apache/iotdb/db/metadata/TemplateTest.java
index ab59cab0ee..ddb1c6b619 100644
--- a/server/src/test/java/org/apache/iotdb/db/metadata/TemplateTest.java
+++ b/server/src/test/java/org/apache/iotdb/db/metadata/TemplateTest.java
@@ -21,6 +21,7 @@ package org.apache.iotdb.db.metadata;
import org.apache.iotdb.db.exception.metadata.IllegalPathException;
import org.apache.iotdb.db.exception.metadata.MetadataException;
import org.apache.iotdb.db.exception.metadata.PathNotExistException;
+import org.apache.iotdb.db.exception.metadata.TemplateIsInUseException;
import org.apache.iotdb.db.exception.query.QueryProcessException;
import org.apache.iotdb.db.metadata.mnode.IMNode;
import org.apache.iotdb.db.metadata.mnode.IMeasurementMNode;
@@ -30,7 +31,10 @@ import org.apache.iotdb.db.metadata.template.Template;
import org.apache.iotdb.db.qp.executor.PlanExecutor;
import org.apache.iotdb.db.qp.physical.PhysicalPlan;
import org.apache.iotdb.db.qp.physical.crud.InsertRowPlan;
+import org.apache.iotdb.db.qp.physical.sys.ActivateTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.CreateTemplatePlan;
+import org.apache.iotdb.db.qp.physical.sys.CreateTimeSeriesPlan;
+import org.apache.iotdb.db.qp.physical.sys.DeactivateTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.DropTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.SetTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.UnsetTemplatePlan;
@@ -56,6 +60,7 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -473,6 +478,147 @@ public class TemplateTest {
}
}
+ @Test
+ public void testDeactivateTemplate() throws Exception {
+ IoTDB.metaManager.createSchemaTemplate(getCreateTemplatePlan());
+ IoTDB.metaManager.setSchemaTemplate(new SetTemplatePlan("template1",
"root.sg0"));
+ IoTDB.metaManager.setSchemaTemplate(new SetTemplatePlan("template1",
"root.sg1.v1"));
+
+ IoTDB.metaManager.setStorageGroup(new PartialPath("root.sg2.v2"));
+ IoTDB.metaManager.setSchemaTemplate(new SetTemplatePlan("template1",
"root.sg2.v2.d2"));
+
+ IoTDB.metaManager.createTimeseries(
+ new CreateTimeSeriesPlan(
+ new PartialPath("root.sg1.v1.d1.s1"),
+ TSDataType.INT32,
+ TSEncoding.PLAIN,
+ CompressionType.GZIP,
+ null,
+ null,
+ null,
+ null));
+
+ assertEquals(1, IoTDB.metaManager.getAllTimeseriesCount(new
PartialPath("root.**")));
+ IoTDB.metaManager.setUsingSchemaTemplate(
+ new ActivateTemplatePlan(new PartialPath("root.sg0.v1")));
+ IoTDB.metaManager.setUsingSchemaTemplate(
+ new ActivateTemplatePlan(new PartialPath("root.sg0.v1.d1")));
+ IoTDB.metaManager.setUsingSchemaTemplate(
+ new ActivateTemplatePlan(new PartialPath("root.sg0.v1.d2")));
+
+ assertEquals(
+ 1 + 3L * IoTDB.metaManager.countMeasurementsInTemplate("template1"),
+ IoTDB.metaManager.getAllTimeseriesCount(new PartialPath("root.**")));
+
+ IoTDB.metaManager.setUsingSchemaTemplate(
+ new ActivateTemplatePlan(new PartialPath("root.sg1.v1")));
+ IoTDB.metaManager.setUsingSchemaTemplate(
+ new ActivateTemplatePlan(new PartialPath("root.sg1.v1.d1")));
+ IoTDB.metaManager.setUsingSchemaTemplate(
+ new ActivateTemplatePlan(new PartialPath("root.sg1.v1.d2")));
+ IoTDB.metaManager.setUsingSchemaTemplate(
+ new ActivateTemplatePlan(new PartialPath("root.sg1.v1.d3")));
+
+ IoTDB.metaManager.setUsingSchemaTemplate(
+ new ActivateTemplatePlan(new PartialPath("root.sg2.v2.d2")));
+ IoTDB.metaManager.setUsingSchemaTemplate(
+ new ActivateTemplatePlan(new PartialPath("root.sg2.v2.d2.s0")));
+ IoTDB.metaManager.setUsingSchemaTemplate(
+ new ActivateTemplatePlan(new PartialPath("root.sg2.v2.d2.sd.s0")));
+
+ assertEquals(10,
IoTDB.metaManager.getPathsUsingTemplate("template1").size());
+
+ try {
+ IoTDB.metaManager.unsetSchemaTemplate(new UnsetTemplatePlan("root.sg0",
"template1"));
+ fail();
+ } catch (TemplateIsInUseException e) {
+ assertEquals("Template is in use on root.sg0.v1", e.getMessage());
+ }
+
+ assertEquals(
+ 3,
+ IoTDB.metaManager.getPathsUsingTemplateUnderPrefix("template1",
"root.sg0", true).size());
+ assertEquals(
+ 4,
+ IoTDB.metaManager.getPathsUsingTemplateUnderPrefix("template1",
"root.sg1", true).size());
+ assertEquals(
+ 4,
+ IoTDB.metaManager
+ .getPathsUsingTemplateUnderPrefix("template1", "root.sg1.v1", true)
+ .size());
+ assertEquals(
+ 3,
+ IoTDB.metaManager.getPathsUsingTemplateUnderPrefix("template1",
"root.sg2", true).size());
+ assertEquals(
+ 3,
+ IoTDB.metaManager
+ .getPathsUsingTemplateUnderPrefix("template1", "root.sg2.v2.d2",
true)
+ .size());
+
+ // check wildcard usage
+ Set<String> ans1 =
+ new HashSet<>(Arrays.asList("root.sg2.v2.d2", "root.sg2.v2.d2.s0",
"root.sg2.v2.d2.sd.s0"));
+ Set<String> ans2 = new HashSet<>(Arrays.asList("root.sg2.v2.d2.s0"));
+ Set<String> ans3 = new HashSet<>(Arrays.asList("root.sg2.v2.d2.s0",
"root.sg2.v2.d2.sd.s0"));
+
+ assertEquals(
+ ans1,
+ IoTDB.metaManager.getPathsUsingTemplateUnderPrefix("template1",
"root.sg2.v2.d2", true)
+ .stream()
+ .map(PartialPath::getFullPath)
+ .collect(Collectors.toSet()));
+ assertEquals(
+ ans2,
+ IoTDB.metaManager.getPathsUsingTemplateUnderPrefix("template1",
"root.sg2.v2.d2.*", true)
+ .stream()
+ .map(PartialPath::getFullPath)
+ .collect(Collectors.toSet()));
+ assertEquals(
+ ans3,
+ IoTDB.metaManager.getPathsUsingTemplateUnderPrefix("template1",
"root.sg2.v2.d2.**", true)
+ .stream()
+ .map(PartialPath::getFullPath)
+ .collect(Collectors.toSet()));
+
+ System.out.println(
+ IoTDB.metaManager
+ .getPathsUsingTemplateUnderPrefix("template1", "root.sg2.v2.d2",
false)
+ .toString());
+
+ IoTDB.metaManager.deactivateSchemaTemplate(getDeactivatePlan("template1",
"root.sg1.v1"));
+ assertEquals(
+ 3,
+ IoTDB.metaManager
+ .getPathsUsingTemplateUnderPrefix("template1", "root.sg1.v1", true)
+ .size());
+ IoTDB.metaManager.deactivateSchemaTemplate(getDeactivatePlan("template1",
"root.sg1.v1.**"));
+ IoTDB.metaManager.unsetSchemaTemplate(new UnsetTemplatePlan("root.sg1.v1",
"template1"));
+ assertEquals(2, IoTDB.metaManager.getPathsSetTemplate("template1").size());
+
+ IoTDB.metaManager.deactivateSchemaTemplate(getDeactivatePlan("template1",
"root.sg2.v2.*"));
+ assertEquals(
+ 2,
+ IoTDB.metaManager.getPathsUsingTemplateUnderPrefix("template1",
"root.sg2", true).size());
+
+ IoTDB.metaManager.deactivateSchemaTemplate(getDeactivatePlan("template1",
"root.**"));
+ assertEquals(1, IoTDB.metaManager.getAllTimeseriesCount(new
PartialPath("root.**")));
+
+ EnvironmentUtils.restartDaemon();
+ assertEquals(1, IoTDB.metaManager.getAllTimeseriesCount(new
PartialPath("root.**")));
+ IoTDB.metaManager.unsetSchemaTemplate(new UnsetTemplatePlan("root.sg0",
"template1"));
+ IoTDB.metaManager.unsetSchemaTemplate(new
UnsetTemplatePlan("root.sg2.v2.d2", "template1"));
+ IoTDB.metaManager.dropSchemaTemplate(new DropTemplatePlan("template1"));
+ assertEquals(0, IoTDB.metaManager.getAllTemplates().size());
+ }
+
+ private DeactivateTemplatePlan getDeactivatePlan(String tName, String prefix)
+ throws MetadataException {
+ DeactivateTemplatePlan plan = new DeactivateTemplatePlan(tName, new
PartialPath(prefix));
+ plan.setPaths(
+ new
ArrayList<>(IoTDB.metaManager.getPathsUsingTemplateUnderPrefix(tName, prefix,
false)));
+ return plan;
+ }
+
private InsertRowPlan getInsertRowPlan(String prefixPath, String measurement)
throws IllegalPathException {
long time = 110L;
diff --git
a/server/src/test/java/org/apache/iotdb/db/qp/physical/InsertRowPlanTest.java
b/server/src/test/java/org/apache/iotdb/db/qp/physical/InsertRowPlanTest.java
index a0505707ce..45ce0a7445 100644
---
a/server/src/test/java/org/apache/iotdb/db/qp/physical/InsertRowPlanTest.java
+++
b/server/src/test/java/org/apache/iotdb/db/qp/physical/InsertRowPlanTest.java
@@ -30,7 +30,9 @@ import
org.apache.iotdb.db.qp.physical.PhysicalPlan.PhysicalPlanType;
import org.apache.iotdb.db.qp.physical.crud.InsertRowPlan;
import org.apache.iotdb.db.qp.physical.crud.QueryPlan;
import org.apache.iotdb.db.qp.physical.sys.CreateTemplatePlan;
+import org.apache.iotdb.db.qp.physical.sys.DeactivateTemplatePlan;
import org.apache.iotdb.db.qp.physical.sys.SetTemplatePlan;
+import org.apache.iotdb.db.qp.physical.sys.UnsetTemplatePlan;
import org.apache.iotdb.db.service.IoTDB;
import org.apache.iotdb.db.utils.EnvironmentUtils;
import
org.apache.iotdb.tsfile.exception.filter.QueryFilterOptimizationException;
@@ -39,6 +41,7 @@ import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
import org.apache.iotdb.tsfile.read.common.RowRecord;
import org.apache.iotdb.tsfile.read.query.dataset.QueryDataSet;
+import org.apache.iotdb.tsfile.utils.Binary;
import org.junit.After;
import org.junit.Assert;
@@ -247,6 +250,43 @@ public class InsertRowPlanTest {
RowRecord record = dataSet.next();
Assert.assertEquals(6, record.getFields().size());
}
+
+ executor.processNonQuery(new DeactivateTemplatePlan("template1",
"root.isp.d1"));
+
+ queryPlan = (QueryPlan) processor.parseSQLToPhysicalPlan("select * from
root.isp.d1");
+ dataSet = executor.processQuery(queryPlan,
EnvironmentUtils.TEST_QUERY_CONTEXT);
+ Assert.assertEquals(0, dataSet.getPaths().size());
+
+ executor.insert(rowPlan);
+ queryPlan = (QueryPlan) processor.parseSQLToPhysicalPlan("select * from
root.isp.d1");
+ dataSet = executor.processQuery(queryPlan,
EnvironmentUtils.TEST_QUERY_CONTEXT);
+
+ // verify data has been deleted
+ int rCnt = 0;
+ while (dataSet.hasNext()) {
+ rCnt++;
+ dataSet.next();
+ }
+ Assert.assertEquals(1, rCnt);
+
+ executor.processNonQuery(new DeactivateTemplatePlan("template1",
"root.isp.d1"));
+ executor.processNonQuery(new UnsetTemplatePlan("root.isp.d1",
"template1"));
+
+ rowPlan.getDataTypes()[0] = TSDataType.TEXT;
+ rowPlan.getValues()[0] = Binary.valueOf("aaa");
+
+ IoTDBDescriptor.getInstance().getConfig().setAutoCreateSchemaEnabled(true);
+ executor.insert(rowPlan);
+ queryPlan = (QueryPlan) processor.parseSQLToPhysicalPlan("select * from
root.isp.d1");
+ dataSet = executor.processQuery(queryPlan,
EnvironmentUtils.TEST_QUERY_CONTEXT);
+
+ // verify template has been removed
+ rCnt = 0;
+ while (dataSet.hasNext()) {
+ rCnt++;
+ dataSet.next();
+ }
+ Assert.assertEquals(1, rCnt);
}
@Test
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 8afc98b360..5025a8f230 100644
--- a/session/src/main/java/org/apache/iotdb/session/Session.java
+++ b/session/src/main/java/org/apache/iotdb/session/Session.java
@@ -2377,6 +2377,12 @@ public class Session {
defaultSessionConnection.setUsingTemplate(request);
}
+ /** Inverse of {@linkplain #createTimeseriesOfTemplateOnPath}, IMPLYING data
deletion. */
+ public void deactivateTemplateOn(String templateName, String prefixPath)
+ throws IoTDBConnectionException, StatementExecutionException {
+ defaultSessionConnection.deactivateTemplate(templateName, prefixPath);
+ }
+
public void dropSchemaTemplate(String templateName)
throws IoTDBConnectionException, StatementExecutionException {
TSDropSchemaTemplateReq request = getTSDropSchemaTemplateReq(templateName);
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 6635b9d013..f65cf2caea 100644
--- a/session/src/main/java/org/apache/iotdb/session/SessionConnection.java
+++ b/session/src/main/java/org/apache/iotdb/session/SessionConnection.java
@@ -944,6 +944,23 @@ public class SessionConnection {
}
}
+ protected void deactivateTemplate(String tName, String pPath)
+ throws IoTDBConnectionException, StatementExecutionException {
+ try {
+ RpcUtils.verifySuccess(client.unsetUsingTemplate(sessionId, tName,
pPath));
+ } catch (TException e) {
+ if (reconnect()) {
+ try {
+ RpcUtils.verifySuccess(client.unsetUsingTemplate(sessionId, tName,
pPath));
+ } catch (TException tException) {
+ throw new IoTDBConnectionException(tException);
+ }
+ } else {
+ throw new IoTDBConnectionException(MSG_RECONNECTION_FAIL);
+ }
+ }
+ }
+
protected void dropSchemaTemplate(TSDropSchemaTemplateReq request)
throws IoTDBConnectionException, StatementExecutionException {
request.setSessionId(sessionId);
diff --git
a/session/src/main/java/org/apache/iotdb/session/pool/SessionPool.java
b/session/src/main/java/org/apache/iotdb/session/pool/SessionPool.java
index 841581f6a2..57b3d1dbb4 100644
--- a/session/src/main/java/org/apache/iotdb/session/pool/SessionPool.java
+++ b/session/src/main/java/org/apache/iotdb/session/pool/SessionPool.java
@@ -2146,6 +2146,25 @@ public class SessionPool {
}
}
+ public void deactivateTempalte(String templateName, String prefixPath)
+ throws IoTDBConnectionException, StatementExecutionException {
+ for (int i = 0; i < RETRY; i++) {
+ Session session = getSession();
+ try {
+ session.deactivateTemplateOn(templateName, prefixPath);
+ putBack(session);
+ } catch (IoTDBConnectionException e) {
+ // TException means the connection is broken, remove it and get a new
one.
+ logger.warn(
+ String.format("Deactivate template [%s] on [%s] failed",
templateName, prefixPath), e);
+ cleanSessionAndMayThrowConnectionException(session, i, e);
+ } catch (StatementExecutionException | RuntimeException e) {
+ putBack(session);
+ throw e;
+ }
+ }
+ }
+
public void dropSchemaTemplate(String templateName)
throws StatementExecutionException, IoTDBConnectionException {
for (int i = 0; i < RETRY; i++) {
diff --git a/thrift/src/main/thrift/rpc.thrift
b/thrift/src/main/thrift/rpc.thrift
index cc38805c89..797270e180 100644
--- a/thrift/src/main/thrift/rpc.thrift
+++ b/thrift/src/main/thrift/rpc.thrift
@@ -518,6 +518,8 @@ service TSIService {
TSStatus setUsingTemplate(1:TSSetUsingTemplateReq req);
+ TSStatus unsetUsingTemplate(1:i64 sessionId, 2:string templateName, 3:string
prefixPath);
+
TSStatus dropSchemaTemplate(1:TSDropSchemaTemplateReq req);
TSStatus executeOperationSync(1:TSOperationSyncWriteReq req);