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

zhangyv pushed a commit to branch 2.x
in repository https://gitbox.apache.org/repos/asf/incubator-seata.git


The following commit(s) were added to refs/heads/2.x by this push:
     new 9b97559e03 feature: support Oracle Batch Insert (#7675)
9b97559e03 is described below

commit 9b97559e032585d0d8c896273125f1d8fea476b5
Author: maple <[email protected]>
AuthorDate: Fri Oct 17 15:27:17 2025 +0800

    feature: support Oracle Batch Insert (#7675)
---
 changes/en-us/2.x.md                               |   1 +
 changes/zh-cn/2.x.md                               |   1 +
 .../druid/DruidSQLRecognizerFactoryImpl.java       |  10 +
 .../druid/oracle/OracleMultiInsertRecognizer.java  | 264 ++++++++++++++
 .../oracle/OracleOperateRecognizerHolder.java      |   4 +
 .../druid/DruidSQLRecognizerFactoryTest.java       | 146 +++++---
 .../oracle/OracleMultiInsertRecognizerTest.java    | 404 +++++++++++++++++++++
 7 files changed, 783 insertions(+), 47 deletions(-)

diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md
index 83fdc753a5..ecbabfb7b7 100644
--- a/changes/en-us/2.x.md
+++ b/changes/en-us/2.x.md
@@ -27,6 +27,7 @@ Add changes here for all PR submitted to the 2.x branch.
 - [[#7559](https://github.com/apache/incubator-seata/pull/7559)] Introduce 
Cleanup API for TableMetaRefreshHolder Instance
 - [[#7669](https://github.com/apache/incubator-seata/pull/7669)] add support 
for Jackson serialization and deserialization of PostgreSQL array types
 - [[#7664](https://github.com/apache/incubator-seata/pull/7664)] support 
shentongdatabase XA mode
+- [[#7675](https://github.com/apache/incubator-seata/pull/7675)] support 
Oracle Batch Insert
 - [[#7663](https://github.com/apache/incubator-seata/pull/7663)] add Java 25 
support in CI configuration files
 
 
diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md
index cb247e0fc6..dc6c1a8459 100644
--- a/changes/zh-cn/2.x.md
+++ b/changes/zh-cn/2.x.md
@@ -27,6 +27,7 @@
 - [[#7559](https://github.com/apache/incubator-seata/pull/7559)] 为 
TableMetaRefreshHolder 实例引入清理 API
 - [[#7669](https://github.com/apache/incubator-seata/pull/7669)] 添加对 Jackson 
序列化和反序列化 PostgreSQL 数组类型的支持
 - [[#7664](https://github.com/apache/incubator-seata/pull/7565)] 支持神通数据库的XA模式
+- [[#7675](https://github.com/apache/incubator-seata/pull/7675)] 支持Oracle批量插入
 - [[#7663](https://github.com/apache/incubator-seata/pull/7663)] 
支持java25版本的CI流水綫
 
 
diff --git 
a/sqlparser/seata-sqlparser-druid/src/main/java/org/apache/seata/sqlparser/druid/DruidSQLRecognizerFactoryImpl.java
 
b/sqlparser/seata-sqlparser-druid/src/main/java/org/apache/seata/sqlparser/druid/DruidSQLRecognizerFactoryImpl.java
index 02d8ada742..90820f84fc 100644
--- 
a/sqlparser/seata-sqlparser-druid/src/main/java/org/apache/seata/sqlparser/druid/DruidSQLRecognizerFactoryImpl.java
+++ 
b/sqlparser/seata-sqlparser-druid/src/main/java/org/apache/seata/sqlparser/druid/DruidSQLRecognizerFactoryImpl.java
@@ -23,10 +23,12 @@ import 
com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
 import com.alibaba.druid.sql.ast.statement.SQLReplaceStatement;
 import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
 import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement;
+import 
com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMultiInsertStatement;
 import org.apache.seata.common.exception.NotSupportYetException;
 import org.apache.seata.common.util.CollectionUtils;
 import org.apache.seata.sqlparser.SQLRecognizer;
 import org.apache.seata.sqlparser.SQLRecognizerFactory;
+import org.apache.seata.sqlparser.druid.oracle.OracleOperateRecognizerHolder;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -72,6 +74,14 @@ class DruidSQLRecognizerFactoryImpl implements 
SQLRecognizerFactory {
                 recognizer = recognizerHolder.getDeleteRecognizer(sql, 
sqlStatement);
             } else if (sqlStatement instanceof SQLSelectStatement) {
                 recognizer = 
recognizerHolder.getSelectForUpdateRecognizer(sql, sqlStatement);
+            } else if (sqlStatement instanceof OracleMultiInsertStatement) {
+                OracleMultiInsertStatement stmt = (OracleMultiInsertStatement) 
sqlStatement;
+                if (stmt.getOption() == 
OracleMultiInsertStatement.Option.FIRST) {
+                    throw new NotSupportYetException("INSERT FIRST not 
supported yet");
+                }
+                // Use specialized methods to handle Oracle bulk inserts
+                recognizer =
+                        ((OracleOperateRecognizerHolder) 
recognizerHolder).getMultiInsertRecognizer(sql, sqlStatement);
             }
 
             // When recognizer is null, it indicates that recognizerHolder 
cannot allocate unsupported syntax, like
diff --git 
a/sqlparser/seata-sqlparser-druid/src/main/java/org/apache/seata/sqlparser/druid/oracle/OracleMultiInsertRecognizer.java
 
b/sqlparser/seata-sqlparser-druid/src/main/java/org/apache/seata/sqlparser/druid/oracle/OracleMultiInsertRecognizer.java
new file mode 100644
index 0000000000..08a445c722
--- /dev/null
+++ 
b/sqlparser/seata-sqlparser-druid/src/main/java/org/apache/seata/sqlparser/druid/oracle/OracleMultiInsertRecognizer.java
@@ -0,0 +1,264 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.seata.sqlparser.druid.oracle;
+
+import com.alibaba.druid.sql.ast.SQLExpr;
+import com.alibaba.druid.sql.ast.SQLStatement;
+import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
+import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
+import com.alibaba.druid.sql.ast.expr.SQLNullExpr;
+import com.alibaba.druid.sql.ast.expr.SQLSequenceExpr;
+import com.alibaba.druid.sql.ast.expr.SQLValuableExpr;
+import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
+import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
+import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
+import 
com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMultiInsertStatement;
+import com.alibaba.druid.sql.dialect.oracle.visitor.OracleOutputVisitor;
+import org.apache.seata.common.exception.NotSupportYetException;
+import org.apache.seata.common.util.CollectionUtils;
+import org.apache.seata.sqlparser.SQLInsertRecognizer;
+import org.apache.seata.sqlparser.SQLType;
+import org.apache.seata.sqlparser.struct.NotPlaceholderExpr;
+import org.apache.seata.sqlparser.struct.Null;
+import org.apache.seata.sqlparser.struct.SqlMethodExpr;
+import org.apache.seata.sqlparser.struct.SqlSequenceExpr;
+import org.apache.seata.sqlparser.util.ColumnUtils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Oracle Multi Insert Recognizer for INSERT ALL statements
+ */
+public class OracleMultiInsertRecognizer extends BaseOracleRecognizer 
implements SQLInsertRecognizer {
+
+    private final OracleMultiInsertStatement ast;
+    private String validatedTableName;
+    private List<String> validatedColumns;
+
+    public OracleMultiInsertRecognizer(String originalSQL, SQLStatement ast) {
+        super(originalSQL);
+        this.ast = (OracleMultiInsertStatement) ast;
+        validateSingleTableConsistency();
+    }
+
+    /**
+     * Verifies that all entries are in the same table and have consistent 
column definitions.
+     * <p>
+     * If validation fails (e.g., conditional clauses are present, or 
table/column consistency is violated),
+     * this method throws a {@link NotSupportYetException}.
+     * <p>
+     * Upon successful validation, initializes {@code validatedTableName} and 
{@code validatedColumns}
+     * with the consistent table name and column definitions.
+     */
+    private void validateSingleTableConsistency() {
+        if (CollectionUtils.isEmpty(ast.getEntries())) {
+            return;
+        }
+
+        String firstTableName = null;
+        List<String> firstColumns = null;
+
+        for (OracleMultiInsertStatement.Entry entry : ast.getEntries()) {
+            // Check whether conditional insertion is included. It is not 
supported yet.
+            if (entry instanceof 
OracleMultiInsertStatement.ConditionalInsertClause) {
+                throw new NotSupportYetException(
+                        "Oracle Multi Insert with conditional clauses 
(WHEN...THEN) is not supported yet. " + "SQL: "
+                                + getOriginalSQL());
+            }
+            if (entry instanceof OracleMultiInsertStatement.InsertIntoClause) {
+                OracleMultiInsertStatement.InsertIntoClause insertClause =
+                        (OracleMultiInsertStatement.InsertIntoClause) entry;
+
+                // Get the current table name
+                String currentTableName = getTableNameFromClause(insertClause);
+                if (currentTableName == null) {
+                    continue;
+                }
+
+                // Get current column information
+                List<String> currentColumns = 
getColumnsFromClause(insertClause);
+
+                if (firstTableName == null) {
+                    firstTableName = currentTableName;
+                    firstColumns = currentColumns;
+                } else {
+                    // Check whether the table names are consistent
+                    if (!firstTableName.equalsIgnoreCase(currentTableName)) {
+                        throw new NotSupportYetException(
+                                "Oracle Multi Insert with different tables is 
not supported yet. " + "Found tables: "
+                                        + firstTableName + " and " + 
currentTableName + ". SQL: "
+                                        + getOriginalSQL());
+                    }
+
+                    // Check that column definitions are consistent
+                    if (!Objects.equals(firstColumns, currentColumns)) {
+                        throw new NotSupportYetException(
+                                "Oracle Multi Insert with different column 
definitions is not supported yet. "
+                                        + "Table: " + firstTableName + ". SQL: 
" + getOriginalSQL());
+                    }
+                }
+            }
+        }
+
+        this.validatedTableName = firstTableName;
+        this.validatedColumns = firstColumns;
+    }
+
+    private String 
getTableNameFromClause(OracleMultiInsertStatement.InsertIntoClause 
insertClause) {
+        if (insertClause.getTableSource() != null) {
+            StringBuilder sb = new StringBuilder();
+            OracleOutputVisitor visitor = new OracleOutputVisitor(sb) {
+                @Override
+                public boolean visit(SQLExprTableSource x) {
+                    printTableSourceExpr(x.getExpr());
+                    return false;
+                }
+            };
+            visitor.visit(insertClause.getTableSource());
+            return sb.toString();
+        }
+        return null;
+    }
+
+    private List<String> 
getColumnsFromClause(OracleMultiInsertStatement.InsertIntoClause insertClause) {
+        if (CollectionUtils.isEmpty(insertClause.getColumns())) {
+            return Collections.emptyList();
+        }
+
+        List<String> columns = new ArrayList<>();
+        for (SQLExpr expr : insertClause.getColumns()) {
+            if (expr instanceof SQLIdentifierExpr) {
+                columns.add(((SQLIdentifierExpr) expr).getName());
+            } else {
+                // Handling non-standard column names
+                wrapSQLParsingException(expr);
+            }
+        }
+        return columns;
+    }
+
+    @Override
+    public SQLType getSQLType() {
+        return SQLType.INSERT;
+    }
+
+    @Override
+    public String getTableName() {
+        return validatedTableName;
+    }
+
+    @Override
+    public String getTableAlias() {
+        if (!CollectionUtils.isEmpty(ast.getEntries())) {
+            OracleMultiInsertStatement.Entry firstEntry = 
ast.getEntries().get(0);
+            if (firstEntry instanceof 
OracleMultiInsertStatement.InsertIntoClause) {
+                OracleMultiInsertStatement.InsertIntoClause insertClause =
+                        (OracleMultiInsertStatement.InsertIntoClause) 
firstEntry;
+                if (insertClause.getTableSource() != null) {
+                    return insertClause.getTableSource().getAlias();
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public List<String> getInsertColumns() {
+        return validatedColumns;
+    }
+
+    @Override
+    public boolean insertColumnsIsEmpty() {
+        return CollectionUtils.isEmpty(validatedColumns);
+    }
+
+    @Override
+    public List<List<Object>> getInsertRows(Collection<Integer> 
primaryKeyIndex) {
+        List<List<Object>> allRows = new ArrayList<>();
+
+        if (!CollectionUtils.isEmpty(ast.getEntries())) {
+            for (OracleMultiInsertStatement.Entry entry : ast.getEntries()) {
+                if (entry instanceof 
OracleMultiInsertStatement.InsertIntoClause) {
+                    OracleMultiInsertStatement.InsertIntoClause insertClause =
+                            (OracleMultiInsertStatement.InsertIntoClause) 
entry;
+
+                    if 
(!CollectionUtils.isEmpty(insertClause.getValuesList())) {
+                        for (SQLInsertStatement.ValuesClause valuesClause : 
insertClause.getValuesList()) {
+                            List<SQLExpr> exprs = valuesClause.getValues();
+                            List<Object> row = new ArrayList<>(exprs.size());
+                            allRows.add(row);
+
+                            for (int i = 0, len = exprs.size(); i < len; i++) {
+                                SQLExpr expr = exprs.get(i);
+                                if (expr instanceof SQLNullExpr) {
+                                    row.add(Null.get());
+                                } else if (expr instanceof SQLValuableExpr) {
+                                    row.add(((SQLValuableExpr) 
expr).getValue());
+                                } else if (expr instanceof SQLVariantRefExpr) {
+                                    row.add(((SQLVariantRefExpr) 
expr).getName());
+                                } else if (expr instanceof 
SQLMethodInvokeExpr) {
+                                    row.add(SqlMethodExpr.get());
+                                } else if (expr instanceof SQLSequenceExpr) {
+                                    SQLSequenceExpr sequenceExpr = 
(SQLSequenceExpr) expr;
+                                    String sequence = 
sequenceExpr.getSequence().getSimpleName();
+                                    String function = 
sequenceExpr.getFunction().name;
+                                    row.add(new SqlSequenceExpr(sequence, 
function));
+                                } else {
+                                    if (primaryKeyIndex.contains(i)) {
+                                        wrapSQLParsingException(expr);
+                                    }
+                                    row.add(NotPlaceholderExpr.get());
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return allRows;
+    }
+
+    @Override
+    public List<String> getInsertParamsValue() {
+        return null;
+    }
+
+    @Override
+    public List<String> getDuplicateKeyUpdate() {
+        return null;
+    }
+
+    @Override
+    public List<String> getInsertColumnsUnEscape() {
+        List<String> insertColumns = getInsertColumns();
+        return ColumnUtils.delEscape(insertColumns, getDbType());
+    }
+
+    @Override
+    protected SQLStatement getAst() {
+        return ast;
+    }
+
+    @Override
+    public boolean isSqlSyntaxSupports() {
+        return true;
+    }
+}
diff --git 
a/sqlparser/seata-sqlparser-druid/src/main/java/org/apache/seata/sqlparser/druid/oracle/OracleOperateRecognizerHolder.java
 
b/sqlparser/seata-sqlparser-druid/src/main/java/org/apache/seata/sqlparser/druid/oracle/OracleOperateRecognizerHolder.java
index 6fe36ed8f7..50d8714155 100644
--- 
a/sqlparser/seata-sqlparser-druid/src/main/java/org/apache/seata/sqlparser/druid/oracle/OracleOperateRecognizerHolder.java
+++ 
b/sqlparser/seata-sqlparser-druid/src/main/java/org/apache/seata/sqlparser/druid/oracle/OracleOperateRecognizerHolder.java
@@ -52,4 +52,8 @@ public class OracleOperateRecognizerHolder implements 
SQLOperateRecognizerHolder
         }
         return null;
     }
+
+    public SQLRecognizer getMultiInsertRecognizer(String sql, SQLStatement 
ast) {
+        return new OracleMultiInsertRecognizer(sql, ast);
+    }
 }
diff --git 
a/sqlparser/seata-sqlparser-druid/src/test/java/org/apache/seata/sqlparser/druid/DruidSQLRecognizerFactoryTest.java
 
b/sqlparser/seata-sqlparser-druid/src/test/java/org/apache/seata/sqlparser/druid/DruidSQLRecognizerFactoryTest.java
index 741e411d90..2d283beb69 100644
--- 
a/sqlparser/seata-sqlparser-druid/src/test/java/org/apache/seata/sqlparser/druid/DruidSQLRecognizerFactoryTest.java
+++ 
b/sqlparser/seata-sqlparser-druid/src/test/java/org/apache/seata/sqlparser/druid/DruidSQLRecognizerFactoryTest.java
@@ -16,104 +16,116 @@
  */
 package org.apache.seata.sqlparser.druid;
 
+import com.alibaba.druid.sql.SQLUtils;
+import com.alibaba.druid.sql.ast.SQLStatement;
+import 
com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMultiInsertStatement;
 import org.apache.seata.common.exception.NotSupportYetException;
 import org.apache.seata.common.loader.EnhancedServiceLoader;
 import org.apache.seata.sqlparser.SQLRecognizer;
 import org.apache.seata.sqlparser.SQLRecognizerFactory;
 import org.apache.seata.sqlparser.SQLType;
 import org.apache.seata.sqlparser.SqlParserType;
+import org.apache.seata.sqlparser.druid.oracle.OracleOperateRecognizerHolder;
 import org.apache.seata.sqlparser.util.JdbcConstants;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
 import java.util.List;
 
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
 public class DruidSQLRecognizerFactoryTest {
     @Test
     public void testSqlRecognizerCreation() {
         SQLRecognizerFactory recognizerFactory =
                 EnhancedServiceLoader.load(SQLRecognizerFactory.class, 
SqlParserType.SQL_PARSER_TYPE_DRUID);
-        Assertions.assertNotNull(recognizerFactory);
+        assertNotNull(recognizerFactory);
         List<SQLRecognizer> recognizers = recognizerFactory.create("delete 
from t1", JdbcConstants.MYSQL);
-        Assertions.assertNotNull(recognizers);
+        assertNotNull(recognizers);
         Assertions.assertEquals(recognizers.size(), 1);
         Assertions.assertEquals(SQLType.DELETE, 
recognizers.get(0).getSQLType());
 
         recognizers = recognizerFactory.create("delete from t1", 
JdbcConstants.MARIADB);
-        Assertions.assertNotNull(recognizers);
+        assertNotNull(recognizers);
         Assertions.assertEquals(recognizers.size(), 1);
         Assertions.assertEquals(SQLType.DELETE, 
recognizers.get(0).getSQLType());
 
         recognizers = recognizerFactory.create("delete from t1", 
JdbcConstants.POLARDBX);
-        Assertions.assertNotNull(recognizers);
+        assertNotNull(recognizers);
         Assertions.assertEquals(recognizers.size(), 1);
         Assertions.assertEquals(SQLType.DELETE, 
recognizers.get(0).getSQLType());
 
         recognizers = recognizerFactory.create("delete from t1", 
JdbcConstants.DM);
-        Assertions.assertNotNull(recognizers);
+        assertNotNull(recognizers);
         Assertions.assertEquals(recognizers.size(), 1);
         Assertions.assertEquals(SQLType.DELETE, 
recognizers.get(0).getSQLType());
 
         recognizers = recognizerFactory.create("delete from t1", 
JdbcConstants.KINGBASE);
-        Assertions.assertNotNull(recognizers);
+        assertNotNull(recognizers);
         Assertions.assertEquals(recognizers.size(), 1);
         Assertions.assertEquals(SQLType.DELETE, 
recognizers.get(0).getSQLType());
 
         recognizers = recognizerFactory.create("delete from t1", 
JdbcConstants.OSCAR);
-        Assertions.assertNotNull(recognizers);
+        assertNotNull(recognizers);
         Assertions.assertEquals(recognizers.size(), 1);
         Assertions.assertEquals(SQLType.DELETE, 
recognizers.get(0).getSQLType());
 
         // test sql syntax
         String sql = "update d.t set d.t.a = ?, d.t.b = ?, d.t.c = ?";
-        Assertions.assertNotNull(recognizerFactory.create(sql, 
JdbcConstants.MYSQL));
-        Assertions.assertNotNull(recognizerFactory.create(sql, 
JdbcConstants.MARIADB));
-        Assertions.assertNotNull(recognizerFactory.create(sql, 
JdbcConstants.POLARDBX));
-        Assertions.assertNotNull(recognizerFactory.create(sql, 
JdbcConstants.ORACLE));
-        Assertions.assertNotNull(recognizerFactory.create(sql, 
JdbcConstants.POSTGRESQL));
-        Assertions.assertNotNull(recognizerFactory.create(sql, 
JdbcConstants.DM));
-        Assertions.assertNotNull(recognizerFactory.create(sql, 
JdbcConstants.KINGBASE));
-        Assertions.assertNotNull(recognizerFactory.create(sql, 
JdbcConstants.OSCAR));
+        assertNotNull(recognizerFactory.create(sql, JdbcConstants.MYSQL));
+        assertNotNull(recognizerFactory.create(sql, JdbcConstants.MARIADB));
+        assertNotNull(recognizerFactory.create(sql, JdbcConstants.POLARDBX));
+        assertNotNull(recognizerFactory.create(sql, JdbcConstants.ORACLE));
+        assertNotNull(recognizerFactory.create(sql, JdbcConstants.POSTGRESQL));
+        assertNotNull(recognizerFactory.create(sql, JdbcConstants.DM));
+        assertNotNull(recognizerFactory.create(sql, JdbcConstants.KINGBASE));
+        assertNotNull(recognizerFactory.create(sql, JdbcConstants.OSCAR));
 
         String sql5 = "insert into a values (1, 2)";
-        Assertions.assertNotNull(recognizerFactory.create(sql5, 
JdbcConstants.MYSQL));
-        Assertions.assertNotNull(recognizerFactory.create(sql5, 
JdbcConstants.MARIADB));
-        Assertions.assertNotNull(recognizerFactory.create(sql5, 
JdbcConstants.POLARDBX));
-        Assertions.assertNotNull(recognizerFactory.create(sql5, 
JdbcConstants.ORACLE));
-        Assertions.assertNotNull(recognizerFactory.create(sql5, 
JdbcConstants.POSTGRESQL));
-        Assertions.assertNotNull(recognizerFactory.create(sql5, 
JdbcConstants.DM));
-        Assertions.assertNotNull(recognizerFactory.create(sql5, 
JdbcConstants.KINGBASE));
-        Assertions.assertNotNull(recognizerFactory.create(sql5, 
JdbcConstants.OSCAR));
+        assertNotNull(recognizerFactory.create(sql5, JdbcConstants.MYSQL));
+        assertNotNull(recognizerFactory.create(sql5, JdbcConstants.MARIADB));
+        assertNotNull(recognizerFactory.create(sql5, JdbcConstants.POLARDBX));
+        assertNotNull(recognizerFactory.create(sql5, JdbcConstants.ORACLE));
+        assertNotNull(recognizerFactory.create(sql5, 
JdbcConstants.POSTGRESQL));
+        assertNotNull(recognizerFactory.create(sql5, JdbcConstants.DM));
+        assertNotNull(recognizerFactory.create(sql5, JdbcConstants.KINGBASE));
+        assertNotNull(recognizerFactory.create(sql5, JdbcConstants.OSCAR));
 
         String sql6 = "insert into a (id, name) values (1, 2), (3, 4)";
-        Assertions.assertNotNull(recognizerFactory.create(sql6, 
JdbcConstants.MYSQL));
-        Assertions.assertNotNull(recognizerFactory.create(sql6, 
JdbcConstants.MARIADB));
-        Assertions.assertNotNull(recognizerFactory.create(sql6, 
JdbcConstants.POLARDBX));
-        Assertions.assertNotNull(recognizerFactory.create(sql6, 
JdbcConstants.ORACLE));
-        Assertions.assertNotNull(recognizerFactory.create(sql6, 
JdbcConstants.POSTGRESQL));
-        Assertions.assertNotNull(recognizerFactory.create(sql6, 
JdbcConstants.DM));
-        Assertions.assertNotNull(recognizerFactory.create(sql6, 
JdbcConstants.KINGBASE));
-        Assertions.assertNotNull(recognizerFactory.create(sql6, 
JdbcConstants.OSCAR));
+        assertNotNull(recognizerFactory.create(sql6, JdbcConstants.MYSQL));
+        assertNotNull(recognizerFactory.create(sql6, JdbcConstants.MARIADB));
+        assertNotNull(recognizerFactory.create(sql6, JdbcConstants.POLARDBX));
+        assertNotNull(recognizerFactory.create(sql6, JdbcConstants.ORACLE));
+        assertNotNull(recognizerFactory.create(sql6, 
JdbcConstants.POSTGRESQL));
+        assertNotNull(recognizerFactory.create(sql6, JdbcConstants.DM));
+        assertNotNull(recognizerFactory.create(sql6, JdbcConstants.KINGBASE));
+        assertNotNull(recognizerFactory.create(sql6, JdbcConstants.OSCAR));
 
         String sql8 = "delete from t where id = ?";
-        Assertions.assertNotNull(recognizerFactory.create(sql8, 
JdbcConstants.MYSQL));
-        Assertions.assertNotNull(recognizerFactory.create(sql8, 
JdbcConstants.MARIADB));
-        Assertions.assertNotNull(recognizerFactory.create(sql8, 
JdbcConstants.POLARDBX));
-        Assertions.assertNotNull(recognizerFactory.create(sql8, 
JdbcConstants.ORACLE));
-        Assertions.assertNotNull(recognizerFactory.create(sql8, 
JdbcConstants.POSTGRESQL));
-        Assertions.assertNotNull(recognizerFactory.create(sql8, 
JdbcConstants.DM));
-        Assertions.assertNotNull(recognizerFactory.create(sql8, 
JdbcConstants.KINGBASE));
-        Assertions.assertNotNull(recognizerFactory.create(sql8, 
JdbcConstants.OSCAR));
+        assertNotNull(recognizerFactory.create(sql8, JdbcConstants.MYSQL));
+        assertNotNull(recognizerFactory.create(sql8, JdbcConstants.MARIADB));
+        assertNotNull(recognizerFactory.create(sql8, JdbcConstants.POLARDBX));
+        assertNotNull(recognizerFactory.create(sql8, JdbcConstants.ORACLE));
+        assertNotNull(recognizerFactory.create(sql8, 
JdbcConstants.POSTGRESQL));
+        assertNotNull(recognizerFactory.create(sql8, JdbcConstants.DM));
+        assertNotNull(recognizerFactory.create(sql8, JdbcConstants.KINGBASE));
+        assertNotNull(recognizerFactory.create(sql8, JdbcConstants.OSCAR));
 
         String sql10 = "select * from t for update";
-        Assertions.assertNotNull(recognizerFactory.create(sql10, 
JdbcConstants.MYSQL));
-        Assertions.assertNotNull(recognizerFactory.create(sql10, 
JdbcConstants.MARIADB));
-        Assertions.assertNotNull(recognizerFactory.create(sql10, 
JdbcConstants.POLARDBX));
-        Assertions.assertNotNull(recognizerFactory.create(sql10, 
JdbcConstants.ORACLE));
-        Assertions.assertNotNull(recognizerFactory.create(sql10, 
JdbcConstants.POSTGRESQL));
-        Assertions.assertNotNull(recognizerFactory.create(sql10, 
JdbcConstants.KINGBASE));
-        Assertions.assertNotNull(recognizerFactory.create(sql10, 
JdbcConstants.DM));
-        Assertions.assertNotNull(recognizerFactory.create(sql10, 
JdbcConstants.OSCAR));
+        assertNotNull(recognizerFactory.create(sql10, JdbcConstants.MYSQL));
+        assertNotNull(recognizerFactory.create(sql10, JdbcConstants.MARIADB));
+        assertNotNull(recognizerFactory.create(sql10, JdbcConstants.POLARDBX));
+        assertNotNull(recognizerFactory.create(sql10, JdbcConstants.ORACLE));
+        assertNotNull(recognizerFactory.create(sql10, 
JdbcConstants.POSTGRESQL));
+        assertNotNull(recognizerFactory.create(sql10, JdbcConstants.KINGBASE));
+        assertNotNull(recognizerFactory.create(sql10, JdbcConstants.DM));
+        assertNotNull(recognizerFactory.create(sql10, JdbcConstants.OSCAR));
     }
 
     @Test
@@ -208,4 +220,44 @@ public class DruidSQLRecognizerFactoryTest {
         Assertions.assertThrows(
                 NotSupportYetException.class, () -> 
recognizerFactory.create(sql9, JdbcConstants.KINGBASE));
     }
+
+    @Test
+    public void testInsertFirstNotSupported() {
+        SQLRecognizerFactory recognizerFactory =
+                EnhancedServiceLoader.load(SQLRecognizerFactory.class, 
SqlParserType.SQL_PARSER_TYPE_DRUID);
+        // Test that INSERT FIRST syntax should be rejected at the Factory 
level
+        String sql = "INSERT FIRST "
+                + "WHEN salary > 1000 THEN INTO high_earners (id, name, 
salary) VALUES (1, 'John', 2000) "
+                + "WHEN salary <= 1000 THEN INTO low_earners (id, name, 
salary) VALUES (1, 'John', 800) "
+                + "SELECT 1 FROM DUAL";
+
+        NotSupportYetException exception = Assertions.assertThrows(
+                NotSupportYetException.class, () -> 
recognizerFactory.create(sql, JdbcConstants.ORACLE));
+
+        assertTrue(exception.getMessage().contains("INSERT FIRST not supported 
yet"));
+    }
+
+    @Test
+    void testGetMultiInsertRecognizerDelegation() {
+        // 1.sql
+        String sql = "INSERT ALL INTO a(id) VALUES(1) INTO a(id) VALUES(2) 
SELECT 1 FROM dual";
+
+        SQLStatement stmt = SQLUtils.parseSingleStatement(sql, "oracle");
+        assertTrue(stmt instanceof OracleMultiInsertStatement);
+
+        // 2. mock recognizerHolder and recognizer
+        OracleOperateRecognizerHolder recognizerHolder = 
mock(OracleOperateRecognizerHolder.class);
+        SQLRecognizer mockRecognizer = mock(SQLRecognizer.class);
+
+        // 3. stub getMultiInsertRecognizer
+        when(recognizerHolder.getMultiInsertRecognizer(sql, 
stmt)).thenReturn(mockRecognizer);
+
+        SQLRecognizer recognizer =
+                ((OracleOperateRecognizerHolder) 
recognizerHolder).getMultiInsertRecognizer(sql, stmt);
+
+        assertNotNull(recognizer);
+        assertSame(mockRecognizer, recognizer);
+
+        verify(recognizerHolder, times(1)).getMultiInsertRecognizer(sql, stmt);
+    }
 }
diff --git 
a/sqlparser/seata-sqlparser-druid/src/test/java/org/apache/seata/sqlparser/druid/oracle/OracleMultiInsertRecognizerTest.java
 
b/sqlparser/seata-sqlparser-druid/src/test/java/org/apache/seata/sqlparser/druid/oracle/OracleMultiInsertRecognizerTest.java
new file mode 100644
index 0000000000..6b6e1ee15b
--- /dev/null
+++ 
b/sqlparser/seata-sqlparser-druid/src/test/java/org/apache/seata/sqlparser/druid/oracle/OracleMultiInsertRecognizerTest.java
@@ -0,0 +1,404 @@
+/*
+ * 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.seata.sqlparser.druid.oracle;
+
+import com.alibaba.druid.sql.SQLUtils;
+import com.alibaba.druid.sql.ast.SQLStatement;
+import org.apache.seata.common.exception.NotSupportYetException;
+import org.apache.seata.sqlparser.SQLType;
+import org.apache.seata.sqlparser.struct.Null;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Oracle Multi Insert Recognizer Test
+ *
+ */
+public class OracleMultiInsertRecognizerTest {
+
+    private static final String DB_TYPE = "oracle";
+
+    @Test
+    public void testGetSqlType() {
+        String sql = "INSERT ALL INTO a (id) VALUES (1) INTO a (id) VALUES (2) 
SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+
+        OracleMultiInsertRecognizer recognizer = new 
OracleMultiInsertRecognizer(sql, asts.get(0));
+        Assertions.assertEquals(SQLType.INSERT, recognizer.getSQLType());
+    }
+
+    @Test
+    public void testGetTableName() {
+        String sql = "INSERT ALL INTO users (id) VALUES (1) INTO users (id) 
VALUES (2) SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+
+        OracleMultiInsertRecognizer recognizer = new 
OracleMultiInsertRecognizer(sql, asts.get(0));
+        Assertions.assertEquals("users", recognizer.getTableName());
+    }
+
+    @Test
+    public void testGetTableAlias() {
+        // Test the case without alias
+        String sql = "INSERT ALL INTO users (id) VALUES (1) INTO users (id) 
VALUES (2) SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+
+        OracleMultiInsertRecognizer recognizer = new 
OracleMultiInsertRecognizer(sql, asts.get(0));
+        Assertions.assertNull(recognizer.getTableAlias());
+    }
+
+    @Test
+    public void testGetInsertColumns() {
+        String sql =
+                "INSERT ALL INTO users (id, name, age) VALUES (1, 'Tom', 20) 
INTO users (id, name, age) VALUES (2, 'Jerry', 25) SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+
+        OracleMultiInsertRecognizer recognizer = new 
OracleMultiInsertRecognizer(sql, asts.get(0));
+        List<String> columns = recognizer.getInsertColumns();
+
+        Assertions.assertNotNull(columns);
+        Assertions.assertEquals(3, columns.size());
+        Assertions.assertEquals("id", columns.get(0));
+        Assertions.assertEquals("name", columns.get(1));
+        Assertions.assertEquals("age", columns.get(2));
+    }
+
+    @Test
+    public void testInsertColumnsIsEmpty() {
+        // Test the case with columns
+        String sqlWithColumns =
+                "INSERT ALL INTO users (id, name) VALUES (1, 'Tom') INTO users 
(id, name) VALUES (2, 'Jerry') SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sqlWithColumns, 
DB_TYPE);
+        OracleMultiInsertRecognizer recognizer = new 
OracleMultiInsertRecognizer(sqlWithColumns, asts.get(0));
+        Assertions.assertFalse(recognizer.insertColumnsIsEmpty());
+    }
+
+    @Test
+    public void testGetInsertRows() {
+        String sql =
+                "INSERT ALL INTO users (id, name, age) VALUES (1, 'Tom', 20) 
INTO users (id, name, age) VALUES (2, 'Jerry', 25) SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+
+        OracleMultiInsertRecognizer recognizer = new 
OracleMultiInsertRecognizer(sql, asts.get(0));
+        List<List<Object>> rows = 
recognizer.getInsertRows(Collections.emptySet());
+
+        Assertions.assertNotNull(rows);
+        Assertions.assertEquals(2, rows.size());
+
+        // Verify the first row of data
+        List<Object> firstRow = rows.get(0);
+        Assertions.assertEquals(3, firstRow.size());
+        Assertions.assertEquals(1, firstRow.get(0));
+        Assertions.assertEquals("Tom", firstRow.get(1));
+        Assertions.assertEquals(20, firstRow.get(2));
+
+        // Verify the second row of data
+        List<Object> secondRow = rows.get(1);
+        Assertions.assertEquals(3, secondRow.size());
+        Assertions.assertEquals(2, secondRow.get(0));
+        Assertions.assertEquals("Jerry", secondRow.get(1));
+        Assertions.assertEquals(25, secondRow.get(2));
+    }
+
+    @Test
+    public void testGetInsertRowsWithNullValues() {
+        String sql =
+                "INSERT ALL INTO users (id, name, age) VALUES (1, 'Tom', NULL) 
INTO users (id, name, age) VALUES (2, NULL, 25) SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+
+        OracleMultiInsertRecognizer recognizer = new 
OracleMultiInsertRecognizer(sql, asts.get(0));
+        List<List<Object>> rows = 
recognizer.getInsertRows(Collections.emptySet());
+
+        Assertions.assertNotNull(rows);
+        Assertions.assertEquals(2, rows.size());
+
+        // Verify the first row of data (age is NULL)
+        List<Object> firstRow = rows.get(0);
+        Assertions.assertEquals(3, firstRow.size());
+        Assertions.assertEquals(1, firstRow.get(0));
+        Assertions.assertEquals("Tom", firstRow.get(1));
+        Assertions.assertEquals(Null.get(), firstRow.get(2));
+
+        // Verify the second row of data (name is NULL)
+        List<Object> secondRow = rows.get(1);
+        Assertions.assertEquals(3, secondRow.size());
+        Assertions.assertEquals(2, secondRow.get(0));
+        Assertions.assertEquals(Null.get(), secondRow.get(1));
+        Assertions.assertEquals(25, secondRow.get(2));
+    }
+
+    @Test
+    public void testGetInsertRowsWithParameters() {
+        String sql =
+                "INSERT ALL INTO users (id, name) VALUES (?, ?) INTO users 
(id, name) VALUES (?, ?) SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+
+        OracleMultiInsertRecognizer recognizer = new 
OracleMultiInsertRecognizer(sql, asts.get(0));
+        List<List<Object>> rows = 
recognizer.getInsertRows(Collections.emptySet());
+
+        Assertions.assertNotNull(rows);
+        Assertions.assertEquals(2, rows.size());
+
+        // Validation parameter placeholders
+        for (List<Object> row : rows) {
+            Assertions.assertEquals(2, row.size());
+            for (Object value : row) {
+                Assertions.assertTrue(value instanceof String);
+                Assertions.assertEquals("?", value);
+            }
+        }
+    }
+
+    @Test
+    public void testGetInsertParamsValue() {
+        String sql =
+                "INSERT ALL INTO users (id, name) VALUES (1, 'Tom') INTO users 
(id, name) VALUES (2, 'Jerry') SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+
+        OracleMultiInsertRecognizer recognizer = new 
OracleMultiInsertRecognizer(sql, asts.get(0));
+        List<String> paramsValue = recognizer.getInsertParamsValue();
+
+        Assertions.assertNull(paramsValue);
+    }
+
+    @Test
+    public void testGetDuplicateKeyUpdate() {
+        String sql =
+                "INSERT ALL INTO users (id, name) VALUES (1, 'Tom') INTO users 
(id, name) VALUES (2, 'Jerry') SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+
+        OracleMultiInsertRecognizer recognizer = new 
OracleMultiInsertRecognizer(sql, asts.get(0));
+        List<String> duplicateKeyUpdate = recognizer.getDuplicateKeyUpdate();
+
+        Assertions.assertNull(duplicateKeyUpdate);
+    }
+
+    @Test
+    public void testIsSqlSyntaxSupports() {
+        String sql =
+                "INSERT ALL INTO users (id, name) VALUES (1, 'Tom') INTO users 
(id, name) VALUES (2, 'Jerry') SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+
+        OracleMultiInsertRecognizer recognizer = new 
OracleMultiInsertRecognizer(sql, asts.get(0));
+        Assertions.assertTrue(recognizer.isSqlSyntaxSupports());
+    }
+
+    @Test
+    public void testMultipleTablesInsert() {
+        // Now this should throw an exception since different tables are 
involved
+        String sql =
+                "INSERT ALL INTO users (id, name) VALUES (1, 'Tom') INTO 
orders (id, user_id) VALUES (101, 1) SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+
+        // should throw NotSupportYetException
+        NotSupportYetException exception = Assertions.assertThrows(
+                NotSupportYetException.class, () -> new 
OracleMultiInsertRecognizer(sql, asts.get(0)));
+
+        Assertions.assertTrue(
+                exception.getMessage().contains("Oracle Multi Insert with 
different tables is not supported yet"));
+        Assertions.assertTrue(exception.getMessage().contains("users"));
+        Assertions.assertTrue(exception.getMessage().contains("orders"));
+    }
+
+    @Test
+    public void testMultipleTablesWithDifferentColumns() {
+        // Testing the same table but different column definitions
+        String sql =
+                "INSERT ALL INTO users (id, name) VALUES (1, 'Tom') INTO users 
(id, name, age) VALUES (2, 'Jerry', 25) SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+
+        // should throw NotSupportYetException
+        NotSupportYetException exception = Assertions.assertThrows(
+                NotSupportYetException.class, () -> new 
OracleMultiInsertRecognizer(sql, asts.get(0)));
+
+        Assertions.assertTrue(exception
+                .getMessage()
+                .contains("Oracle Multi Insert with different column 
definitions is not supported yet"));
+        Assertions.assertTrue(exception.getMessage().contains("users"));
+    }
+
+    @Test
+    public void testSameTableMultipleInserts() {
+        // Test the normal situation of the same table and column
+        String sql =
+                "INSERT ALL INTO users (id, name) VALUES (1, 'Tom') INTO users 
(id, name) VALUES (2, 'Jerry') SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+
+        // success
+        OracleMultiInsertRecognizer recognizer = new 
OracleMultiInsertRecognizer(sql, asts.get(0));
+
+        Assertions.assertEquals("users", recognizer.getTableName());
+        Assertions.assertEquals(2, recognizer.getInsertColumns().size());
+        Assertions.assertEquals("id", recognizer.getInsertColumns().get(0));
+        Assertions.assertEquals("name", recognizer.getInsertColumns().get(1));
+
+        List<List<Object>> rows = 
recognizer.getInsertRows(Collections.emptySet());
+        Assertions.assertEquals(2, rows.size());
+    }
+
+    @Test
+    public void testEmptyColumnsConsistency() {
+        // Tests the consistency of empty column definitions
+        String sql = "INSERT ALL INTO users VALUES (1, 'Tom') INTO users 
VALUES (2, 'Jerry') SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+
+        // This should succeed since neither entry specifies a column.
+        OracleMultiInsertRecognizer recognizer = new 
OracleMultiInsertRecognizer(sql, asts.get(0));
+
+        Assertions.assertEquals("users", recognizer.getTableName());
+        Assertions.assertTrue(recognizer.insertColumnsIsEmpty());
+    }
+
+    @Test
+    public void testMixedColumnDefinitions() {
+        // Test one case with column definition and one case without column 
definition
+        String sql =
+                "INSERT ALL INTO users (id, name) VALUES (1, 'Tom') INTO users 
VALUES (2, 'Jerry') SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+
+        // An exception should be thrown because the column definitions are 
inconsistent
+        NotSupportYetException exception = Assertions.assertThrows(
+                NotSupportYetException.class, () -> new 
OracleMultiInsertRecognizer(sql, asts.get(0)));
+
+        Assertions.assertTrue(exception
+                .getMessage()
+                .contains("Oracle Multi Insert with different column 
definitions is not supported yet"));
+    }
+
+    @Test
+    public void testCaseInsensitiveTableNames() {
+        // Test table name case sensitivity
+        String sql =
+                "INSERT ALL INTO users (id, name) VALUES (1, 'Tom') INTO USERS 
(id, name) VALUES (2, 'Jerry') SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+
+        // This should succeed because equalsIgnoreCase is used
+        OracleMultiInsertRecognizer recognizer = new 
OracleMultiInsertRecognizer(sql, asts.get(0));
+
+        Assertions.assertEquals("users", recognizer.getTableName());
+        Assertions.assertEquals(2, recognizer.getInsertColumns().size());
+    }
+
+    @Test
+    public void testTableWithSchema() {
+        // Test table name with Schema
+        String sql =
+                "INSERT ALL INTO schema1.users (id, name) VALUES (1, 'Tom') 
INTO schema1.users (id, name) VALUES (2, 'Jerry') SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+
+        // success
+        OracleMultiInsertRecognizer recognizer = new 
OracleMultiInsertRecognizer(sql, asts.get(0));
+
+        Assertions.assertEquals("schema1.users", recognizer.getTableName());
+        Assertions.assertEquals(2, recognizer.getInsertColumns().size());
+    }
+
+    @Test
+    public void testDifferentSchemas() {
+        // Testing tables with the same name in different schemas
+        String sql =
+                "INSERT ALL INTO schema1.users (id, name) VALUES (1, 'Tom') 
INTO schema2.users (id, name) VALUES (2, 'Jerry') SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+
+        // An exception should be thrown because they are different tables
+        NotSupportYetException exception = Assertions.assertThrows(
+                NotSupportYetException.class, () -> new 
OracleMultiInsertRecognizer(sql, asts.get(0)));
+
+        Assertions.assertTrue(
+                exception.getMessage().contains("Oracle Multi Insert with 
different tables is not supported yet"));
+        
Assertions.assertTrue(exception.getMessage().contains("schema1.users"));
+        
Assertions.assertTrue(exception.getMessage().contains("schema2.users"));
+    }
+
+    @Test
+    public void testComplexInsertAllStatement() {
+        // Testing a more complex INSERT ALL statement
+        String sql = "INSERT ALL "
+                + "INTO sales (prod_id, cust_id, time_id, amount) VALUES 
(product_id, customer_id, weekly_start_date, sales_sun) "
+                + "INTO sales (prod_id, cust_id, time_id, amount) VALUES 
(product_id, customer_id, weekly_start_date+1, sales_mon) "
+                + "INTO sales (prod_id, cust_id, time_id, amount) VALUES 
(product_id, customer_id, weekly_start_date+2, sales_tue) "
+                + "SELECT product_id, customer_id, weekly_start_date, 
sales_sun, sales_mon, sales_tue FROM sales_input_table";
+
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+        OracleMultiInsertRecognizer recognizer = new 
OracleMultiInsertRecognizer(sql, asts.get(0));
+
+        Assertions.assertEquals("sales", recognizer.getTableName());
+        Assertions.assertEquals(SQLType.INSERT, recognizer.getSQLType());
+
+        List<String> columns = recognizer.getInsertColumns();
+        Assertions.assertNotNull(columns);
+        Assertions.assertEquals(4, columns.size());
+        Assertions.assertEquals("prod_id", columns.get(0));
+        Assertions.assertEquals("cust_id", columns.get(1));
+        Assertions.assertEquals("time_id", columns.get(2));
+        Assertions.assertEquals("amount", columns.get(3));
+    }
+
+    @Test
+    public void testEmptyEntriesHandling() {
+        // This test is mainly to ensure that no exceptions occur in boundary 
conditions
+
+        String sql = "INSERT ALL INTO users (id, name) VALUES (1, 'Tom') 
SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+
+        OracleMultiInsertRecognizer recognizer = new 
OracleMultiInsertRecognizer(sql, asts.get(0));
+
+        Assertions.assertEquals(SQLType.INSERT, recognizer.getSQLType());
+        Assertions.assertEquals("users", recognizer.getTableName());
+        Assertions.assertTrue(recognizer.isSqlSyntaxSupports());
+    }
+
+    @Test
+    public void testGetInsertRowsWithPrimaryKeyIndex() {
+        String sql =
+                "INSERT ALL INTO users (id, name, age) VALUES (1, 'Tom', 20) 
INTO users (id, name, age) VALUES (2, 'Jerry', 25) SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+
+        OracleMultiInsertRecognizer recognizer = new 
OracleMultiInsertRecognizer(sql, asts.get(0));
+
+        // Test behavior when primary key index is specified
+        List<List<Object>> rows = recognizer.getInsertRows(Arrays.asList(0));
+
+        Assertions.assertNotNull(rows);
+        Assertions.assertEquals(2, rows.size());
+
+        // Validate the value of the primary key field
+        for (List<Object> row : rows) {
+            Assertions.assertEquals(3, row.size());
+            Assertions.assertTrue(row.get(0) instanceof Integer);
+        }
+    }
+
+    @Test
+    public void testConditionalInsertNotSupported() {
+        // Testing conditional insert statements
+        String sql = "INSERT ALL " + "INTO users (id, name) VALUES (1, 'Tom') "
+                + "WHEN salary > 1000 THEN INTO employees (id, name) VALUES 
(2, 'Jerry') "
+                + "SELECT 1 FROM DUAL";
+        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DB_TYPE);
+
+        // Should throw NotSupportYetException
+        NotSupportYetException exception = Assertions.assertThrows(
+                NotSupportYetException.class, () -> new 
OracleMultiInsertRecognizer(sql, asts.get(0)));
+
+        Assertions.assertTrue(exception.getMessage().contains("conditional 
clauses"));
+        Assertions.assertTrue(exception.getMessage().contains("WHEN...THEN"));
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to