您好,我在使用分页或范围时遇到了 1.0.0.CR9 中的 MS SQL 查询参数问题(SQL 异常,message='Incorrect syntax near '?'.'),可能是因为该参数在 Select 子句中?
堆栈:Quarkus 2.1.0.Final / Panache Reactive / Mutiny 4.1.2 / Hibernate Reactive 1.0.0.CR9 / Hibernate Core 5.5.5.Final
从我的休息资源,运行这个:
[PanacheRepository].find("firstName LIKE ?1").page(Page.of(25)).list();
在 Hibernate 中登录 SQL 后,这是生成的 SQL:
Hibernate:
select
top(?) request0_.id as id1_1_,
request0_.caseId as caseid2_1_,
request0_.caseNumber as casenumb3_1_,
request0_.expires as expires4_1_,
request0_.addressLine1 as addressl5_1_,
request0_.addressLine2 as addressl6_1_,
request0_.agency as agency7_1_,
request0_.city as city8_1_,
request0_.email as email9_1_,
request0_.firstName as firstna10_1_,
request0_.lastName as lastnam11_1_,
request0_.phone as phone12_1_,
request0_.relationship as relatio13_1_,
request0_.state as state14_1_,
request0_.zipcode as zipcode15_1_,
request0_.submitted as submitt16_1_
from
Request request0_
where
request0_.firstName like <strong i="11">@P1</strong>
请注意 where 子句中的正确参数替换,但是 select 子句中的“top(?)”没有发生替换。
如果我删除分页并重新运行,查询将成功执行。
跟踪日志如下所示,显示 HQL 和 SQL。 我猜 Panache 在查询中使用了setMaxResults()
。 如果问题出在那里,很高兴与 Quarkus 或 Mutiny 打开一个问题,并提前感谢您!
2021-08-05 12:55:57,342 DEBUG [org.hib.hql.int.ast.QueryTranslatorImpl] (vert.x-eventloop-thread-1) HQL: FROM myproject.entities.Request WHERE requestor.firstName LIKE ?1
2021-08-05 12:55:57,342 DEBUG [org.hib.hql.int.ast.QueryTranslatorImpl] (vert.x-eventloop-thread-1) SQL: select request0_.id as id1_1_, request0_.caseId as caseid2_1_, request0_.caseNumber as casenumb3_1_, request0_.expires as expires4_1_, request0_.addressLine1 as addressl5_1_, request0_.addressLine2 as addressl6_1_, request0_.agency as agency7_1_, request0_.city as city8_1_, request0_.email as email9_1_, request0_.firstName as firstna10_1_, request0_.lastName as lastnam11_1_, request0_.phone as phone12_1_, request0_.relationship as relatio13_1_, request0_.state as state14_1_, request0_.zipcode as zipcode15_1_, request0_.submitted as submitt16_1_ from Request request0_ where request0_.firstName like ?
2021-08-05 12:55:57,342 DEBUG [org.hib.hql.int.ast.ErrorTracker] (vert.x-eventloop-thread-1) throwQueryException() : no errors
2021-08-05 12:55:57,342 TRACE [org.hib.rea.ses.imp.ReactiveHQLQueryPlan] (vert.x-eventloop-thread-1) Find: FROM myproject.entities.Request WHERE requestor.firstName LIKE ?1
2021-08-05 12:55:57,344 TRACE [org.hib.eng.spi.QueryParameters] (vert.x-eventloop-thread-1) Named parameters: {1=%j%}
2021-08-05 12:55:57,345 TRACE [org.hib.typ.des.sql.BasicBinder] (vert.x-eventloop-thread-1) binding parameter [2] as [VARCHAR] - [%j%]
2021-08-05 12:55:57,345 TRACE [org.hib.loa.Loader] (vert.x-eventloop-thread-1) Bound [3] parameters total
2021-08-05 12:55:57,355 DEBUG [org.hib.SQL] (vert.x-eventloop-thread-1)
select
top(?) request0_.id as id1_1_,
request0_.caseId as caseid2_1_,
request0_.caseNumber as casenumb3_1_,
request0_.expires as expires4_1_,
request0_.addressLine1 as addressl5_1_,
request0_.addressLine2 as addressl6_1_,
request0_.agency as agency7_1_,
request0_.city as city8_1_,
request0_.email as email9_1_,
request0_.firstName as firstna10_1_,
request0_.lastName as lastnam11_1_,
request0_.phone as phone12_1_,
request0_.relationship as relatio13_1_,
request0_.state as state14_1_,
request0_.zipcode as zipcode15_1_,
request0_.submitted as submitt16_1_
from
Request request0_
where
request0_.firstName like <strong i="18">@P1</strong>
2021-08-05 12:55:57,358 ERROR [org.hib.rea.errors] (vert.x-eventloop-thread-1) HR000057: Failed to execute statement [$1select request0_.id as id1_1_, request0_.caseId as caseid2_1_, request0_.caseNumber as casenumb3_1_, request0_.expires as expires4_1_, request0_.addressLine1 as addressl5_1_, request0_.addressLine2 as addressl6_1_, request0_.agency as agency7_1_, request0_.city as city8_1_, request0_.email as email9_1_, request0_.firstName as firstna10_1_, request0_.lastName as lastnam11_1_, request0_.phone as phone12_1_, request0_.relationship as relatio13_1_, request0_.state as state14_1_, request0_.zipcode as zipcode15_1_, request0_.submitted as submitt16_1_ from Request request0_ where request0_.firstName like @P1]: $2could not execute query: java.util.concurrent.CompletionException: io.vertx.mssqlclient.MSSQLException: {number=102, state=1, severity=15, message='Incorrect syntax near '?'.', serverName='aa3ae4a0fd3c', lineNumber=1, additional=[io.vertx.mssqlclient.MSSQLException: {number=8180, state=1, severity=16, message='Statement(s) could not be prepared.', serverName='aa3ae4a0fd3c', lineNumber=1}]}
该 SQL 有一些奇怪的地方。
为什么我们甚至使用top n
而不是offset ... fetch ...
。 为什么会有多余的括号?
我猜想 Panache 在查询中使用了
setMaxResults()
。
那么它当然应该是。 Panache 没有业务去做自己的 SQL 生成,对吗 @FroMage?
好吧,我在普通的 HR 中尝试过这个,我得到:
select hqlquerypa0_.id as id1_0_, hqlquerypa0_.description as descript2_0_, hqlquerypa0_.name as name3_0_, hqlquerypa0_.type as type4_0_ from Flour hqlquerypa0_ order by hqlquerypa0_.id offset <strong i="6">@P1</strong> rows fetch next <strong i="7">@P2</strong> rows only
所以在我看来,这一定是一个与华丽相关的问题。
非常感谢您的审阅,我会联系堆栈中的一些项目。 由于跟踪日志中显示的唯一 HQL 是FROM myproject.entities.Request WHERE requestor.firstName LIKE ?1
,我假设top(?)
来自setMaxResults()
的 MS SQL 实现,但是您帖子中的 SQL显示它使用完全不同的语法。
仍然遇到这个问题,我尝试添加一个订单,以获得这个 HQL: FROM myproject.entities.Request WHERE requestor.firstName LIKE ?1 ORDER BY submitted
2021-08-05 16:20:37,992 DEBUG [org.hib.hql.int.ast.QueryTranslatorImpl] (vert.x-eventloop-thread-19) HQL: FROM myproject.entities.Request WHERE requestor.firstName LIKE ?1 ORDER BY submitted
2021-08-05 16:20:37,992 DEBUG [org.hib.hql.int.ast.QueryTranslatorImpl] (vert.x-eventloop-thread-19) SQL: select request0_.id as id1_1_, request0_.caseId as caseid2_1_, request0_.caseNumber as casenumb3_1_, request0_.expires as expires4_1_, request0_.addressLine1 as addressl5_1_, request0_.addressLine2 as addressl6_1_, request0_.agency as agency7_1_, request0_.city as city8_1_, request0_.email as email9_1_, request0_.firstName as firstna10_1_, request0_.lastName as lastnam11_1_, request0_.phone as phone12_1_, request0_.relationship as relatio13_1_, request0_.state as state14_1_, request0_.zipcode as zipcode15_1_, request0_.submitted as submitt16_1_ from Request request0_ where request0_.firstName like ? order by request0_.submitted
这试图执行以下 SQL:
2021-08-05 16:20:38,022 DEBUG [org.hib.SQL] (vert.x-eventloop-thread-19)
select
request0_.id as id1_1_,
request0_.caseId as caseid2_1_,
request0_.caseNumber as casenumb3_1_,
request0_.expires as expires4_1_,
request0_.addressLine1 as addressl5_1_,
request0_.addressLine2 as addressl6_1_,
request0_.agency as agency7_1_,
request0_.city as city8_1_,
request0_.email as email9_1_,
request0_.firstName as firstna10_1_,
request0_.lastName as lastnam11_1_,
request0_.phone as phone12_1_,
request0_.relationship as relatio13_1_,
request0_.state as state14_1_,
request0_.zipcode as zipcode15_1_,
request0_.submitted as submitt16_1_
from
Request request0_
where
request0_.firstName like <strong i="10">@P1</strong>
order by
request0_.submitted offset 0 rows fetch next ? rows only
所以......同样的问题仍然存在,因为它没有正确地进行参数替换(现在是fetch next ? rows only
),但这确实改变了生成的 SQL 语法以匹配您的示例。
由于 Quarkus 还没有包含 hibernate-reactive-core 1.0.0.CR9,我专门为此和 hibernate-core 5.5.5.Final 覆盖了我的 pom 中的版本。 我可能缺少依赖项吗?
我查看了我认为在 Panache io.quarkus.hibernate.reactive.panache.common.runtime.CommonPanache QueryImpl:L254 中创建 Hibernate 查询的setFirstResult
和setMaxResults
在查询上。 我查看了调试器中的查询对象,在createQuery
方法的末尾,底层的 ReactiveQueryImpl 具有包含 firstRow=0 和 maxRows=25 的 queryOptions。
感谢帮助! (了解我正在使用预览)
我想我发现了一个错误,可能在SQLServerParameters.processLimit()
Panache 正在创建一个 firstRow=0 的休眠查询。
在org.hibernate.reactive.loader.ReactiveLoader.executeReactiveQueryStatement
, SQLServer2012LimitHandler.getOffsetFetch()
被调用:
if ( !LimitHelper.hasFirstRow( selection ) ) {
return " offset 0 rows fetch next ? rows only";
}
return " offset ? rows fetch next ? rows only";
因此,此时的 SQL 以offset 0 rows fetch next ? rows only
结尾。 注意 0 而不是 ?。
从SQLServerParameters.processLimit()
:
if (isProcessingNotRequired(sql)) {
return sql;
}
// Replace 'offset ? fetch next ? rows only' with the <strong i="17">@P</strong> style parameters for Sql Server
int index = hasOffset ? parameterArray.length - 1 : parameterArray.length;
int pos = sql.indexOf( " offset ?" );
if ( pos > -1 ) {
String sqlProcessed = sql.substring( 0, pos ) + " offset @P" + index++ + " rows";
if ( sql.indexOf( " fetch next ?" ) > -1 ) {
sqlProcessed += " fetch next @P" + index + " rows only ";
}
return sqlProcessed;
}
return sql;
sql.indexOf( " offset ?")
是问题所在:由于 LimitHandler 已经将偏移量硬编码为 0,因此找不到子字符串offset ?
,因此它不会尝试处理任何进一步的参数。
是否应该将查找fetch next ?
的嵌套字符串匹配移到offset
的匹配之外?
@bharward如果您能创建一个仅使用 Hibernate Reactive 的测试用例,将不胜感激
我想我们也会看看一个使用 Panache 的,但是这个存储库不是解决这类问题的正确位置
我怀疑我们错过了一个只设置最大结果而不是第一个结果的测试。
我们有一个基本的: https :
@gavinking和@DavideD - 谢谢。 似乎另一个测试,一个可以执行_both_ setFirstResult(0)
和setMaxResults(n)
(n 是任何值 > 0)的测试,会重现我看到的错误。
SQLServer2012LimitHandler.getOffsetFetch()
在 firstResult==0 ("offset 0 rows...") 和 firstResult >0 ("offset ? rows") 时创建不同的 SQL;
如果它仍然有帮助,那么几天后我可以花一些时间创建一个仅 HR 的小示例来重现,或者修改 HQLQueryParameterNamedLimitTest 以添加我描述的测试。
啊,你是对的,这个测试会在HQLQueryParameterNamedLimitTest
失败:
<strong i="7">@Test</strong>
public void testFirstResultZeroAndMaxResults(TestContext context) {
test(
context,
openSession()
.thenCompose( s ->
s.createQuery( "from Flour order by id" )
.setFirstResult( 0 )
.setMaxResults( 10 )
.getResultList()
.thenAccept( result -> {
context.assertEquals( 3, result.size() );
} )
)
);
}
我会看一下
@DavideD _除了您提议的测试之外,我是否还建议进行这样的附加测试:
<strong i="7">@Test</strong>
public void testFirstResultZeroAndMaxResultsWithoutOrderBy(TestContext context) {
test(
context,
openSession()
.thenCompose( s ->
s.createQuery( "from Flour" )
.setFirstResult( 0 )
.setMaxResults( 10 )
.getResultList()
.thenAccept( result -> {
context.assertEquals( 3, result.size() );
} )
)
);
}
区别在于删除“order by”。 其原因是, SQLServer2005LimitHandler写入查询作为select top(?) ...
每当查询不包括“按订单”,但是当它做它使用offset ? fetch next ?
语法。 所以我认为需要2个测试用例。
非常感激!!