You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@seata.apache.org by ji...@apache.org on 2025/06/23 06:46:17 UTC

(incubator-seata) branch 2.x updated: optimize: Druid SQL parser throws ParserException for unsupported REPLACE statement (#7456)

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

jianbin 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 cbc6ac5ad0 optimize: Druid SQL parser throws ParserException for unsupported REPLACE statement (#7456)
cbc6ac5ad0 is described below

commit cbc6ac5ad0aa89e0085d06817f995b6bf949d767
Author: maple <gs...@163.com>
AuthorDate: Mon Jun 23 14:46:12 2025 +0800

    optimize: Druid SQL parser throws ParserException for unsupported REPLACE statement (#7456)
---
 changes/en-us/2.x.md                               |  1 +
 changes/zh-cn/2.x.md                               |  1 +
 .../druid/DruidSQLRecognizerFactoryImpl.java       | 56 +++++++++++++++-------
 .../druid/DruidSQLRecognizerFactoryTest.java       |  8 +---
 4 files changed, 43 insertions(+), 23 deletions(-)

diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md
index 483bcd2b67..e78723e74f 100644
--- a/changes/en-us/2.x.md
+++ b/changes/en-us/2.x.md
@@ -61,6 +61,7 @@ Add changes here for all PR submitted to the 2.x branch.
 - [[#7445](https://github.com/apache/incubator-seata/pull/7432)] separate the license from the server and namingserver
 - [[#7426](https://github.com/apache/incubator-seata/pull/7426)] add some license header
 - [[#7450](https://github.com/apache/incubator-seata/pull/7450)] Apply Spotless to the entire codebase
+- [[#7456](https://github.com/apache/incubator-seata/pull/7456)] Druid SQL parser throws ParserException for unsupported REPLACE statement
 
 
 ### security:
diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md
index 29bb3d6c75..18bb174686 100644
--- a/changes/zh-cn/2.x.md
+++ b/changes/zh-cn/2.x.md
@@ -60,6 +60,7 @@
 - [[#7445](https://github.com/apache/incubator-seata/pull/7432)] 分离license到server和namingserver
 - [[#7426](https://github.com/apache/incubator-seata/pull/7426)] 添加 license header
 - [[#7450](https://github.com/apache/incubator-seata/pull/7450)] 将 Spotless 应用于整个代码库
+- [[#7456](https://github.com/apache/incubator-seata/pull/7456)] Druid SQL 解析器因不支持的 REPLACE 语句而抛出 ParserException
 
 
 ### security:
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 d4ee5a5361..02d8ada742 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
@@ -38,36 +38,48 @@ import java.util.List;
 class DruidSQLRecognizerFactoryImpl implements SQLRecognizerFactory {
     @Override
     public List<SQLRecognizer> create(String sql, String dbType) {
-        List<SQLStatement> asts = SQLUtils.parseStatements(sql, DruidDbTypeAdapter.getAdaptiveDbType(dbType));
-        if (CollectionUtils.isEmpty(asts)) {
+        List<SQLStatement> sqlStatements;
+        try {
+            sqlStatements = SQLUtils.parseStatements(sql, DruidDbTypeAdapter.getAdaptiveDbType(dbType));
+        } catch (RuntimeException e) {
+            if (isParserException(e)) {
+                throw new NotSupportYetException(
+                        "not support the sql syntax: " + sql
+                                + "\nplease see the doc about SQL restrictions https://seata.apache.org/zh-cn/docs/user/sqlreference/dml",
+                        e);
+            }
+            throw e;
+        }
+
+        if (CollectionUtils.isEmpty(sqlStatements)) {
             throw new UnsupportedOperationException("Unsupported SQL: " + sql);
         }
-        if (asts.size() > 1
-                && !(asts.stream().allMatch(statement -> statement instanceof SQLUpdateStatement)
-                        || asts.stream().allMatch(statement -> statement instanceof SQLDeleteStatement))) {
+        if (sqlStatements.size() > 1
+                && !(sqlStatements.stream().allMatch(statement -> statement instanceof SQLUpdateStatement)
+                        || sqlStatements.stream().allMatch(statement -> statement instanceof SQLDeleteStatement))) {
             throw new UnsupportedOperationException("ONLY SUPPORT SAME TYPE (UPDATE OR DELETE) MULTI SQL -" + sql);
         }
         List<SQLRecognizer> recognizers = null;
         SQLRecognizer recognizer = null;
-        for (SQLStatement ast : asts) {
+        for (SQLStatement sqlStatement : sqlStatements) {
             SQLOperateRecognizerHolder recognizerHolder =
                     SQLOperateRecognizerHolderFactory.getSQLRecognizerHolder(dbType.toLowerCase());
-            if (ast instanceof SQLInsertStatement) {
-                recognizer = recognizerHolder.getInsertRecognizer(sql, ast);
-            } else if (ast instanceof SQLUpdateStatement) {
-                recognizer = recognizerHolder.getUpdateRecognizer(sql, ast);
-            } else if (ast instanceof SQLDeleteStatement) {
-                recognizer = recognizerHolder.getDeleteRecognizer(sql, ast);
-            } else if (ast instanceof SQLSelectStatement) {
-                recognizer = recognizerHolder.getSelectForUpdateRecognizer(sql, ast);
+            if (sqlStatement instanceof SQLInsertStatement) {
+                recognizer = recognizerHolder.getInsertRecognizer(sql, sqlStatement);
+            } else if (sqlStatement instanceof SQLUpdateStatement) {
+                recognizer = recognizerHolder.getUpdateRecognizer(sql, sqlStatement);
+            } else if (sqlStatement instanceof SQLDeleteStatement) {
+                recognizer = recognizerHolder.getDeleteRecognizer(sql, sqlStatement);
+            } else if (sqlStatement instanceof SQLSelectStatement) {
+                recognizer = recognizerHolder.getSelectForUpdateRecognizer(sql, sqlStatement);
             }
 
             // When recognizer is null, it indicates that recognizerHolder cannot allocate unsupported syntax, like
             // merge and replace
-            if (ast instanceof SQLReplaceStatement) {
+            if (sqlStatement instanceof SQLReplaceStatement) {
                 // just like:replace into t (id,dr) values (1,'2'), (2,'3')
                 throw new NotSupportYetException(
-                        "not support the sql syntax with ReplaceStatement:" + ast
+                        "not support the sql syntax with ReplaceStatement:" + sqlStatement
                                 + "\nplease see the doc about SQL restrictions https://seata.apache.org/zh-cn/docs/user/sqlreference/dml");
             }
 
@@ -80,4 +92,16 @@ class DruidSQLRecognizerFactoryImpl implements SQLRecognizerFactory {
         }
         return recognizers;
     }
+
+    /**
+     * Check if the exception is a Druid ParserException
+     * Use class name comparison to avoid directly referencing the ParserException class
+     */
+    private boolean isParserException(Throwable e) {
+        if (e == null) {
+            return false;
+        }
+        String className = e.getClass().getName();
+        return "com.alibaba.druid.sql.parser.ParserException".equals(className);
+    }
 }
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 7666638813..741e411d90 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
@@ -166,13 +166,7 @@ public class DruidSQLRecognizerFactoryTest {
                 NotSupportYetException.class, () -> recognizerFactory.create(sql3, JdbcConstants.MARIADB));
         Assertions.assertThrows(
                 NotSupportYetException.class, () -> recognizerFactory.create(sql3, JdbcConstants.POLARDBX));
-
-        // When dbtype are DM and SQLSERVER, druid cannot parse the sql syntax 'replace'
-        try {
-            recognizerFactory.create(sql3, JdbcConstants.DM);
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
+        Assertions.assertThrows(NotSupportYetException.class, () -> recognizerFactory.create(sql3, JdbcConstants.DM));
 
         String sql5 = "insert into a select * from b";
         Assertions.assertThrows(


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@seata.apache.org
For additional commands, e-mail: notifications-help@seata.apache.org