/* Copyright (c) 2001-2019, The HSQL Development Group
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the HSQL Development Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */


package org.hsqldb.jdbc;

import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Blob;
import java.sql.SQLException;

import org.hsqldb.HsqlException;
import org.hsqldb.SessionInterface;
import org.hsqldb.error.ErrorCode;
import org.hsqldb.types.BlobDataID;
import org.hsqldb.types.BlobInputStream;

A wrapper for HSQLDB BlobData objects. Instances of this class are returned by calls to ResultSet methods.
Author:Fred Toussi (fredt@users dot sourceforge.net)
Version:2.3.5
Since:1.9.0
/** * A wrapper for HSQLDB BlobData objects. * * Instances of this class are returned by calls to ResultSet methods. * * @author Fred Toussi (fredt@users dot sourceforge.net) * @version 2.3.5 * @since 1.9.0 */
public class JDBCBlobClient implements Blob {
Returns the number of bytes in the BLOB value designated by this Blob object.
Throws:
  • SQLException – if there is an error accessing the length of the BLOB
Returns:length of the BLOB in bytes
/** * Returns the number of bytes in the <code>BLOB</code> value designated * by this <code>Blob</code> object. * * @return length of the <code>BLOB</code> in bytes * @throws SQLException if there is an error accessing the length of the * <code>BLOB</code> */
public synchronized long length() throws SQLException { checkClosed(); try { return blob.length(session); } catch (HsqlException e) { throw JDBCUtil.sqlException(e); } }
Retrieves all or part of the BLOB value that this Blob object represents, as an array of bytes.
Params:
  • pos – the ordinal position of the first byte in the BLOB value to be extracted; the first byte is at position 1
  • length – the number of consecutive bytes to be copied
Throws:
  • SQLException – if there is an error accessing the BLOB value
Returns:a byte array containing up to length consecutive bytes from the BLOB value designated by this Blob object, starting with the byte at position pos
/** * Retrieves all or part of the <code>BLOB</code> value that this * <code>Blob</code> object represents, as an array of bytes. * * @param pos the ordinal position of the first byte in the * <code>BLOB</code> value to be extracted; the first byte is at * position 1 * @param length the number of consecutive bytes to be copied * @return a byte array containing up to <code>length</code> consecutive * bytes from the <code>BLOB</code> value designated by this * <code>Blob</code> object, starting with the byte at position * <code>pos</code> * @throws SQLException if there is an error accessing the * <code>BLOB</code> value */
public synchronized byte[] getBytes(long pos, int length) throws SQLException { checkClosed(); if (!isInLimits(Long.MAX_VALUE, pos - 1, length)) { throw JDBCUtil.outOfRangeArgument(); } try { return blob.getBytes(session, pos - 1, length); } catch (HsqlException e) { throw JDBCUtil.sqlException(e); } }
Retrieves the BLOB value designated by this Blob instance as a stream.
Throws:
  • SQLException – if there is an error accessing the BLOB value
Returns:a stream containing the BLOB data
/** * Retrieves the <code>BLOB</code> value designated by this * <code>Blob</code> instance as a stream. * * @return a stream containing the <code>BLOB</code> data * @throws SQLException if there is an error accessing the * <code>BLOB</code> value */
public synchronized InputStream getBinaryStream() throws SQLException { checkClosed(); return new BlobInputStream(session, blob, 0, length()); }
Retrieves the byte position at which the specified byte array pattern begins within the BLOB value that this Blob object represents.
Params:
  • pattern – the byte array for which to search
  • start – the position at which to begin searching; the first position is 1
Throws:
Returns:the position at which the pattern appears, else -1
/** * Retrieves the byte position at which the specified byte array * <code>pattern</code> begins within the <code>BLOB</code> value that * this <code>Blob</code> object represents. * * @param pattern the byte array for which to search * @param start the position at which to begin searching; the first * position is 1 * @return the position at which the pattern appears, else -1 * @throws SQLException if there is an error accessing the * <code>BLOB</code> */
public synchronized long position(byte[] pattern, long start) throws SQLException { checkClosed(); if (!isInLimits(Long.MAX_VALUE, start - 1, 0)) { throw JDBCUtil.outOfRangeArgument(); } try { long position = blob.position(session, pattern, start - 1); if (position >= 0) { position++; } return position; } catch (HsqlException e) { throw JDBCUtil.sqlException(e); } }
Retrieves the byte position in the BLOB value designated by this Blob object at which pattern begins.
Params:
  • pattern – the Blob object designating the BLOB value for which to search
  • start – the position in the BLOB value at which to begin searching; the first position is 1
Throws:
  • SQLException – if there is an error accessing the BLOB value
Returns:the position at which the pattern begins, else -1
/** * Retrieves the byte position in the <code>BLOB</code> value designated * by this <code>Blob</code> object at which <code>pattern</code> begins. * * @param pattern the <code>Blob</code> object designating the * <code>BLOB</code> value for which to search * @param start the position in the <code>BLOB</code> value at which to * begin searching; the first position is 1 * @return the position at which the pattern begins, else -1 * @throws SQLException if there is an error accessing the * <code>BLOB</code> value */
public synchronized long position(Blob pattern, long start) throws SQLException { checkClosed(); if (!isInLimits(Long.MAX_VALUE, start - 1, 0)) { throw JDBCUtil.outOfRangeArgument(); } if (pattern instanceof JDBCBlobClient) { BlobDataID searchClob = ((JDBCBlobClient) pattern).blob; try { long position = blob.position(session, searchClob, start - 1); if (position >= 0) { position++; } return position; } catch (HsqlException e) { throw JDBCUtil.sqlException(e); } } if (!isInLimits(Integer.MAX_VALUE, 0, pattern.length())) { throw JDBCUtil.outOfRangeArgument(); } byte[] bytePattern = pattern.getBytes(1, (int) pattern.length()); return position(bytePattern, start); }
Writes the given array of bytes to the BLOB value that this Blob object represents, starting at position pos, and returns the number of bytes written.
Params:
  • pos – the position in the BLOB object at which to start writing
  • bytes – the array of bytes to be written to the BLOB value that this Blob object represents
Throws:
  • SQLException – if there is an error accessing the BLOB value
Returns:the number of bytes written
/** * Writes the given array of bytes to the <code>BLOB</code> value that * this <code>Blob</code> object represents, starting at position * <code>pos</code>, and returns the number of bytes written. * * @param pos the position in the <code>BLOB</code> object at which to * start writing * @param bytes the array of bytes to be written to the * <code>BLOB</code> value that this <code>Blob</code> object * represents * @return the number of bytes written * @throws SQLException if there is an error accessing the * <code>BLOB</code> value */
public synchronized int setBytes(long pos, byte[] bytes) throws SQLException { return setBytes(pos, bytes, 0, bytes.length); }
Writes all or part of the given byte array to the BLOB value that this Blob object represents and returns the number of bytes written.
Params:
  • pos – the position in the BLOB object at which to start writing
  • bytes – the array of bytes to be written to this BLOB object
  • offset – the offset into the array bytes at which to start reading the bytes to be set
  • len – the number of bytes to be written to the BLOB value from the array of bytes bytes
Throws:
  • SQLException – if there is an error accessing the BLOB value
Returns:the number of bytes written
/** * Writes all or part of the given <code>byte</code> array to the * <code>BLOB</code> value that this <code>Blob</code> object represents * and returns the number of bytes written. * * @param pos the position in the <code>BLOB</code> object at which to * start writing * @param bytes the array of bytes to be written to this * <code>BLOB</code> object * @param offset the offset into the array <code>bytes</code> at which * to start reading the bytes to be set * @param len the number of bytes to be written to the <code>BLOB</code> * value from the array of bytes <code>bytes</code> * @return the number of bytes written * @throws SQLException if there is an error accessing the * <code>BLOB</code> value */
public synchronized int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException { checkClosed(); if (!isInLimits(bytes.length, offset, len)) { throw JDBCUtil.outOfRangeArgument(); } if (!isInLimits(Long.MAX_VALUE, pos - 1, len)) { throw JDBCUtil.outOfRangeArgument(); } if (!isWritable) { throw JDBCUtil.notUpdatableColumn(); } startUpdate(); try { blob.setBytes(session, pos - 1, bytes, offset, len); return len; } catch (HsqlException e) { throw JDBCUtil.sqlException(e); } }
Retrieves a stream that can be used to write to the BLOB value that this Blob object represents.
Params:
  • pos – the position in the BLOB value at which to start writing
Throws:
  • SQLException – if there is an error accessing the BLOB value
Returns:a java.io.OutputStream object to which data can be written
/** * Retrieves a stream that can be used to write to the <code>BLOB</code> * value that this <code>Blob</code> object represents. * * @param pos the position in the <code>BLOB</code> value at which to * start writing * @return a <code>java.io.OutputStream</code> object to which data can * be written * @throws SQLException if there is an error accessing the * <code>BLOB</code> value */
public synchronized OutputStream setBinaryStream(long pos) throws SQLException { throw JDBCUtil.notSupported(); }
Truncates the BLOB value that this Blob object represents to be len bytes in length.
Params:
  • len – the length, in bytes, to which the BLOB value that this Blob object represents should be truncated
Throws:
  • SQLException – if there is an error accessing the BLOB value
/** * Truncates the <code>BLOB</code> value that this <code>Blob</code> * object represents to be <code>len</code> bytes in length. * * @param len the length, in bytes, to which the <code>BLOB</code> value * that this <code>Blob</code> object represents should be truncated * @throws SQLException if there is an error accessing the * <code>BLOB</code> value */
public synchronized void truncate(long len) throws SQLException { checkClosed(); if (!isInLimits(Long.MAX_VALUE, 0, len)) { throw JDBCUtil.outOfRangeArgument(); } try { blob.truncate(session, len); } catch (HsqlException e) { throw JDBCUtil.sqlException(e); } }
This method frees the Blob object and releases the resources that it holds. The object is invalid once the free method is called.

After free has been called, any attempt to invoke a method other than free will result in a SQLException being thrown. If free is called multiple times, the subsequent calls to free are treated as a no-op.

Throws:
  • SQLException – if an error occurs releasing the Blob's resources
Since:JDK 1.6, HSQLDB 2.0
/** * This method frees the <code>Blob</code> object and releases the resources that * it holds. The object is invalid once the <code>free</code> * method is called. * <p> * After <code>free</code> has been called, any attempt to invoke a * method other than <code>free</code> will result in a <code>SQLException</code> * being thrown. If <code>free</code> is called multiple times, the subsequent * calls to <code>free</code> are treated as a no-op. * <p> * * @throws SQLException if an error occurs releasing * the Blob's resources * @since JDK 1.6, HSQLDB 2.0 */
public synchronized void free() throws SQLException { isClosed = true; }
Returns an InputStream object that contains a partial Blob value, starting with the byte specified by pos, which is length bytes in length.
Params:
  • pos – the offset to the first byte of the partial value to be retrieved. The first byte in the Blob is at position 1
  • length – the length in bytes of the partial value to be retrieved
Throws:
  • SQLException – if pos is less than 1 or if pos is greater than the number of bytes in the Blob or if pos + length is greater than the number of bytes in the Blob
Returns:InputStream through which the partial Blob value can be read.
Since:JDK 1.6, HSQLDB 2.0
/** * Returns an <code>InputStream</code> object that contains a partial <code>Blob</code> value, * starting with the byte specified by pos, which is length bytes in length. * * @param pos the offset to the first byte of the partial value to be retrieved. * The first byte in the <code>Blob</code> is at position 1 * @param length the length in bytes of the partial value to be retrieved * @return <code>InputStream</code> through which the partial <code>Blob</code> value can be read. * @throws SQLException if pos is less than 1 or if pos is greater than the number of bytes * in the <code>Blob</code> or if pos + length is greater than the number of bytes * in the <code>Blob</code> * * @since JDK 1.6, HSQLDB 2.0 */
public synchronized InputStream getBinaryStream(long pos, long length) throws SQLException { checkClosed(); if (!isInLimits(this.length(), pos - 1, length)) { throw JDBCUtil.outOfRangeArgument(); } return new BlobInputStream(session, blob, pos - 1, length); } //-- BlobDataID originalBlob; BlobDataID blob; SessionInterface session; int colIndex; private boolean isClosed; private boolean isWritable; JDBCResultSet resultSet; public JDBCBlobClient(SessionInterface session, BlobDataID blob) { this.session = session; this.blob = blob; } public boolean isClosed() { return isClosed; } public BlobDataID getBlob() { return blob; } public synchronized void setWritable(JDBCResultSet result, int index) { isWritable = true; resultSet = result; colIndex = index; } public synchronized void clearUpdates() { if (originalBlob != null) { blob = originalBlob; originalBlob = null; } } private void startUpdate() throws SQLException { if (originalBlob != null) { return; } originalBlob = blob; blob = (BlobDataID) blob.duplicate(session); resultSet.startUpdate(colIndex + 1); resultSet.preparedStatement.parameterValues[colIndex] = blob; resultSet.preparedStatement.parameterSet[colIndex] = Boolean.TRUE; } private void checkClosed() throws SQLException { if (isClosed) { throw JDBCUtil.sqlException(ErrorCode.X_0F502); } } static boolean isInLimits(long fullLength, long pos, long len) { return pos >= 0 && len >= 0 && pos + len <= fullLength; } }