Hibernate-reactive: Kesalahan penggantian parameter saat membatasi hasil pada MS SQL Server dan Hibernate Reactive 1.0.0.CR9

Dibuat pada 5 Agu 2021  ·  13Komentar  ·  Sumber: hibernate/hibernate-reactive

Halo, Saya mengalami masalah dengan parameter kueri MS SQL di 1.0.0.CR9 saat menggunakan Paging atau Rentang (Pengecualian SQL, message='Salah sintaks di dekat '?'.'), mungkin karena parameternya ada di klausa Select?

Stack: Quarkus 2.1.0.Final / Panache Reactive / Mutiny 4.1.2 / Hibernate Reactive 1.0.0.CR9 / Hibernate Core 5.5.5.Final

Dari sumber daya istirahat saya, jalankan ini:
[PanacheRepository].find("firstName LIKE ?1").page(Page.of(25)).list();

Dengan SQL masuk di Hibernate, ini adalah SQL yang dihasilkan:

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>

Perhatikan substitusi parameter yang benar di klausa where, tetapi substitusi tidak terjadi untuk "top(?)" di klausa pilih.
Jika saya menghapus paging dan menjalankan kembali, kueri berhasil dijalankan.

Trace logging yang ditunjukkan di bawah ini, menunjukkan HQL dan SQL. Saya kira Panache menggunakan setMaxResults() pada kueri. Senang membuka masalah dengan Quarkus atau Pemberontakan jika itu masalahnya, dan terima kasih sebelumnya!

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

Semua 13 komentar

Ada yang aneh dengan SQL itu.

Mengapa kita bahkan menggunakan top n alih-alih offset ... fetch ... . Dan mengapa tanda kurung yang berlebihan?

Saya kira Panache menggunakan setMaxResults() pada kueri.

Yah itu pasti harus . Panache tidak memiliki bisnis dan melakukan pembuatan SQL sendiri, bukan @FroMage?

Yah saya mencoba ini di HR biasa, dan saya mendapatkan:

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

Jadi menurut saya ini pasti masalah yang berhubungan dengan Panache.

Terima kasih banyak telah meninjau dan saya akan menghubungi beberapa proyek di tumpukan. Karena satu-satunya HQL yang ditampilkan dalam log jejak adalah FROM myproject.entities.Request WHERE requestor.firstName LIKE ?1 , saya berasumsi penambahan top(?) berasal dari implementasi MS SQL untuk setMaxResults() , namun SQL di posting Anda menunjukkan itu menggunakan sintaks yang sama sekali berbeda.

Masih mengalami masalah, saya mencoba menambahkan pesanan dengan, untuk memiliki HQL ini: 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

Ini mencoba menjalankan SQL berikut:

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

masalah yang sama masih ada karena tidak melakukan substitusi parameter dengan benar (sekarang untuk fetch next ? rows only ), tetapi itu mengubah sintaks SQL yang dihasilkan agar sesuai dengan contoh Anda.

Karena Quarkus belum menyertakan hibernate-reactive-core 1.0.0.CR9, saya secara khusus mengganti versi di pom saya untuk ini dan hibernate-core 5.5.5.Final. Mungkinkah saya kehilangan ketergantungan?

Saya melihat di mana saya percaya kueri Hibernate dibuat di Panache io.quarkus.hibernate.reactive.panache.common.runtime.CommonPanache QueryImpl:L254 , tampaknya hanya menggunakan setFirstResult dan setMaxResults pada kueri. Saya melihat objek kueri di debugger dan pada akhir metode createQuery , ReactiveQueryImpl yang mendasarinya memiliki queryOptions yang berisi firstRow=0 dan maxRows=25.

Hargai bantuannya! (Pahami saya menggunakan pratinjau)

Saya pikir saya menemukan bug, kemungkinan di SQLServerParameters.processLimit()

Panache sedang membuat kueri hibernasi dengan firstRow=0.

Di dalam org.hibernate.reactive.loader.ReactiveLoader.executeReactiveQueryStatement , SQLServer2012LimitHandler.getOffsetFetch() dipanggil:

if ( !LimitHelper.hasFirstRow( selection ) ) {
    return " offset 0 rows fetch next ? rows only";
}
return " offset ? rows fetch next ? rows only";

Oleh karena itu, SQL pada titik ini diakhiri dengan offset 0 rows fetch next ? rows only . Perhatikan 0 bukannya ?.
Dari 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 ?") adalah masalahnya: Karena LimitHandler sudah mengkodekan offset ke 0, substring offset ? tidak ditemukan, jadi ia tidak mencoba memproses parameter lebih lanjut.
Haruskah pencocokan string bersarang yang mencari fetch next ? dipindahkan ke luar kecocokan untuk offset ?

@bharward Jika Anda bisa membuat test case yang hanya menggunakan Hibernate Reactive yang akan sangat dihargai

Saya kira kita juga akan melihat salah satu yang menggunakan Panache, tetapi repositori ini bukan tempat yang tepat untuk masalah semacam itu

Saya menduga kami melewatkan tes yang hanya menetapkan hasil maksimal dan bukan hasil pertama.

@gavinking dan @DavideD - Terima kasih. Tampaknya tes lain, yang akan melakukan _both_ setFirstResult(0) dan setMaxResults(n) (n menjadi nilai apa pun > 0), akan mereproduksi kesalahan yang saya lihat.

SQLServer2012LimitHandler.getOffsetFetch() membuat SQL yang berbeda saat firstResult==0 ("offset 0 baris...") dibandingkan saat firstResult >0 ("offset ? rows");

Jika masih membantu, dalam beberapa hari saya dapat meluangkan waktu untuk membuat contoh kecil khusus HR untuk direproduksi, atau memodifikasi HQLQueryParameterNamedLimitTest untuk menambahkan tes seperti yang saya jelaskan.

Ah, Anda benar, tes ini akan gagal di 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() );
                                        } )
                        )
        );
    }

akan saya lihat

@DavideD _selain_ untuk tes yang Anda usulkan, bolehkah saya juga menyarankan tes tambahan seperti ini:

       <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() );
                                        } )
                        )
        );
    }

Perbedaannya adalah dalam menghapus "order by". Alasannya adalah bahwa SQLServer2005LimitHandler menulis query seperti select top(?) ... setiap kali query tidak termasuk "order by", tapi ketika itu terjadi itu menggunakan offset ? fetch next ? sintaks. Jadi saya pikir 2 kasus uji diperlukan.

Sangat dihargai!!

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

gavinking picture gavinking  ·  6Komentar

aguibert picture aguibert  ·  28Komentar

gavinking picture gavinking  ·  16Komentar

tsegismont picture tsegismont  ·  9Komentar

gavinking picture gavinking  ·  23Komentar