Hello

After upgrade from 1.2.x to 1.3.171 I think that I found an issue, 
that may influence many users of the new version.

Consider the following scenario:
1. create table t (id number);
2. insert into t (id) values (1);
3. select * from t order by id  limit 1 offset 2; <- produces error, see 
stacktrace bellow;
4. select * from t order by id  limit 1 offset -1; <- produces error, see 
stacktrace bellow;

Error on point 3:
org.h2.jdbc.JdbcSQLException: General error: 
"java.lang.IllegalArgumentException: fromIndex(2) > toIndex(1)"; SQL 
statement:
select * from t order by id  limit 1 offset 2 [50000-171]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:329)
    at org.h2.message.DbException.get(DbException.java:158)
    at org.h2.message.DbException.convert(DbException.java:281)
    at org.h2.command.Command.executeQuery(Command.java:195)
    at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:173)
    at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:152)
    at org.h2.server.web.WebApp.getResult(WebApp.java:1312)
    at org.h2.server.web.WebApp.query(WebApp.java:1002)
    at org.h2.server.web.WebApp.query(WebApp.java:978)
    at org.h2.server.web.WebApp.process(WebApp.java:217)
    at org.h2.server.web.WebApp.processRequest(WebApp.java:164)
    at org.h2.server.web.WebServlet.doGet(WebServlet.java:120)
    at org.h2.server.web.WebServlet.doPost(WebServlet.java:155)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at quizful.startup.Main$1.service(Main.java:81)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    at 
org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
    at 
org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
    at quizful.startup.QuizfulFilter.doFilter(QuizfulFilter.java:91)
    at 
org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
    at 
org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
    at 
org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
    at 
org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:722)
    at 
org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
    at org.mortbay.jetty.Server.handle(Server.java:324)
    at 
org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:505)
    at 
org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:842)
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:648)
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:380)
    at 
org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:395)
    at 
org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:450)
Caused by: java.lang.IllegalArgumentException: fromIndex(2) > toIndex(1)
    at java.util.Arrays.rangeCheck(Arrays.java:1306)
    at java.util.Arrays.sort(Arrays.java:1246)
    at org.h2.util.Utils.sortTopN(Utils.java:450)
    at org.h2.result.SortOrder.sort(SortOrder.java:174)
    at org.h2.result.LocalResult.done(LocalResult.java:339)
    at org.h2.command.dml.Select.queryWithoutCache(Select.java:632)
    at org.h2.command.dml.Query.query(Query.java:311)
    at org.h2.command.dml.Query.query(Query.java:281)
    at org.h2.command.dml.Query.query(Query.java:36)
    at org.h2.command.CommandContainer.query(CommandContainer.java:86)
    at org.h2.command.Command.executeQuery(Command.java:191)
    ... 28 more

Error on point 4:
select * from t order by id  limit 1 offset -1 [50000-171] HY000/50000 
(Help)
org.h2.jdbc.JdbcSQLException: General error: 
"java.lang.ArrayIndexOutOfBoundsException: Array index out of range: -1"; 
SQL statement:
select * from t order by id  limit 1 offset -1 [50000-171]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:329)
    at org.h2.message.DbException.get(DbException.java:158)
    at org.h2.message.DbException.convert(DbException.java:281)
    at org.h2.command.Command.executeQuery(Command.java:195)
    at org.h2.jdbc.JdbcStatement.executeInternal(JdbcStatement.java:173)
    at org.h2.jdbc.JdbcStatement.execute(JdbcStatement.java:152)
    at org.h2.server.web.WebApp.getResult(WebApp.java:1312)
    at org.h2.server.web.WebApp.query(WebApp.java:1002)
    at org.h2.server.web.WebApp.query(WebApp.java:978)
    at org.h2.server.web.WebApp.process(WebApp.java:217)
    at org.h2.server.web.WebApp.processRequest(WebApp.java:164)
    at org.h2.server.web.WebServlet.doGet(WebServlet.java:120)
    at org.h2.server.web.WebServlet.doPost(WebServlet.java:155)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at quizful.startup.Main$1.service(Main.java:81)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    at 
org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
    at 
org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
    at quizful.startup.QuizfulFilter.doFilter(QuizfulFilter.java:91)
    at 
org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
    at 
org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
    at 
org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
    at 
org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:722)
    at 
org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
    at org.mortbay.jetty.Server.handle(Server.java:324)
    at 
org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:505)
    at 
org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:842)
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:648)
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:380)
    at 
org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:395)
    at 
org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:450)
Caused by: java.lang.ArrayIndexOutOfBoundsException: Array index out of 
range: -1
    at java.util.Arrays.rangeCheck(Arrays.java:1309)
    at java.util.Arrays.sort(Arrays.java:1246)
*    at org.h2.util.Utils.sortTopN(Utils.java:450)*
    at org.h2.result.SortOrder.sort(SortOrder.java:174)
    at org.h2.result.LocalResult.done(LocalResult.java:339)
    at org.h2.command.dml.Select.queryWithoutCache(Select.java:632)
    at org.h2.command.dml.Query.query(Query.java:311)
    at org.h2.command.dml.Query.query(Query.java:281)
    at org.h2.command.dml.Query.query(Query.java:36)
    at org.h2.command.CommandContainer.query(CommandContainer.java:86)
    at org.h2.command.Command.executeQuery(Command.java:191)
    ... 28 more

The reason of both errors is probably in Arrays.sort invocation inside 
Utils.sortTopN():
    /**
     * Find the top limit values using given comparator and place them as 
in a
     * full array sort, in descending order.
     *
     * @param array the array.
     * @param offset the offset.
     * @param limit the limit.
     * @param comp the comparator.
     */
    public static <X> void sortTopN(X[] array, int offset, int limit,
                                    Comparator<? super X> comp) {
        partitionTopN(array, offset, limit, comp);
        Arrays.sort(array, offset, (int) Math.min((long) offset + limit, 
array.length), comp);
    }

The snippet probably should be changed to something like this:
    /**
     * Find the top limit values using given comparator and place them as 
in a
     * full array sort, in descending order.
     *
     * @param array the array.
     * @param offset the offset.
     * @param limit the limit.
     * @param comp the comparator.
     */
    public static <X> void sortTopN(X[] array, int offset, int limit,
                                    Comparator<? super X> comp) {
        partitionTopN(array, offset, limit, comp);

        int from = Math.max(offset, 0);                                 // 
from >= 0;
        int to = (int) Math.min((long) offset + limit, array.length);   // 
to   <= array.length
        from = Math.min(from, to);                                      // 
from <= to

        Arrays.sort(array, from, to, comp);
    }

While the case with negative offsets is an exotic one, the case with 
offset, that is greater than resultset's length,
should be very common. Hope this information would help.

-
Kind Regards
Dima Pekar

-- 
You received this message because you are subscribed to the Google Groups "H2 
Database" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/h2-database?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to