Здравствуйте, у меня возникла проблема с параметрами запроса MS SQL в 1.0.0.CR9 при использовании разбиения по страницам или диапазонов (исключение SQL, сообщение = 'Неверный синтаксис рядом с'? '.'), Возможно, из-за того, что параметр находится в предложении 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();
При входе в систему SQL в Hibernate, это произведенный 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, но для «top (?)» В предложении select подстановки не было.
Если я удалю разбиение на страницы и перезапущу, запрос будет выполнен успешно.
Ниже показано ведение журнала трассировки, показывающее 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
Мне кажется, что это проблема, связанная с Panache.
Большое спасибо за обзор, и я обращусь к некоторым проектам в стеке. Поскольку единственный HQL, показанный в журналах трассировки, был FROM myproject.entities.Request WHERE requestor.firstName LIKE ?1
, я предположил, что добавление top(?)
исходило из реализации MS SQL для setMaxResults()
, однако 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, я специально переопределил версию в моем pom для этого и hibernate-core 5.5.5.Final. Могу ли я упустить зависимость?
Я посмотрел, где, по моему мнению, запрос Hibernate создается в Panache io.quarkus.hibernate.reactive.panache.common.runtime.CommonPanache QueryImpl: L254 , setFirstResult
и setMaxResults
по запросу. Я посмотрел на объект запроса в отладчике, и в конце этого метода createQuery
у базового ReactiveQueryImpl есть queryOptions, содержащие firstRow = 0 и maxRows = 25.
Цените помощь! (Поймите, я использую предварительный просмотр)
Я думаю, что нашел ошибку, вероятно, в 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, но этот репозиторий не подходит для такого рода проблем.
Я подозреваю, что нам не хватает теста, который устанавливает только максимальные результаты, а не первый результат.
@gavinking и @DavideD - Спасибо. Похоже, что другой тест, который будет выполнять _both_ setFirstResult(0)
и setMaxResults(n)
(n - любое значение> 0), воспроизведет ошибку, которую я вижу.
SQLServer2012LimitHandler.getOffsetFetch()
создает другой SQL, когда firstResult == 0 ("смещение 0 строк ...") по сравнению с тем, когда firstResult> 0 ("offset? Rows");
Если это все еще будет полезно, через несколько дней я мог бы потратить некоторое время на создание небольшого примера только для 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() );
} )
)
);
}
Отличие заключается в удалении «порядка по». Причина в том, что SQLServer2005LimitHandler записывает запрос как select top(?) ...
всякий раз, когда запрос не включает «порядок по», но когда он это делает, он использует синтаксис offset ? fetch next ?
. Поэтому я думаю, что нужны 2 тестовых примера.
Очень признателен!!