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

jt2594838 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 1c8ed311c95 Support target database in write-back sink (#18058)
1c8ed311c95 is described below

commit 1c8ed311c95392ea5256c02a7f5848f2ecaec62e
Author: Caideyipi <[email protected]>
AuthorDate: Wed Jul 1 18:30:44 2026 +0800

    Support target database in write-back sink (#18058)
    
    * Support target database in write back sink
    
    * Validate write-back sink target database
    
    * Cover write-back sink database validation semantics
    
    * Update WriteBackSink.java
    
    * Address write-back sink review comments
    
    * Clarify write-back sink target database normalization
---
 .../manual/basic/IoTDBPipeDataSinkIT.java          |   4 +-
 .../treemodel/manual/IoTDBPipeWriteBackSinkIT.java |  96 ++++++
 .../apache/iotdb/db/i18n/DataNodePipeMessages.java |  15 +
 .../apache/iotdb/db/i18n/DataNodePipeMessages.java |  12 +
 .../sink/protocol/writeback/WriteBackSink.java     | 383 +++++++++++++++++++--
 .../apache/iotdb/db/pipe/sink/PipeSinkTest.java    | 213 ++++++++++++
 6 files changed, 691 insertions(+), 32 deletions(-)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/pipe/it/dual/tablemodel/manual/basic/IoTDBPipeDataSinkIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/pipe/it/dual/tablemodel/manual/basic/IoTDBPipeDataSinkIT.java
index 2092bb9239e..2a5c9352e25 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/pipe/it/dual/tablemodel/manual/basic/IoTDBPipeDataSinkIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/pipe/it/dual/tablemodel/manual/basic/IoTDBPipeDataSinkIT.java
@@ -277,10 +277,8 @@ public class IoTDBPipeDataSinkIT extends 
AbstractPipeTableModelDualManualIT {
       sourceAttributes.put("source.table-name", "test.*");
       sourceAttributes.put("user", "root");
 
-      processorAttributes.put("processor", "rename-database-processor");
-      processorAttributes.put("processor.new-db-name", "Test1");
-
       sinkAttributes.put("sink", "write-back-sink");
+      sinkAttributes.put("sink.database", "Test1");
       sinkAttributes.put("user", "root");
 
       final TSStatus status =
diff --git 
a/integration-test/src/test/java/org/apache/iotdb/pipe/it/dual/treemodel/manual/IoTDBPipeWriteBackSinkIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/pipe/it/dual/treemodel/manual/IoTDBPipeWriteBackSinkIT.java
new file mode 100644
index 00000000000..11edc8cf6be
--- /dev/null
+++ 
b/integration-test/src/test/java/org/apache/iotdb/pipe/it/dual/treemodel/manual/IoTDBPipeWriteBackSinkIT.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.pipe.it.dual.treemodel.manual;
+
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.commons.client.sync.SyncConfigNodeIServiceClient;
+import org.apache.iotdb.confignode.rpc.thrift.TCreatePipeReq;
+import org.apache.iotdb.db.it.utils.TestUtils;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.MultiClusterIT2DualTreeManual;
+import org.apache.iotdb.rpc.TSStatusCode;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({MultiClusterIT2DualTreeManual.class})
+public class IoTDBPipeWriteBackSinkIT extends 
AbstractPipeDualTreeModelManualIT {
+
+  @Test
+  public void testWriteBackSinkWithTargetDatabaseForTreeModel() throws 
Exception {
+    TestUtils.executeNonQueries(
+        senderEnv,
+        Arrays.asList(
+            "create database root.source",
+            "create timeseries root.source.d1.s1 with 
datatype=INT32,encoding=PLAIN",
+            "create database root.target.db",
+            "create timeseries root.target.db.d1.s1 with 
datatype=INT32,encoding=PLAIN"),
+        null);
+
+    try (final SyncConfigNodeIServiceClient client =
+        (SyncConfigNodeIServiceClient) 
senderEnv.getLeaderConfigNodeConnection()) {
+      final Map<String, String> sourceAttributes = new HashMap<>();
+      final Map<String, String> processorAttributes = new HashMap<>();
+      final Map<String, String> sinkAttributes = new HashMap<>();
+
+      sourceAttributes.put("source.inclusion", "data.insert");
+      sourceAttributes.put("source.forwarding-pipe-requests", "false");
+      sourceAttributes.put("source.path", "root.source.**");
+      sourceAttributes.put("user", "root");
+
+      sinkAttributes.put("sink", "write-back-sink");
+      sinkAttributes.put("sink.database", "root.target.db");
+      sinkAttributes.put("user", "root");
+
+      final TSStatus status =
+          client.createPipe(
+              new TCreatePipeReq("testPipe", sinkAttributes)
+                  .setExtractorAttributes(sourceAttributes)
+                  .setProcessorAttributes(processorAttributes));
+      Assert.assertEquals(TSStatusCode.SUCCESS_STATUS.getStatusCode(), 
status.getCode());
+
+      Assert.assertEquals(
+          TSStatusCode.SUCCESS_STATUS.getStatusCode(), 
client.startPipe("testPipe").getCode());
+    }
+
+    TestUtils.executeNonQueries(
+        senderEnv,
+        Arrays.asList(
+            "insert into root.source.d1(time, s1) values (1, 1)",
+            "insert into root.source.d1(time, s1) values (2, 2)",
+            "flush"),
+        null);
+
+    TestUtils.assertDataEventuallyOnEnv(
+        senderEnv,
+        "select * from root.target.db.**",
+        "Time,root.target.db.d1.s1,",
+        Collections.unmodifiableSet(new HashSet<>(Arrays.asList("1,1,", 
"2,2,"))));
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodePipeMessages.java
 
b/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodePipeMessages.java
index 13369fc5ee3..bfac58fbab1 100644
--- 
a/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodePipeMessages.java
+++ 
b/iotdb-core/datanode/src/main/i18n/en/org/apache/iotdb/db/i18n/DataNodePipeMessages.java
@@ -1449,6 +1449,21 @@ public final class DataNodePipeMessages {
   // 
---------------------------------------------------------------------------
   public static final String PLUGIN_NOT_REGISTERED_FMT = "plugin %s is not 
registered.";
 
+  // 
---------------------------------------------------------------------------
+  // pipe - WriteBackSink
+  // 
---------------------------------------------------------------------------
+  public static final String TABLE_MODEL_DATABASE_INVALID_FMT =
+      "The table-model database %s is invalid. It should not contain '%s', 
should match the "
+          + "pattern %s, and the length should not exceed %d";
+  public static final String TREE_MODEL_DATABASE_INVALID_FMT =
+      "The tree-model database %s is invalid. It should be a legal tree-model 
database path, "
+          + "should match the pattern %s, and the length should not exceed %d";
+  public static final String 
TARGET_TREE_MODEL_DATABASE_CANNOT_BE_USED_FOR_TABLE_MODEL_EVENTS_FMT =
+      "The target tree-model database %s cannot be used for table-model events 
because the "
+          + "corresponding table-model database %s is invalid.";
+  public static final String FAILED_TO_REWRITE_TREE_MODEL_DATABASE_FMT =
+      "Failed to rewrite tree-model database from %s to %s for device %s.";
+
   // 
---------------------------------------------------------------------------
   // pipe – PipeTransferTrackableHandler
   // 
---------------------------------------------------------------------------
diff --git 
a/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodePipeMessages.java
 
b/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodePipeMessages.java
index 49ee222c3e9..6fbc50ac13b 100644
--- 
a/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodePipeMessages.java
+++ 
b/iotdb-core/datanode/src/main/i18n/zh/org/apache/iotdb/db/i18n/DataNodePipeMessages.java
@@ -1396,6 +1396,18 @@ public final class DataNodePipeMessages {
   // 
---------------------------------------------------------------------------
   public static final String PLUGIN_NOT_REGISTERED_FMT = "插件 %s 未注册。";
 
+  // 
---------------------------------------------------------------------------
+  // pipe - WriteBackSink
+  // 
---------------------------------------------------------------------------
+  public static final String TABLE_MODEL_DATABASE_INVALID_FMT =
+      "表模型数据库 %s 非法:不应包含 '%s',应匹配 %s,且长度不应超过 %d";
+  public static final String TREE_MODEL_DATABASE_INVALID_FMT =
+      "树模型数据库 %s 非法:应为合法的树模型数据库路径,应匹配 %s,且长度不应超过 %d";
+  public static final String 
TARGET_TREE_MODEL_DATABASE_CANNOT_BE_USED_FOR_TABLE_MODEL_EVENTS_FMT =
+      "目标树模型数据库 %s 不能用于表模型事件,因为对应的表模型数据库 %s 非法。";
+  public static final String FAILED_TO_REWRITE_TREE_MODEL_DATABASE_FMT =
+      "将树模型数据库从 %s 重写为 %s 失败,设备为 %s。";
+
   // 
---------------------------------------------------------------------------
   // pipe – PipeTransferTrackableHandler
   // 
---------------------------------------------------------------------------
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/sink/protocol/writeback/WriteBackSink.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/sink/protocol/writeback/WriteBackSink.java
index 9bec114ede1..fe46e47234d 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/sink/protocol/writeback/WriteBackSink.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/sink/protocol/writeback/WriteBackSink.java
@@ -22,14 +22,18 @@ package org.apache.iotdb.db.pipe.sink.protocol.writeback;
 import org.apache.iotdb.common.rpc.thrift.TSStatus;
 import org.apache.iotdb.commons.audit.UserEntity;
 import org.apache.iotdb.commons.conf.IoTDBConstant;
+import org.apache.iotdb.commons.exception.IllegalPathException;
 import org.apache.iotdb.commons.exception.IoTDBRuntimeException;
 import org.apache.iotdb.commons.exception.auth.AccessDeniedException;
 import 
org.apache.iotdb.commons.exception.pipe.PipeRuntimeSinkNonReportTimeConfigurableException;
+import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.commons.pipe.resource.log.PipeLogger;
 import org.apache.iotdb.commons.queryengine.common.SqlDialect;
+import org.apache.iotdb.commons.utils.PathUtils;
 import org.apache.iotdb.commons.utils.StatusUtils;
 import org.apache.iotdb.confignode.rpc.thrift.TDatabaseSchema;
 import org.apache.iotdb.db.auth.AuthorityChecker;
+import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.conf.IoTDBDescriptor;
 import org.apache.iotdb.db.i18n.DataNodePipeMessages;
 import 
org.apache.iotdb.db.pipe.event.common.statement.PipeStatementInsertionEvent;
@@ -43,6 +47,7 @@ import org.apache.iotdb.db.queryengine.plan.Coordinator;
 import org.apache.iotdb.db.queryengine.plan.analyze.ClusterPartitionFetcher;
 import 
org.apache.iotdb.db.queryengine.plan.analyze.schema.ClusterSchemaFetcher;
 import org.apache.iotdb.db.queryengine.plan.execution.config.ConfigTaskResult;
+import 
org.apache.iotdb.db.queryengine.plan.execution.config.TableConfigTaskVisitor;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.executor.ClusterConfigTaskExecutor;
 import 
org.apache.iotdb.db.queryengine.plan.execution.config.metadata.relational.CreateDBTask;
 import org.apache.iotdb.db.queryengine.plan.planner.LocalExecutionPlanner;
@@ -51,8 +56,12 @@ import 
org.apache.iotdb.db.queryengine.plan.relational.security.TreeAccessCheckC
 import org.apache.iotdb.db.queryengine.plan.relational.sql.parser.SqlParser;
 import org.apache.iotdb.db.queryengine.plan.statement.Statement;
 import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertBaseStatement;
+import 
org.apache.iotdb.db.queryengine.plan.statement.crud.InsertMultiTabletsStatement;
+import 
org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowsOfOneDeviceStatement;
+import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowsStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.crud.InsertTabletStatement;
 import 
org.apache.iotdb.db.queryengine.plan.statement.pipe.PipeEnrichedStatement;
+import org.apache.iotdb.db.schemaengine.schemaregion.utils.MetaFormatUtils;
 import 
org.apache.iotdb.db.storageengine.dataregion.wal.exception.WALPipeException;
 import org.apache.iotdb.pipe.api.PipeConnector;
 import org.apache.iotdb.pipe.api.annotation.TableModel;
@@ -75,7 +84,9 @@ import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.time.ZoneId;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.Locale;
 import java.util.Objects;
 import java.util.Set;
@@ -84,6 +95,7 @@ import java.util.concurrent.ExecutionException;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.stream.Collectors;
 
+import static 
org.apache.iotdb.commons.conf.IoTDBConstant.MAX_DATABASE_NAME_LENGTH;
 import static 
org.apache.iotdb.commons.pipe.config.constant.PipeSinkConstant.CONNECTOR_IOTDB_CLI_HOSTNAME;
 import static 
org.apache.iotdb.commons.pipe.config.constant.PipeSinkConstant.CONNECTOR_IOTDB_PASSWORD_KEY;
 import static 
org.apache.iotdb.commons.pipe.config.constant.PipeSinkConstant.CONNECTOR_IOTDB_SKIP_IF_NO_PRIVILEGES;
@@ -103,17 +115,18 @@ import static 
org.apache.iotdb.commons.pipe.config.constant.PipeSinkConstant.SIN
 import static 
org.apache.iotdb.commons.pipe.config.constant.PipeSinkConstant.WRITE_BACK_CONNECTOR_SKIP_IF_DEFAULT_VALUE;
 import static 
org.apache.iotdb.commons.utils.ErrorHandlingCommonUtils.getRootCause;
 import static 
org.apache.iotdb.db.exception.metadata.DatabaseNotSetException.DATABASE_NOT_SET;
+import static org.apache.tsfile.common.constant.TsFileConstant.PATH_SEPARATOR;
 
 @TreeModel
 @TableModel
 public class WriteBackSink implements PipeConnector {
 
   private static final Logger LOGGER = 
LoggerFactory.getLogger(WriteBackSink.class);
+  private static final String CONNECTOR_IOTDB_DATABASE_KEY = 
"connector.database";
+  private static final String SINK_IOTDB_DATABASE_KEY = "sink.database";
 
   // Simulate the behavior of the client-to-server communication
   // for correctly handling data insertion in IoTDBReceiverAgent#receive method
-  private static final Coordinator COORDINATOR = Coordinator.getInstance();
-  private static final SessionManager SESSION_MANAGER = 
SessionManager.getInstance();
   public static final AtomicLong id = new AtomicLong();
   private InternalClientSession session;
 
@@ -121,17 +134,110 @@ public class WriteBackSink implements PipeConnector {
   private boolean useEventUserName;
 
   private UserEntity userEntity;
-
-  private static final SqlParser RELATIONAL_SQL_PARSER = new SqlParser();
+  private String targetTableModelDatabaseName;
+  private String invalidTargetTableModelDatabaseName;
+  private String targetTreeModelDatabaseName;
 
   private static final Set<String> ALREADY_CREATED_DATABASES = 
ConcurrentHashMap.newKeySet();
 
+  private static SessionManager getSessionManager() {
+    return SessionManagerHolder.INSTANCE;
+  }
+
+  private static SqlParser getRelationalSqlParser() {
+    return SqlParserHolder.INSTANCE;
+  }
+
+  private static class SessionManagerHolder {
+
+    private static final SessionManager INSTANCE = 
SessionManager.getInstance();
+
+    private SessionManagerHolder() {
+      // empty constructor
+    }
+  }
+
+  private static class SqlParserHolder {
+
+    private static final SqlParser INSTANCE = new SqlParser();
+
+    private SqlParserHolder() {
+      // empty constructor
+    }
+  }
+
   @Override
   public void validate(final PipeParameterValidator validator) throws 
Exception {
     validator.validateSynonymAttributes(
         Arrays.asList(CONNECTOR_IOTDB_USER_KEY, SINK_IOTDB_USER_KEY),
         Arrays.asList(CONNECTOR_IOTDB_USERNAME_KEY, SINK_IOTDB_USERNAME_KEY),
         false);
+    validator.validateSynonymAttributes(
+        Collections.singletonList(CONNECTOR_IOTDB_DATABASE_KEY),
+        Collections.singletonList(SINK_IOTDB_DATABASE_KEY),
+        false);
+
+    final String targetDatabase =
+        validator
+            .getParameters()
+            .getStringByKeys(CONNECTOR_IOTDB_DATABASE_KEY, 
SINK_IOTDB_DATABASE_KEY);
+    if (Objects.nonNull(targetDatabase)) {
+      validateTargetDatabase(targetDatabase);
+    }
+  }
+
+  private static void validateTargetDatabase(final String targetDatabase) {
+    if (PathUtils.isTableModelDatabase(targetDatabase)) {
+      validateTableModelDatabaseName(targetDatabase);
+      
validateAndNormalizeTreeModelDatabaseName(PathUtils.qualifyDatabaseName(targetDatabase));
+      return;
+    }
+
+    validateAndNormalizeTreeModelDatabaseName(targetDatabase);
+  }
+
+  private static void validateTableModelDatabaseName(final String 
databaseName) {
+    try {
+      TableConfigTaskVisitor.validateDatabaseName(databaseName);
+    } catch (final Exception e) {
+      throw new PipeException(
+          String.format(
+              DataNodePipeMessages.TABLE_MODEL_DATABASE_INVALID_FMT,
+              databaseName,
+              PATH_SEPARATOR,
+              IoTDBConfig.DATABASE_PATTERN,
+              MAX_DATABASE_NAME_LENGTH),
+          e);
+    }
+  }
+
+  private static String validateAndNormalizeTreeModelDatabaseName(final String 
databaseName) {
+    try {
+      final PartialPath databasePath = new PartialPath(databaseName);
+      final String[] nodes = databasePath.getNodes();
+      if (nodes.length <= 1 || !IoTDBConstant.PATH_ROOT.equals(nodes[0])) {
+        throw new IllegalPathException(
+            databaseName, "the database name in tree model must start with 
'root.'.");
+      }
+
+      final String normalizedDatabaseName = databasePath.getFullPath();
+      MetaFormatUtils.checkDatabase(normalizedDatabaseName);
+
+      if (normalizedDatabaseName.length() > MAX_DATABASE_NAME_LENGTH) {
+        throw new IllegalPathException(
+            normalizedDatabaseName,
+            "the length of database name shall not exceed " + 
MAX_DATABASE_NAME_LENGTH);
+      }
+      return normalizedDatabaseName;
+    } catch (final Exception e) {
+      throw new PipeException(
+          String.format(
+              DataNodePipeMessages.TREE_MODEL_DATABASE_INVALID_FMT,
+              databaseName,
+              IoTDBConfig.DATABASE_PATTERN,
+              MAX_DATABASE_NAME_LENGTH),
+          e);
+    }
   }
 
   @Override
@@ -192,13 +298,20 @@ public class WriteBackSink implements PipeConnector {
             Arrays.asList(CONNECTOR_USE_EVENT_USER_NAME_KEY, 
SINK_USE_EVENT_USER_NAME_KEY),
             CONNECTOR_USE_EVENT_USER_NAME_DEFAULT_VALUE);
 
-    if (SESSION_MANAGER.getCurrSession() == null) {
-      SESSION_MANAGER.registerSession(session);
+    final String targetDatabase =
+        parameters.getStringByKeys(CONNECTOR_IOTDB_DATABASE_KEY, 
SINK_IOTDB_DATABASE_KEY);
+    if (Objects.nonNull(targetDatabase)) {
+      customizeTargetDatabase(targetDatabase);
+    }
+
+    final SessionManager sessionManager = getSessionManager();
+    if (sessionManager.getCurrSession() == null) {
+      sessionManager.registerSession(session);
     }
 
     // Check the password and its expiration
     if (Objects.nonNull(passwordString)
-        && SESSION_MANAGER
+        && sessionManager
                 .login(
                     session,
                     usernameString,
@@ -215,6 +328,35 @@ public class WriteBackSink implements PipeConnector {
     }
   }
 
+  private void customizeTargetDatabase(final String targetDatabase) {
+    targetTableModelDatabaseName = null;
+    invalidTargetTableModelDatabaseName = null;
+    targetTreeModelDatabaseName = null;
+
+    // The sink only sees its own parameters during customization, without the 
pipe's isolated
+    // runtime model. Normalize one configured target database to both model 
names, and later use
+    // the one matching the incoming event model.
+    if (PathUtils.isTableModelDatabase(targetDatabase)) {
+      targetTableModelDatabaseName = 
targetDatabase.toLowerCase(Locale.ENGLISH);
+      targetTreeModelDatabaseName =
+          validateAndNormalizeTreeModelDatabaseName(
+              PathUtils.qualifyDatabaseName(targetTableModelDatabaseName));
+      return;
+    }
+
+    targetTreeModelDatabaseName = 
validateAndNormalizeTreeModelDatabaseName(targetDatabase);
+    final String tableModelDatabaseName =
+        
PathUtils.unQualifyDatabaseName(targetTreeModelDatabaseName).toLowerCase(Locale.ENGLISH);
+    try {
+      TableConfigTaskVisitor.validateDatabaseName(tableModelDatabaseName);
+      targetTableModelDatabaseName = tableModelDatabaseName;
+    } catch (final Exception e) {
+      // A valid multi-level tree database like root.target.db cannot be 
converted to a valid
+      // table-model database name, but tree-model events can still use the 
original target.
+      invalidTargetTableModelDatabaseName = tableModelDatabaseName;
+    }
+  }
+
   @Override
   public void handshake() throws Exception {
     // Do nothing
@@ -266,13 +408,19 @@ public class WriteBackSink implements PipeConnector {
     final InsertNode insertNode = 
pipeInsertNodeTabletInsertionEvent.getInsertNode();
     final String dataBaseName =
         pipeInsertNodeTabletInsertionEvent.isTableModelEvent()
-            ? pipeInsertNodeTabletInsertionEvent.getTableModelDatabaseName()
-            : pipeInsertNodeTabletInsertionEvent.getTreeModelDatabaseName();
+            ? getTargetTableModelDatabaseNameOrDefault(
+                pipeInsertNodeTabletInsertionEvent.getTableModelDatabaseName())
+            : getTargetTreeModelDatabaseNameOrDefault(
+                pipeInsertNodeTabletInsertionEvent.getTreeModelDatabaseName());
 
     final InsertBaseStatement insertBaseStatement;
     insertBaseStatement =
         PipeTransferTabletInsertNodeReqV2.toTabletInsertNodeReq(insertNode, 
dataBaseName)
             .constructStatement();
+    if (!insertBaseStatement.isWriteToTable()) {
+      rewriteTreeModelDatabaseNameIfNecessary(
+          insertBaseStatement, 
pipeInsertNodeTabletInsertionEvent.getTreeModelDatabaseName());
+    }
 
     final TSStatus status =
         insertBaseStatement.isWriteToTable()
@@ -310,8 +458,10 @@ public class WriteBackSink implements PipeConnector {
       throws PipeException {
     final String dataBaseName =
         pipeRawTabletInsertionEvent.isTableModelEvent()
-            ? pipeRawTabletInsertionEvent.getTableModelDatabaseName()
-            : pipeRawTabletInsertionEvent.getTreeModelDatabaseName();
+            ? getTargetTableModelDatabaseNameOrDefault(
+                pipeRawTabletInsertionEvent.getTableModelDatabaseName())
+            : getTargetTreeModelDatabaseNameOrDefault(
+                pipeRawTabletInsertionEvent.getTreeModelDatabaseName());
 
     final InsertTabletStatement insertTabletStatement =
         PipeTransferTabletRawReqV2.toTPipeTransferRawReq(
@@ -319,6 +469,10 @@ public class WriteBackSink implements PipeConnector {
                 pipeRawTabletInsertionEvent.isAligned(),
                 dataBaseName)
             .constructStatement();
+    if (!insertTabletStatement.isWriteToTable()) {
+      rewriteTreeModelDatabaseNameIfNecessary(
+          insertTabletStatement, 
pipeRawTabletInsertionEvent.getTreeModelDatabaseName());
+    }
 
     final TSStatus status =
         insertTabletStatement.isWriteToTable()
@@ -362,15 +516,24 @@ public class WriteBackSink implements PipeConnector {
   private void doTransfer(final PipeStatementInsertionEvent 
pipeStatementInsertionEvent)
       throws PipeException {
 
-    final TSStatus status =
-        pipeStatementInsertionEvent.isTableModelEvent()
-            ? executeStatementForTableModel(
-                pipeStatementInsertionEvent.getStatement(),
-                pipeStatementInsertionEvent.getTableModelDatabaseName(),
-                pipeStatementInsertionEvent.getUserName())
-            : executeStatementForTreeModel(
-                pipeStatementInsertionEvent.getStatement(),
-                pipeStatementInsertionEvent.getUserName());
+    final TSStatus status;
+    if (pipeStatementInsertionEvent.isTableModelEvent()) {
+      final String dataBaseName =
+          getTargetTableModelDatabaseNameOrDefault(
+              pipeStatementInsertionEvent.getTableModelDatabaseName());
+      status =
+          executeStatementForTableModel(
+              
rewriteTableModelDatabaseNameIfNecessary(pipeStatementInsertionEvent.getStatement()),
+              dataBaseName,
+              pipeStatementInsertionEvent.getUserName());
+    } else {
+      status =
+          executeStatementForTreeModel(
+              rewriteTreeModelDatabaseNameIfNecessary(
+                  pipeStatementInsertionEvent.getStatement(),
+                  pipeStatementInsertionEvent.getTreeModelDatabaseName()),
+              pipeStatementInsertionEvent.getUserName());
+    }
 
     if (status.getCode() != TSStatusCode.REDIRECTION_RECOMMEND.getStatusCode()
         && status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()
@@ -384,6 +547,166 @@ public class WriteBackSink implements PipeConnector {
     }
   }
 
+  private String getTargetTableModelDatabaseNameOrDefault(final String 
databaseName) {
+    if (Objects.nonNull(invalidTargetTableModelDatabaseName)) {
+      throw new PipeException(
+          String.format(
+              DataNodePipeMessages
+                  
.TARGET_TREE_MODEL_DATABASE_CANNOT_BE_USED_FOR_TABLE_MODEL_EVENTS_FMT,
+              targetTreeModelDatabaseName,
+              invalidTargetTableModelDatabaseName));
+    }
+
+    validateTableModelDatabaseName(databaseName);
+    return Objects.nonNull(targetTableModelDatabaseName)
+        ? targetTableModelDatabaseName
+        : databaseName;
+  }
+
+  private String getTargetTreeModelDatabaseNameOrDefault(final String 
databaseName) {
+    final String sourceTreeModelDatabaseName =
+        validateAndNormalizeTreeModelDatabaseName(databaseName);
+    return Objects.nonNull(targetTreeModelDatabaseName)
+        ? targetTreeModelDatabaseName
+        : sourceTreeModelDatabaseName;
+  }
+
+  private Statement rewriteTableModelDatabaseNameIfNecessary(final Statement 
statement) {
+    if (Objects.isNull(targetTableModelDatabaseName)
+        || !(statement instanceof InsertBaseStatement)) {
+      return statement;
+    }
+
+    rewriteTableModelDatabaseName((InsertBaseStatement) statement);
+    return statement;
+  }
+
+  private void rewriteTableModelDatabaseName(final InsertBaseStatement 
statement) {
+    statement.setDatabaseName(targetTableModelDatabaseName);
+
+    if (statement instanceof InsertRowsStatement) {
+      ((InsertRowsStatement) statement)
+          .getInsertRowStatementList()
+          .forEach(this::rewriteTableModelDatabaseName);
+    } else if (statement instanceof InsertRowsOfOneDeviceStatement) {
+      ((InsertRowsOfOneDeviceStatement) statement)
+          .getInsertRowStatementList()
+          .forEach(this::rewriteTableModelDatabaseName);
+    } else if (statement instanceof InsertMultiTabletsStatement) {
+      ((InsertMultiTabletsStatement) statement)
+          .getInsertTabletStatementList()
+          .forEach(this::rewriteTableModelDatabaseName);
+    }
+  }
+
+  private Statement rewriteTreeModelDatabaseNameIfNecessary(
+      final Statement statement, final String sourceTreeModelDatabaseName) {
+    if (!(statement instanceof InsertBaseStatement)) {
+      return statement;
+    }
+
+    return rewriteTreeModelDatabaseNameIfNecessary(
+        (InsertBaseStatement) statement, sourceTreeModelDatabaseName);
+  }
+
+  private InsertBaseStatement rewriteTreeModelDatabaseNameIfNecessary(
+      final InsertBaseStatement statement, final String 
sourceTreeModelDatabaseName) {
+    final String normalizedSourceTreeModelDatabaseName =
+        validateAndNormalizeTreeModelDatabaseName(sourceTreeModelDatabaseName);
+    if (Objects.isNull(targetTreeModelDatabaseName)) {
+      return statement;
+    }
+
+    rewriteTreeModelDatabaseName(statement, 
normalizedSourceTreeModelDatabaseName);
+    return statement;
+  }
+
+  private void rewriteTreeModelDatabaseName(
+      final InsertBaseStatement statement, final String 
sourceTreeModelDatabaseName) {
+    statement.setDatabaseName(targetTreeModelDatabaseName);
+
+    if (statement instanceof InsertRowsStatement) {
+      ((InsertRowsStatement) statement)
+          .getInsertRowStatementList()
+          .forEach(
+              rowStatement ->
+                  rewriteTreeModelDatabaseName(rowStatement, 
sourceTreeModelDatabaseName));
+      return;
+    }
+
+    if (statement instanceof InsertRowsOfOneDeviceStatement) {
+      final InsertRowsOfOneDeviceStatement insertRowsOfOneDeviceStatement =
+          (InsertRowsOfOneDeviceStatement) statement;
+      insertRowsOfOneDeviceStatement
+          .getInsertRowStatementList()
+          .forEach(
+              rowStatement ->
+                  rewriteTreeModelDatabaseName(rowStatement, 
sourceTreeModelDatabaseName));
+      insertRowsOfOneDeviceStatement.setDevicePath(
+          rewriteTreeModelDevicePath(
+              insertRowsOfOneDeviceStatement.getDevicePath(), 
sourceTreeModelDatabaseName));
+      return;
+    }
+
+    if (statement instanceof InsertMultiTabletsStatement) {
+      ((InsertMultiTabletsStatement) statement)
+          .getInsertTabletStatementList()
+          .forEach(
+              tabletStatement ->
+                  rewriteTreeModelDatabaseName(tabletStatement, 
sourceTreeModelDatabaseName));
+      return;
+    }
+
+    statement.setDevicePath(
+        rewriteTreeModelDevicePath(statement.getDevicePath(), 
sourceTreeModelDatabaseName));
+  }
+
+  private PartialPath rewriteTreeModelDevicePath(
+      final PartialPath devicePath, final String sourceTreeModelDatabaseName) {
+    if (Objects.isNull(devicePath) || 
Objects.isNull(sourceTreeModelDatabaseName)) {
+      return devicePath;
+    }
+
+    try {
+      final String[] sourceDatabaseNodes = new 
PartialPath(sourceTreeModelDatabaseName).getNodes();
+      final String[] targetDatabaseNodes = new 
PartialPath(targetTreeModelDatabaseName).getNodes();
+      final String[] deviceNodes = devicePath.getNodes();
+      // A processor may rewrite the device path before write-back sink 
receives the event.
+      // If it no longer belongs to the source database, keep it untouched to 
avoid corruption.
+      if (!startsWith(deviceNodes, sourceDatabaseNodes)) {
+        return devicePath;
+      }
+
+      final ArrayList<String> rebasedNodes =
+          new ArrayList<>(
+              targetDatabaseNodes.length + deviceNodes.length - 
sourceDatabaseNodes.length);
+      rebasedNodes.addAll(Arrays.asList(targetDatabaseNodes));
+      rebasedNodes.addAll(
+          Arrays.asList(deviceNodes).subList(sourceDatabaseNodes.length, 
deviceNodes.length));
+      return new PartialPath(rebasedNodes.toArray(new String[0]));
+    } catch (final Exception e) {
+      throw new PipeException(
+          String.format(
+              DataNodePipeMessages.FAILED_TO_REWRITE_TREE_MODEL_DATABASE_FMT,
+              sourceTreeModelDatabaseName,
+              targetTreeModelDatabaseName,
+              devicePath),
+          e);
+    }
+  }
+
+  private static boolean startsWith(final String[] nodes, final String[] 
prefixNodes) {
+    if (nodes.length < prefixNodes.length) {
+      return false;
+    }
+    for (int i = 0; i < prefixNodes.length; ++i) {
+      if (!Objects.equals(nodes[i], prefixNodes[i])) {
+        return false;
+      }
+    }
+    return true;
+  }
+
   private static void throwWriteBackExceptionIfNecessary(
       final TSStatus status, final String exceptionMessage) {
     if (status.getCode() == TSStatusCode.NO_PERMISSION.getStatusCode()) {
@@ -396,7 +719,9 @@ public class WriteBackSink implements PipeConnector {
   @Override
   public void close() throws Exception {
     if (session != null) {
-      SESSION_MANAGER.closeSession(session, 
COORDINATOR::cleanupQueryExecution, false);
+      getSessionManager()
+          .closeSession(
+              session, queryId -> 
Coordinator.getInstance().cleanupQueryExecution(queryId), false);
     }
   }
 
@@ -413,10 +738,10 @@ public class WriteBackSink implements PipeConnector {
       return Coordinator.getInstance()
           .executeForTableModel(
               new PipeEnrichedStatement(statement),
-              RELATIONAL_SQL_PARSER,
+              getRelationalSqlParser(),
               session,
-              SESSION_MANAGER.requestQueryId(),
-              SESSION_MANAGER.getSessionInfoOfPipeReceiver(session, 
dataBaseName),
+              getSessionManager().requestQueryId(),
+              getSessionManager().getSessionInfoOfPipeReceiver(session, 
dataBaseName),
               "",
               LocalExecutionPlanner.getInstance().metadata,
               
IoTDBDescriptor.getInstance().getConfig().getQueryTimeoutThreshold())
@@ -446,10 +771,10 @@ public class WriteBackSink implements PipeConnector {
         return Coordinator.getInstance()
             .executeForTableModel(
                 new PipeEnrichedStatement(statement),
-                RELATIONAL_SQL_PARSER,
+                getRelationalSqlParser(),
                 session,
-                SESSION_MANAGER.requestQueryId(),
-                SESSION_MANAGER.getSessionInfo(session),
+                getSessionManager().requestQueryId(),
+                getSessionManager().getSessionInfo(session),
                 "",
                 LocalExecutionPlanner.getInstance().metadata,
                 
IoTDBDescriptor.getInstance().getConfig().getQueryTimeoutThreshold())
@@ -534,8 +859,8 @@ public class WriteBackSink implements PipeConnector {
       return Coordinator.getInstance()
           .executeForTreeModel(
               new PipeEnrichedStatement(statement),
-              SESSION_MANAGER.requestQueryId(),
-              SESSION_MANAGER.getSessionInfo(session),
+              getSessionManager().requestQueryId(),
+              getSessionManager().getSessionInfo(session),
               "",
               ClusterPartitionFetcher.getInstance(),
               ClusterSchemaFetcher.getInstance(),
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/sink/PipeSinkTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/sink/PipeSinkTest.java
index cf311639ee9..fa18695ef1f 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/sink/PipeSinkTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/sink/PipeSinkTest.java
@@ -24,6 +24,7 @@ import 
org.apache.iotdb.commons.pipe.agent.task.progress.CommitterKey;
 import org.apache.iotdb.commons.pipe.config.constant.PipeSinkConstant;
 import 
org.apache.iotdb.commons.pipe.config.plugin.configuraion.PipeTaskRuntimeConfiguration;
 import 
org.apache.iotdb.commons.pipe.config.plugin.env.PipeTaskSinkRuntimeEnvironment;
+import 
org.apache.iotdb.db.pipe.event.common.statement.PipeStatementInsertionEvent;
 import 
org.apache.iotdb.db.pipe.event.common.tablet.PipeRawTabletInsertionEvent;
 import org.apache.iotdb.db.pipe.sink.protocol.legacy.IoTDBLegacyPipeSink;
 import org.apache.iotdb.db.pipe.sink.protocol.opcua.OpcUaSink;
@@ -31,6 +32,8 @@ import 
org.apache.iotdb.db.pipe.sink.protocol.thrift.async.IoTDBDataRegionAsyncS
 import 
org.apache.iotdb.db.pipe.sink.protocol.thrift.sync.IoTDBDataRegionSyncSink;
 import 
org.apache.iotdb.db.pipe.sink.protocol.websocket.WebSocketConnectorServer;
 import org.apache.iotdb.db.pipe.sink.protocol.websocket.WebSocketSink;
+import org.apache.iotdb.db.pipe.sink.protocol.writeback.WriteBackSink;
+import 
org.apache.iotdb.db.queryengine.plan.statement.crud.InsertTabletStatement;
 import org.apache.iotdb.pipe.api.customizer.parameter.PipeParameterValidator;
 import org.apache.iotdb.pipe.api.customizer.parameter.PipeParameters;
 import org.apache.iotdb.pipe.api.exception.PipeException;
@@ -43,8 +46,10 @@ import org.junit.Assert;
 import org.junit.Test;
 import org.mockito.Mockito;
 
+import java.lang.reflect.Field;
 import java.security.SecureRandom;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 
@@ -279,6 +284,214 @@ public class PipeSinkTest {
     }
   }
 
+  @Test
+  public void testWriteBackSinkTargetDatabaseValidation() throws Exception {
+    assertWriteBackSinkTargetDatabaseValid("target");
+    assertWriteBackSinkTargetDatabaseValid("root.target");
+    assertWriteBackSinkTargetDatabaseValid("root.target.db");
+
+    Assert.assertThrows(PipeException.class, () -> 
assertWriteBackSinkTargetDatabaseValid("a.b"));
+    Assert.assertThrows(
+        PipeException.class, () -> 
assertWriteBackSinkTargetDatabaseValid("a".repeat(65)));
+    Assert.assertThrows(
+        PipeException.class, () -> 
assertWriteBackSinkTargetDatabaseValid("root.a+b"));
+    Assert.assertThrows(
+        PipeException.class,
+        () -> assertWriteBackSinkTargetDatabaseValid("root." + 
"a".repeat(60)));
+  }
+
+  @Test
+  public void testWriteBackSinkTargetDatabaseCustomization() throws Exception {
+    try (final WriteBackSink sink = 
createCustomizedWriteBackSink("TestTarget")) {
+      Assert.assertEquals(
+          "testtarget", getWriteBackSinkDatabaseName(sink, 
"targetTableModelDatabaseName"));
+      Assert.assertNull(getWriteBackSinkDatabaseName(sink, 
"invalidTargetTableModelDatabaseName"));
+      Assert.assertEquals(
+          "root.testtarget", getWriteBackSinkDatabaseName(sink, 
"targetTreeModelDatabaseName"));
+    }
+
+    try (final WriteBackSink sink = 
createCustomizedWriteBackSink("root.target")) {
+      Assert.assertEquals(
+          "target", getWriteBackSinkDatabaseName(sink, 
"targetTableModelDatabaseName"));
+      Assert.assertNull(getWriteBackSinkDatabaseName(sink, 
"invalidTargetTableModelDatabaseName"));
+      Assert.assertEquals(
+          "root.target", getWriteBackSinkDatabaseName(sink, 
"targetTreeModelDatabaseName"));
+    }
+
+    try (final WriteBackSink sink = 
createCustomizedWriteBackSink("root.target.db")) {
+      Assert.assertNull(getWriteBackSinkDatabaseName(sink, 
"targetTableModelDatabaseName"));
+      Assert.assertEquals(
+          "target.db", getWriteBackSinkDatabaseName(sink, 
"invalidTargetTableModelDatabaseName"));
+      Assert.assertEquals(
+          "root.target.db", getWriteBackSinkDatabaseName(sink, 
"targetTreeModelDatabaseName"));
+    }
+  }
+
+  @Test
+  public void testWriteBackSinkRejectsInvalidTableModelDatabaseFromEvent() {
+    try (final WriteBackSink sink = new WriteBackSink()) {
+      final PipeRawTabletInsertionEvent event = 
createTableModelRawTabletInsertionEvent("root.a.b");
+      Assert.assertThrows(PipeException.class, () -> sink.transfer(event));
+    } catch (final Exception e) {
+      Assert.fail(e.getMessage());
+    }
+  }
+
+  @Test
+  public void 
testWriteBackSinkRejectsInvalidTableModelDatabaseFromEventWithTargetDatabase()
+      throws Exception {
+    final PipeParameters parameters =
+        new PipeParameters(Collections.singletonMap("sink.database", 
"target"));
+
+    try (final WriteBackSink sink = new WriteBackSink()) {
+      sink.validate(new PipeParameterValidator(parameters));
+      sink.customize(
+          parameters,
+          new PipeTaskRuntimeConfiguration(new 
PipeTaskSinkRuntimeEnvironment("pipe", 1L, 1)));
+
+      final PipeRawTabletInsertionEvent event = 
createTableModelRawTabletInsertionEvent("root.a.b");
+      Assert.assertThrows(PipeException.class, () -> sink.transfer(event));
+    }
+  }
+
+  @Test
+  public void 
testWriteBackSinkRejectsInvalidTreeModelDatabaseFromEventWithTargetDatabase()
+      throws Exception {
+    final PipeParameters parameters =
+        new PipeParameters(Collections.singletonMap("sink.database", 
"root.target"));
+
+    try (final WriteBackSink sink = new WriteBackSink()) {
+      sink.validate(new PipeParameterValidator(parameters));
+      sink.customize(
+          parameters,
+          new PipeTaskRuntimeConfiguration(new 
PipeTaskSinkRuntimeEnvironment("pipe", 1L, 1)));
+
+      final PipeRawTabletInsertionEvent event = 
createTreeModelRawTabletInsertionEvent("root.a+b");
+      Assert.assertThrows(PipeException.class, () -> sink.transfer(event));
+    }
+  }
+
+  @Test
+  public void testWriteBackSinkRejectsInvalidStatementEventDatabases() throws 
Exception {
+    try (final WriteBackSink sink = createCustomizedWriteBackSink("target")) {
+      Assert.assertThrows(
+          PipeException.class,
+          () -> 
sink.transfer(createTableModelStatementInsertionEvent("root.a.b")));
+    }
+
+    try (final WriteBackSink sink = 
createCustomizedWriteBackSink("root.target")) {
+      Assert.assertThrows(
+          PipeException.class,
+          () -> 
sink.transfer(createTreeModelStatementInsertionEvent("root.a+b")));
+    }
+
+    try (final WriteBackSink sink = 
createCustomizedWriteBackSink("root.target.db")) {
+      Assert.assertThrows(
+          PipeException.class,
+          () -> 
sink.transfer(createTableModelStatementInsertionEvent("valid_db")));
+    }
+  }
+
+  @Test
+  public void 
testWriteBackSinkRejectsInvalidTableModelDatabaseFromTreeTarget() throws 
Exception {
+    final PipeParameters parameters =
+        new PipeParameters(
+            new HashMap<String, String>() {
+              {
+                put("sink.database", "root.target.db");
+              }
+            });
+
+    try (final WriteBackSink sink = new WriteBackSink()) {
+      sink.validate(new PipeParameterValidator(parameters));
+      sink.customize(
+          parameters,
+          new PipeTaskRuntimeConfiguration(new 
PipeTaskSinkRuntimeEnvironment("pipe", 1L, 1)));
+
+      final PipeRawTabletInsertionEvent event = 
createTableModelRawTabletInsertionEvent("valid_db");
+      Assert.assertThrows(PipeException.class, () -> sink.transfer(event));
+    }
+  }
+
+  private void assertWriteBackSinkTargetDatabaseValid(final String 
targetDatabase)
+      throws Exception {
+    try (final WriteBackSink sink = new WriteBackSink()) {
+      sink.validate(
+          new PipeParameterValidator(
+              new PipeParameters(Collections.singletonMap("sink.database", 
targetDatabase))));
+    }
+  }
+
+  private WriteBackSink createCustomizedWriteBackSink(final String 
targetDatabase)
+      throws Exception {
+    final PipeParameters parameters =
+        new PipeParameters(Collections.singletonMap("sink.database", 
targetDatabase));
+    final WriteBackSink sink = new WriteBackSink();
+    sink.validate(new PipeParameterValidator(parameters));
+    sink.customize(
+        parameters,
+        new PipeTaskRuntimeConfiguration(new 
PipeTaskSinkRuntimeEnvironment("pipe", 1L, 1)));
+    return sink;
+  }
+
+  private String getWriteBackSinkDatabaseName(final WriteBackSink sink, final 
String fieldName)
+      throws Exception {
+    final Field field = WriteBackSink.class.getDeclaredField(fieldName);
+    field.setAccessible(true);
+    return (String) field.get(sink);
+  }
+
+  private PipeRawTabletInsertionEvent createTableModelRawTabletInsertionEvent(
+      final String databaseName) {
+    final List<IMeasurementSchema> schemaList =
+        Arrays.asList(new MeasurementSchema("s1", TSDataType.INT64));
+    final Tablet tablet = new Tablet("table", schemaList, 1);
+    tablet.addTimestamp(0, 1L);
+    tablet.addValue("s1", 0, 1L);
+    return new PipeRawTabletInsertionEvent(
+        true, databaseName, null, null, tablet, false, "pipe", 0L, null, null, 
false);
+  }
+
+  private PipeRawTabletInsertionEvent createTreeModelRawTabletInsertionEvent(
+      final String databaseName) {
+    final List<IMeasurementSchema> schemaList =
+        Arrays.asList(new MeasurementSchema("s1", TSDataType.INT64));
+    final Tablet tablet = new Tablet(databaseName + ".d1", schemaList, 1);
+    tablet.addTimestamp(0, 1L);
+    tablet.addValue("s1", 0, 1L);
+    return new PipeRawTabletInsertionEvent(
+        false, databaseName, null, databaseName, tablet, false, "pipe", 0L, 
null, null, false);
+  }
+
+  private PipeStatementInsertionEvent createTableModelStatementInsertionEvent(
+      final String databaseName) {
+    return createStatementInsertionEvent(true, databaseName);
+  }
+
+  private PipeStatementInsertionEvent createTreeModelStatementInsertionEvent(
+      final String databaseName) {
+    return createStatementInsertionEvent(false, databaseName);
+  }
+
+  private PipeStatementInsertionEvent createStatementInsertionEvent(
+      final boolean isTableModelEvent, final String databaseName) {
+    final InsertTabletStatement statement = new InsertTabletStatement();
+    statement.setRamBytesUsed(1L);
+    return new PipeStatementInsertionEvent(
+        "pipe",
+        0L,
+        null,
+        null,
+        null,
+        null,
+        null,
+        null,
+        true,
+        isTableModelEvent,
+        databaseName,
+        statement);
+  }
+
   private PipeRawTabletInsertionEvent createPipeRawTabletInsertionEvent(
       final String pipeName, final long creationTime, final int regionId) {
     final List<IMeasurementSchema> schemaList =


Reply via email to