Hibernate-reactive: خطأ في استبدال المعلمة عند تقييد النتائج على MS SQL Server و Hibernate Reactive 1.0.0.CR9

تم إنشاؤها على ٥ أغسطس ٢٠٢١  ·  13تعليقات  ·  مصدر: hibernate/hibernate-reactive

مرحبًا ، أواجه مشكلة مع معلمات استعلام MS SQL في 1.0.0.CR9 عند استخدام Paging أو Ranges (استثناء SQL ، رسالة = 'بناء جملة غير صحيح بالقرب من'؟ '.') ، ربما لأن المعلمة موجودة في جملة التحديد؟

المكدس: 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}]}
bug

ال 13 كومينتر

هناك شيء غريب في SQL.

لماذا نستخدم حتى top n بدلاً من offset ... fetch ... . ولماذا الأقواس الزائدة عن الحاجة؟

أعتقد أن Panache يستخدم setMaxResults() في الاستعلام.

حسنًا ، يجب أن يكون كذلك بالتأكيد. لا يوجد لدى Panache أي أعمال مستمرة وتقوم بعمل جيل SQL الخاص بها ، أليس كذلكFroMage؟

حسنًا ، لقد جربت هذا في الموارد البشرية العادية ، وحصلت على:

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 لم يشتمل بعد على النواة التفاعلية 1.0.0.CR9 ، فقد تجاوزت على وجه التحديد الإصدار الموجود في بوم الخاص بي لهذا و 5.5.5 في وضع السبات الأساسي. هل يمكن أن أفتقد التبعية؟

نظرت إلى المكان الذي أعتقد أنه تم إنشاء استعلام Hibernate فيه في Panache io.quarkus.hibernate.reactive.panache.common.runtime.CommonPanache QueryImpl: L254 ، يبدو أنه يستخدم فقط setFirstResult و setMaxResults على الاستعلام. نظرت إلى كائن الاستعلام في مصحح الأخطاء وفي نهاية طريقة createQuery هذه ، يحتوي ReactiveQueryImpl الأساسي على خيارات استعلام تحتوي على 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 و DavidD - شكرا لك. يبدو أن اختبارًا آخر ، الاختبار الذي من شأنه أن يؤدي _b كل من setFirstResult(0) و setMaxResults(n) (يمثل n أي قيمة> 0) ، ينتج الخطأ الذي أراه.

SQLServer2012LimitHandler.getOffsetFetch() يقوم بإنشاء SQL مختلفة عند firstResult == 0 ("offset 0 rows ...") بالمقارنة مع when firstResult> 0 ("offset؟ rows")؛

إذا كان لا يزال مفيدًا ، في غضون أيام قليلة يمكنني قضاء بعض الوقت إما لإنشاء مثال صغير للموارد البشرية فقط لإعادة إنتاجه ، أو تعديل 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 ? بناء الجملة. لذلك أعتقد أن هناك حاجة لحالتين اختبار.

مقدر جدا!!

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات