Mybatis-PageHelper
Mybatis-PageHelper copied to clipboard
无法解析中括号的问题
- [x] 我已在 issues 搜索类似问题,并且不存在相同的问题.
异常模板
使用环境
- PageHelper 版本:pagehelper-spring-boot-starter:1.3.0
- 数据库类型和版本: Microsoft SQL Server 2014 (SP2) (KB3171021) - 12.0.5000.0 (X64)
- JDBC_URL: jdbc:jtds:sqlserver:///;useLOBs=false
SQL 解析错误
分页参数
page = PageHelper.startPage(pageNo, pageSize, count);
原 SQL
SELECT [ID] AS [ComsnCountID] FROM B_ComsnCount ;
期望的结果:
能解析成功
完整异常信息
### Error querying database. Cause: java.sql.SQLException: 除非另外还指定了 TOP、OFFSET 或 FOR XML,否则,ORDER BY 子句在视图、内联函数、派生表、子查询和公用表表达式中无效。
### The error may exist in file [C:\IJProject\marketing\dao\target\classes\mapper\SellCommissionMapper.xml]
### The error may involve com.xkw.marketing.dao.mapper.SellCommissionMapper.queryCommissionCountList-Inline
### The error occurred while setting parameters
### Cause: java.sql.SQLException: 除非另外还指定了 TOP、OFFSET 或 FOR XML,否则,ORDER BY 子句在视图、内联函数、派生表、子查询和公用表表达式中无效。
; 除非另外还指定了 TOP、OFFSET 或 FOR XML,否则,ORDER BY 子句在视图、内联函数、派生表、子查询和公用表表达式中无效。; nested exception is java.sql.SQLException: 除非另外还指定了 TOP、OFFSET 或 FOR XML,否则,ORDER BY 子句在视图、内联函数、派生表、子查询和公用表表达式中无效。]
其他类型的错误
我看了源码,是在CountSqlParser的第180行,无法正常解析中括号,所以使用默认的getSimpleCountSql方法,但这个方法只是单纯的加一个count(0),没有去除 order by。
try {
stmt = CCJSqlParserUtil.parse(sql);
} catch (Throwable e) {
//无法解析的用一般方法返回count语句
return getSimpleCountSql(sql, name);
}
但我使用这个SQL就能正常输出 SELECT ID AS ComsnCountID FROM B_ComsnCount ; 所以我觉得是因为新版本无法正常解析中括号导致的,我使用1.2.12版本就能正常解析
功能建议
建议优化 getSimpleCountSql 方法,或者排查CCJSqlParserUtil.parse(sql)中不能正常解析中括号的原因
1. 功能修改建议
com.github.pagehelper.parser.SqlServerParser
/**
* 转换为分页语句
*
* @param sql
* @param offset
* @param limit
* @return
*/
public String convertToPageSql(String sql, Integer offset, Integer limit) {
//解析SQL
Statement stmt;
try {
stmt = CCJSqlParserUtil.parse(sql);
} catch (Throwable e) {
throw new PageException("不支持该SQL转换为分页查询!", e);
}
if (!(stmt instanceof Select)) {
throw new PageException("分页语句必须是Select查询!");
}
//获取分页查询的select
Select pageSelect = getPageSelect((Select) stmt);
String pageSql = pageSelect.toString();
//缓存移到外面了,所以不替换参数
if (offset != null) {
pageSql = pageSql.replace(START_ROW, String.valueOf(offset));
}
if (limit != null) {
pageSql = pageSql.replace(PAGE_SIZE, String.valueOf(limit));
}
return pageSql;
}
订正方法:
/**
* Parses an sql statement while allowing via consumer to configure the used parser before.
*
* For instance to activate SQLServer bracket quotation on could use:
*
* {@code
* CCJSqlParserUtil.parse("select * from [mytable]", parser -> parser.withSquareBracketQuotation(true));
* }
*
* @param sql
* @param consumer
* @return
* @throws JSQLParserException
*/
public static Statement parse(String sql, Consumer<CCJSqlParser> consumer) throws JSQLParserException {
CCJSqlParser parser = new CCJSqlParser(new StringProvider(sql));
if (consumer != null) {
consumer.accept(parser);
}
try {
return parser.Statement();
} catch (Exception ex) {
throw new JSQLParserException(ex);
}
}
@pagehelper 应该是升级 jsqlparser 导致的: https://stackoverflow.com/questions/59135053/how-to-handle-characters-on-jsqlparser
等后续大版本升级jdk8时会解决上面的问题。
计划什么时候升级了, 项目还能赶得上吗 ?
这样就可以了 Select select = (Select) CCJSqlParserUtil.parse(sql,parser->parser.withSquareBracketQuotation(true));
sqlParser
:配置 JSqlParser 解析器,注意是 com.github.pagehelper.JSqlParser
接口,用于支持 sqlserver 等需要额外配置的情况。