Why throwing java.lang.IndexOutOfBoundsException when reading blob in the database hsqldb

740 views Asked by At

Hi. I am using the following code to write blob to database at the server side.



    @Override
    public void write(TypeHandlerContext context, ResultSet resultSet, Object value) {
        int column = context.getColumn();
        LargeObject lo = (LargeObject)value;
        if(lo == null) {
            try {
                resultSet.updateNull(column);
            } catch(SQLException e) {
                throw new RuntimeException(e);
            }
        } else {
            InputStream is = lo.getInputStream();
            try {
                if(is == null) {
                    Reader r = lo.getReader();
                    if(r == null) {
                        resultSet.updateNull(column);
                        return;//empty Large object
                    }
                    is = new ReaderInputStream(r, "UTF-8");
                } 
                resultSet.updateBlob(column, is, lo.getLength());
            } catch(Exception e) {
                Throwables.throwAsUndeclarable(e);
            } finally {
                Tools.closeSilent(is);
            }
        }
    }

For reading blob used the following code:



    @Override
    public LargeObject read(TypeHandlerContext context, ResultSet resultSet) {
        try {
            Blob blob = resultSet.getBlob(context.getColumn());
            if(blob == null) {
                return null;
            }
            final long len = blob.length();
            final byte[] bytes = readBytes((int)len, blob);
            return new ByteArrayLargeObject(bytes, true, false);
        } catch(Exception e) {
            Throwables.throwAsUndeclarable(e);
            return null;
        }
    }

    private byte[] readBytes(int len, Blob blob) throws Exception {
        try {
            return blob.getBytes(1l, len);
        } catch(SQLFeatureNotSupportedException e) {
            InputStream is = blob.getBinaryStream();
            try {
                return IOUtils.toByteArray(is, len);
            } finally {
                Tools.closeSilent(is);
            }
        }
    }

Blob contains next text for test:

    and(
     gt(
      field("sinSystems.childsCount"),
      param(0, "integer")
     ),
     security.checkAccessForTarget("sinSystems.target", "sinSystems.targetType")
    )

I have tested this on oracle and postresql successfully, but testing on hsqldb failed with exception:



    Caused by: java.lang.IndexOutOfBoundsException: Index out of bounds: 0 >= 0
        at org.hsqldb.lib.HsqlArrayList.get(Unknown Source)
        at org.hsqldb.persist.LobStoreMem.getBlockBytes(Unknown Source)
        at org.hsqldb.persist.LobManager.getBytesNormal(Unknown Source)
        at org.hsqldb.persist.LobManager.getBytes(Unknown Source)
        at org.hsqldb.Session.performLOBOperation(Unknown Source)
        at org.hsqldb.Session.execute(Unknown Source)
        at org.hsqldb.types.BlobDataID.getBytes(Unknown Source)
        at org.hsqldb.jdbc.JDBCBlobClient.getBytes(Unknown Source)
        at ru.kih.sin.db.types.LargeObjectHandler.readBytes(LargeObjectHandler.java:100)
        at ru.kih.sin.db.types.LargeObjectHandler.read(LargeObjectHandler.java:44)
        at ru.kih.sin.db.types.LargeObjectHandler.read(LargeObjectHandler.java:27)
        at ru.kih.sql.types.NullValueWrapper.read(NullValueWrapper.java:24)
        at ru.kih.sql.types.TypeHandlerWrapper.read(TypeHandlerWrapper.java:74)
        at ru.kih.sql.types.TypeConverter.read(TypeConverter.java:48)
        at ru.kih.sin.model.impl.ObjectReadFunction.apply(ObjectReadFunction.java:119)
        at ru.kih.sin.model.impl.ObjectHandler.handle(ObjectHandler.java:41)
        at ru.kih.sin.model.impl.ObjectHandler.handle(ObjectHandler.java:16)
        at ru.kih.sql.query.handlers.SimpleSelect.handle(SimpleSelect.java:63)
        at ru.kih.sql.query.QueryHelper$UnsafeFunctionImpl.apply(QueryHelper.java:39)
        at ru.kih.sql.query.QueryHelper$UnsafeFunctionImpl.apply(QueryHelper.java:25)
        at ru.kih.sql.query.QueryContext.runIn(QueryContext.java:479)
        at ru.kih.sql.query.QueryContext.run(QueryContext.java:228)
        at ru.kih.sql.query.QueryContext.run(QueryContext.java:212)
        at ru.kih.sql.query.QueryContext.call(QueryContext.java:242)
        at ru.kih.sql.query.QueryHelper.query(QueryHelper.java:57)
        at ru.kih.sin.model.impl.SelectLobFunction.apply(SelectLobFunction.java:62)
        at ru.kih.sin.model.impl.SelectLobFunction.apply(SelectLobFunction.java:24)
        at ru.kih.sql.query.QueryContext.runIn(QueryContext.java:479)
        at ru.kih.sql.query.QueryContext.run(QueryContext.java:228)
        at ru.kih.sql.query.QueryContext.run(QueryContext.java:212)
        at ru.kih.sql.query.QueryContext.call(QueryContext.java:242)
        at ru.kih.sin.model.impl.ModelImpl.lambda$loadLob$8(ModelImpl.java:280)
        at ru.kih.sin.model.impl.ModelImpl$$Lambda$16/26663026.call(Unknown Source)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at ru.kih.sin.model.impl.ModelImpl.loadLob(ModelImpl.java:285)
        ... 48 more

The debugger can see that the blob.getLength() is greater than 0.

To connect to the database using a driver hsqldb-2.3.1

Tell me what's the problem?

P.S. Sorry for my english ))

2

There are 2 answers

0
st_nikolas On BEST ANSWER

Answer is closed. The problem in row Tools.closeSilent(is); of the method public void write(TypeHandlerContext context, ResultSet resultSet, Object value). It closes the InputStream before calling resultSet.updateRow().

1
fredt On

The code for writing the blob is incomplete. You must call resultSet.updateRow() after resultSet.updateBlob(...).

It is best to use the latest version of HSQLDB, currently 2.3.2 and 2.3.3 (release candidate).