| Hibernate pagination generated script execution return incorrect data. I found this when I have retrieved data from a view. I have created table, data, view generation script for you to reproduce this bug. According to hibernate sources getLimitString method from org.hibernate.dialect.Oracle9iDialect Lets first select all rows from view:
select * from v_mytable_last order by status desc
Result:
| RowNumber |
ID |
VERSION |
CAPTION |
STATUS |
| 1 |
1 |
7 |
t40 |
2 |
| 2 |
16 |
1 |
t47 |
2 |
| 3 |
11 |
2 |
t43 |
2 |
| 4 |
6 |
4 |
t31 |
2 |
| 5 |
15 |
1 |
t46 |
2 |
| 6 |
2 |
6 |
t39 |
2 |
| 7 |
14 |
1 |
t45 |
2 |
| 8 |
4 |
5 |
t38 |
2 |
| 9 |
8 |
2 |
t29 |
2 |
| 10 |
17 |
1 |
t48 |
2 |
| 11 |
3 |
3 |
t21 |
2 |
| 12 |
7 |
2 |
t23 |
2 |
| 13 |
9 |
2 |
t30 |
2 |
| 14 |
10 |
3 |
t42 |
2 |
| 15 |
12 |
1 |
t41 |
2 |
| 16 |
5 |
6 |
t37 |
1 |
| 17 |
13 |
1 |
t44 |
1 |
After that is we are using hibernate pagination for first page then we have an appended code at first and last line of request:
select * from (
select * from v_mytable_last order by status desc
) where rownum <= 5
Result:
| RowNumber |
ID |
VERSION |
CAPTION |
STATUS |
| 1 |
1 |
7 |
t40 |
2 |
| 2 |
14 |
1 |
t45 |
2 |
| 3 |
2 |
6 |
t39 |
2 |
| 4 |
6 |
4 |
t31 |
2 |
| 5 |
11 |
2 |
t43 |
2 |
And for second page we are having offset so hibernate execute:
select * from (
select * from v_mytable_last order by status desc
) where rownum <= 5
Result:
| RowNumber |
ID |
VERSION |
CAPTION |
STATUS |
ROWNUM_ |
| 1 |
4 |
5 |
t38 |
2 |
6 |
| 2 |
14 |
1 |
t45 |
2 |
7 |
| 3 |
2 |
6 |
t39 |
2 |
8 |
| 4 |
6 |
4 |
t31 |
2 |
9 |
| 5 |
11 |
2 |
t43 |
2 |
10 |
You can see for the second page ROWNUM_ seem to be correct but the data is not. I was wonder to find this bug. I found it reproducible only for my view, not for table. To solve this issue I has to override dialect and use my own implementation:
final StringBuilder pagingSelect = new StringBuilder( sql.length() + 100 )
pagingSelect.append( "select * from ( select row_.*, rownum rownum_ from ( " )
pagingSelect.append( sql )
if (hasOffset) {
pagingSelect.append( " ) row_ ) where rownum_ <= ? and rownum_ > ? " )
}
else {
pagingSelect.append( " ) row_ ) where rownum_ <= ?" )
}
This code is working correct for views as well as for tables. |