From 905fcbdfacc68855a4733c0a7e9a5b5a03e56843 Mon Sep 17 00:00:00 2001 From: Looly Date: Thu, 11 Sep 2025 14:33:44 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D`NamedSql.replaceVar`?= =?UTF-8?q?=E5=85=B3=E9=94=AE=E5=AD=97=E5=A4=84=E7=90=86=E9=97=AE=E9=A2=98?= =?UTF-8?q?=EF=BC=88issue#4062@Github=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 ++- .../main/java/cn/hutool/db/sql/NamedSql.java | 2 +- .../main/java/cn/hutool/db/sql/SqlUtil.java | 16 +++++++++++ .../test/java/cn/hutool/db/NamedSqlTest.java | 27 ++++++++++++++++++- 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0e0810166..6142213b84 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,8 @@ * 【core 】 修复`IoUtil`的`closeIfPosible`拼写错误,新建一个`closeIfPossible`方法,原方法标记deprecated(issue#4047@Github) * 【http 】 修复`HttpRequest.sendRedirectIfPossible`未对308做判断问题。(issue#4053@Github) * 【cron 】 修复`CronPatternUtil.nextDateAfter`当日为L时计算错误问题。(issue#4056@Github) -* 【cron 】 修复`DialectRunner.count`方法中,去除包含多字段order by子句的SQL语句时错误问题(issue#4066@Github) +* 【db 】 修复`NamedSql.replaceVar`关键字处理问题(issue#4062@Github) +* 【db 】 修复`DialectRunner.count`方法中,去除包含多字段order by子句的SQL语句时错误问题(issue#4066@Github) ------------------------------------------------------------------------------------------------------------- # 5.8.40(2025-08-26) diff --git a/hutool-db/src/main/java/cn/hutool/db/sql/NamedSql.java b/hutool-db/src/main/java/cn/hutool/db/sql/NamedSql.java index f060ae6c34..d8af4b028e 100644 --- a/hutool-db/src/main/java/cn/hutool/db/sql/NamedSql.java +++ b/hutool-db/src/main/java/cn/hutool/db/sql/NamedSql.java @@ -138,7 +138,7 @@ public class NamedSql { if(paramMap.containsKey(nameStr)) { // 有变量对应值(值可以为null),替换占位符为?,变量值放入相应index位置 final Object paramValue = paramMap.get(nameStr); - if(ArrayUtil.isArray(paramValue) && StrUtil.containsIgnoreCase(sqlBuilder, "in")){ + if(ArrayUtil.isArray(paramValue) && SqlUtil.isInClause(sqlBuilder)){ // 可能为select in (xxx)语句,则拆分参数为多个参数,变成in (?,?,?) final int length = ArrayUtil.length(paramValue); for (int i = 0; i < length; i++) { diff --git a/hutool-db/src/main/java/cn/hutool/db/sql/SqlUtil.java b/hutool-db/src/main/java/cn/hutool/db/sql/SqlUtil.java index ba35e4e992..ff9da9b79f 100644 --- a/hutool-db/src/main/java/cn/hutool/db/sql/SqlUtil.java +++ b/hutool-db/src/main/java/cn/hutool/db/sql/SqlUtil.java @@ -30,6 +30,10 @@ public class SqlUtil { * 创建SQL中的order by语句的正则 */ private static final Pattern PATTERN_ORDER_BY = PatternPool.get("(.*)\\s+order\\s+by\\s+[^\\s]+", Pattern.CASE_INSENSITIVE); + /** + * SQL中的in语句部分的正则 + */ + private static final Pattern PATTERN_IN_CLAUSE = PatternPool.get("\\s+in\\s+[(]", Pattern.CASE_INSENSITIVE); /** * 构件相等条件的where语句
@@ -268,4 +272,16 @@ public class SqlUtil { // 去除order by 子句 return ReUtil.getGroup1(PATTERN_ORDER_BY, selectSql); } + + /** + * 判断当前上下文是否在 IN 子句中 + * 通过检查变量前的SQL文本,判断是否符合 IN 子句的模式 + * + * @param sql 当前已构建的SQL + * @return 是否在 IN 子句中 + * @since 5.8.41 + */ + public static boolean isInClause(final CharSequence sql) { + return ReUtil.contains(PATTERN_IN_CLAUSE, sql); + } } diff --git a/hutool-db/src/test/java/cn/hutool/db/NamedSqlTest.java b/hutool-db/src/test/java/cn/hutool/db/NamedSqlTest.java index dba29ae8f2..6ece77a89e 100644 --- a/hutool-db/src/test/java/cn/hutool/db/NamedSqlTest.java +++ b/hutool-db/src/test/java/cn/hutool/db/NamedSqlTest.java @@ -2,7 +2,6 @@ package cn.hutool.db; import cn.hutool.core.map.MapUtil; import cn.hutool.db.sql.NamedSql; -import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; import java.sql.SQLException; @@ -10,6 +9,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import static org.junit.jupiter.api.Assertions.*; + public class NamedSqlTest { @Test @@ -100,4 +101,28 @@ public class NamedSqlTest { query = Db.use().query(sql, new Object[]{paramMap}); assertEquals(1, query.size()); } + + @Test + public void parseInTest2() { + // 测试表名包含"in"但不是IN子句的情况 + final String sql = "select * from information where info_data = :info"; + final HashMap paramMap = MapUtil.of("info", new int[]{10, 20}); + + final NamedSql namedSql = new NamedSql(sql, paramMap); + // sql语句不包含IN子句,不会展开数组 + assertEquals("select * from information where info_data = ?", namedSql.getSql()); + assertArrayEquals(new int[]{10, 20}, (int[]) namedSql.getParams()[0]); + } + + @Test + public void parseInTest3() { + // 测试字符串中包含"in"关键字但不是IN子句的情况 + final String sql = "select * from user where comment = 'include in text' and id = :id"; + final HashMap paramMap = MapUtil.of("id", new int[]{5, 6}); + + final NamedSql namedSql = new NamedSql(sql, paramMap); + // sql语句不包含IN子句,不会展开数组 + assertEquals("select * from user where comment = 'include in text' and id = ?", namedSql.getSql()); + assertArrayEquals(new int[]{5, 6}, (int[]) namedSql.getParams()[0]); + } }