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 <gsk525...@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-unsubscr...@seata.apache.org For additional commands, e-mail: notifications-h...@seata.apache.org