The HSQLDB jdbcBlob.java source code
/* Copyright (c) 2001-2008, 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.ByteArrayInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Blob;
import java.sql.SQLException;
import org.hsqldb.Trace;
// boucherb@users 2004-04-xx - patch 1.7.2 - position and truncate methods
// implemented; minor changes for moderate thread
// safety and optimal performance
// boucherb@users 2004-04-xx - doc 1.7.2 - javadocs updated; methods put in
// correct (historical, interface declared) order
/**
* The representation (mapping) in the Java<sup>TM
* programming language of an SQL BLOB value. <p>
*
* Provides methods for getting the length of an SQL BLOB (Binary Large Object)
* value, for materializing a BLOB value on the client, and for determining the
* position of an octet sequence (byte pattern) within a BLOB value. <p>
*
* <!-- start Release-specific documentation -->
* <div class="ReleaseSpecificDocumentation">
* <h3>HSQLDB-Specific Information:
*
* Including 1.8.x, the HSQLDB driver does not implement Blob using an SQL
* locator(BLOB). That is, an HSQLDB Blob object does not contain a logical
* pointer to SQL BLOB data; rather it directly contains a representation of
* the data (a byte array). As a result, an HSQLDB Blob object is itself
* valid beyond the duration of the transaction in which is was created,
* although it does not necessarily represent a corresponding value
* on the database. <p>
*
* Currently, the interface methods for updating a BLOB value are
* unsupported. However, the truncate method is supported for local use.
* </div>
* <!-- start Release-specific documentation -->
*
* @author james house jhouse@part.net
* @author boucherb@users
* @version 1.7.2
* @since JDK 1.2, HSQLDB 1.7.2
*/
public class jdbcBlob implements Blob {
volatile byte[] data;
/**
* Constructs a new jdbcBlob instance wrapping the given octet sequence. <p>
*
* This constructor is used internally to retrieve result set values as
* Blob objects, yet it must be public to allow access from other packages.
* As such (in the interest of efficiency) this object maintains a reference
* to the given octet sequence rather than making a copy; special care
* should be taken by extenal clients never to use this constructor with a
* byte array object that may later be modified extenally.
*
* @param data the octet sequence representing the Blob value
* @throws SQLException if the argument is null
*/
public jdbcBlob(final byte[] data) throws SQLException {
if (data == null) {
throw Util.sqlException(Trace.INVALID_JDBC_ARGUMENT, "null");
}
this.data = data; // (byte[]) data.clone();
}
/**
* Returns the number of bytes in the <code>BLOB value
* designated by this <code>Blob object.
*
* @return length of the <code>BLOB in bytes
* @exception SQLException if there is an error accessing the
* length of the <code>BLOB
*
* @since JDK 1.2, HSQLDB 1.7.2
*/
public long length() throws SQLException {
final byte[] ldata = data;
return ldata.length;
}
/**
* Retrieves all or part of the <code>BLOB value that this
* <code>Blob object represents, as an array of bytes. This
* <code>byte array contains up to length
* consecutive bytes starting at position <code>pos.
*
* <!-- start release-specific documentation -->
* <div class="ReleaseSpecificDocumentation">
* <h3>HSQLDB-Specific Information:
*
* The official specification above is ambiguous in that it does not
* precisely indicate the policy to be observed when
* pos > this.length() - length. One policy would be to retrieve the
* octets from pos to this.length(). Another would be to throw an
* exception. HSQLDB observes the later policy.
* </div>
*
* @param pos the ordinal position of the first byte in the
* <code>BLOB 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
* consecutive bytes from the <code>BLOB value designated
* by this <code>Blob object, starting with the
* byte at position <code>pos
* @exception SQLException if there is an error accessing the
* <code>BLOB value
* @see #setBytes
*
* @since JDK 1.2, HSQLDB 1.7.2
*/
public byte[] getBytes(long pos, final int length) throws SQLException {
final byte[] ldata = data;
final int dlen = ldata.length;
pos--;
if (pos < 0 || pos > dlen) {
throw Util.sqlException(Trace.INVALID_JDBC_ARGUMENT,
"pos: " + (pos + 1));
}
if (length < 0 || length > dlen - pos) {
throw Util.sqlException(Trace.INVALID_JDBC_ARGUMENT,
"length: " + length);
}
final byte[] out = new byte[length];
System.arraycopy(ldata, (int) pos, out, 0, length);
return out;
}
/**
* Retrieves the <code>BLOB value designated by this
* <code>Blob instance as a stream.
*
* @return a stream containing the <code>BLOB data
* @exception SQLException if there is an error accessing the
* <code>BLOB value
* @see #setBinaryStream
*
* @since JDK 1.2, HSQLDB 1.7.2
*/
public InputStream getBinaryStream() throws SQLException {
final byte[] ldata = data;
return new ByteArrayInputStream(ldata);
}
/**
* Retrieves the byte position at which the specified byte array
* <code>pattern begins within the BLOB
* value that this <code>Blob object represents. The
* search for <code>pattern begins at position
* <code>start.
*
* @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
* @exception SQLException if there is an error accessing the
* <code>BLOB
*
* @since JDK 1.2, HSQLDB 1.7.2
*/
public long position(final byte[] pattern,
long start) throws SQLException {
final byte[] ldata = data;
final int dlen = ldata.length;
if (start > dlen || pattern == null) {
return -1;
} else if (start < 1) {
start = 0;
} else {
start--;
}
final int plen = pattern.length;
if (plen == 0 || start > dlen - plen) {
return -1;
}
final int stop = dlen - plen;
final byte b0 = pattern[0];
outer_loop:
for (int i = (int) start; i <= stop; i++) {
if (ldata[i] != b0) {
continue;
}
int len = plen;
int doffset = i;
int poffset = 0;
boolean match = true;
while (len-- > 0) {
if (ldata[doffset++] != pattern[poffset++]) {
continue outer_loop;
}
}
return i + 1;
}
return -1;
}
/**
* Retrieves the byte position in the <code>BLOB value
* designated by this <code>Blob object at which
* <code>pattern begins. The search begins at position
* <code>start.
*
* @param pattern the <code>Blob object designating
* the <code>BLOB value for which to search
* @param start the position in the <code>BLOB value
* at which to begin searching; the first position is 1
* @return the position at which the pattern begins, else -1
* @exception SQLException if there is an error accessing the
* <code>BLOB value
*
* @since JDK 1.2, HSQLDB 1.7.2
*/
public long position(final Blob pattern, long start) throws SQLException {
final byte[] ldata = data;
final int dlen = ldata.length;
if (start > dlen || pattern == null) {
return -1;
} else if (start < 1) {
start = 0;
} else {
start--;
}
final long plen = pattern.length();
if (plen == 0 || start > ((long) dlen) - plen) {
return -1;
}
// by now, we know plen <= Integer.MAX_VALUE
final int iplen = (int) plen;
byte[] bap;
if (pattern instanceof jdbcBlob) {
bap = ((jdbcBlob) pattern).data;
} else {
bap = pattern.getBytes(1, iplen);
}
final int stop = dlen - iplen;
final byte b0 = bap[0];
outer_loop:
for (int i = (int) start; i <= stop; i++) {
if (ldata[i] != b0) {
continue;
}
int len = iplen;
int doffset = i;
int poffset = 0;
while (len-- > 0) {
if (ldata[doffset++] != bap[poffset++]) {
continue outer_loop;
}
}
return i + 1;
}
return -1;
}
// -------------------------- JDBC 3.0 -----------------------------------
/**
* Writes the given array of bytes to the <code>BLOB value that
* this <code>Blob object represents, starting at position
* <code>pos, and returns the number of bytes written.
*
* <!-- start release-specific documentation -->
* <div class="ReleaseSpecificDocumentation">
* <h3>HSQLDB-Specific Information:
*
* HSLQDB 1.7.2 does not support this feature. <p>
*
* Calling this method always throws an <code>SQLException.
* </div>
* <!-- end release-specific documentation -->
*
* @param pos the position in the <code>BLOB object at which
* to start writing
* @param bytes the array of bytes to be written to the <code>BLOB
* value that this <code>Blob object represents
* @return the number of bytes written
* @exception SQLException if there is an error accessing the
* <code>BLOB value
* @see #getBytes
*
* @since JDK 1.4, HSQLDB 1.7.2
*/
public int setBytes(long pos, byte[] bytes) throws SQLException {
throw Util.notSupported();
}
/**
* Writes all or part of the given <code>byte array to the
* <code>BLOB value that this Blob
object represents
* and returns the number of bytes written.
* Writing starts at position <code>pos in the BLOB
* value; <code>len bytes from the given byte array are written.
*
* <!-- start release-specific documentation -->
* <div class="ReleaseSpecificDocumentation">
* <h3>HSQLDB-Specific Information:
*
* HSLQDB 1.7.2 does not support this feature. <p>
*
* Calling this method always throws an <code>SQLException.
* </div>
* <!-- end release-specific documentation -->
*
* @param pos the position in the <code>BLOB object at which
* to start writing
* @param bytes the array of bytes to be written to this <code>BLOB
* object
* @param offset the offset into the array <code>bytes at which
* to start reading the bytes to be set
* @param len the number of bytes to be written to the <code>BLOB
* value from the array of bytes <code>bytes
* @return the number of bytes written
* @exception SQLException if there is an error accessing the
* <code>BLOB value
* @see #getBytes
*
* @since JDK 1.4, HSQLDB 1.7.2
*/
public int setBytes(long pos, byte[] bytes, int offset,
int len) throws SQLException {
throw Util.notSupported();
}
/**
* Retrieves a stream that can be used to write to the <code>BLOB
* value that this <code>Blob object represents. The stream begins
* at position <code>pos.
*
* <!-- start release-specific documentation -->
* <div class="ReleaseSpecificDocumentation">
* <h3>HSQLDB-Specific Information:
*
* HSQLDB 1.7.2 does not support this feature. <p>
*
* Calling this method always throws an <code>SQLException.
* </div>
* <!-- end release-specific documentation -->
*
* @param pos the position in the <code>BLOB value at which
* to start writing
* @return a <code>java.io.OutputStream object to which data can
* be written
* @exception SQLException if there is an error accessing the
* <code>BLOB value
* @see #getBinaryStream
*
* @since JDK 1.4, HSQLDB 1.7.2
*/
public OutputStream setBinaryStream(long pos) throws SQLException {
throw Util.notSupported();
}
/**
* Truncates the <code>BLOB value that this Blob
* object represents to be <code>len bytes in length.
*
* <!-- start release-specific documentation -->
* <div class="ReleaseSpecificDocumentation">
* <h3>HSQLDB-Specific Information:
*
* This operation affects only the client-side value; it has no effect upon
* the value as it is stored in the database.
* </div>
* <!-- end release-specific documentation -->
*
* @param len the length, in bytes, to which the <code>BLOB value
* that this <code>Blob object represents should be truncated
* @exception SQLException if there is an error accessing the
* <code>BLOB value
*
* @since JDK 1.4, HSQLDB 1.7.2
*/
public void truncate(final long len) throws SQLException {
final byte[] ldata = data;
if (len < 0 || len > ldata.length) {
throw Util.sqlException(Trace.INVALID_JDBC_ARGUMENT,
Long.toString(len));
}
if (len == ldata.length) {
return;
}
byte[] newData = new byte[(int) len];
System.arraycopy(ldata, 0, newData, 0, (int) len);
data = newData;
}
//#ifdef JAVA6
/*
public void free() throws SQLException
{
throw new UnsupportedOperationException("Not supported yet.");
}
public InputStream getBinaryStream(long pos, long length) throws SQLException
{
throw new UnsupportedOperationException("Not supported yet.");
}
*/
//#endif JAVA6
// public static void main(String[] args) throws Exception {
//
// System.out.println("--------------------------------");
// System.out.println((new jdbcBlob(new byte[0])).position(new byte[]{1}, 1));
// System.out.println((new jdbcBlob(new byte[]{1})).position(new byte[0], 1));
// System.out.println((new jdbcBlob(new byte[]{1})).position((byte[])null, 1));
//
// System.out.println("--------------------------------");
// byte[] data1 = new byte[]{0,1,2,1,2,3,2,3,4,2,3,4,5,2,3,4,5,0,1,2,
// 1,2,3,2,3,4,2,3,4,5,2,3,4};
// byte[] pattern = new byte[]{2,3,4,5};
//
// jdbcBlob blob1 = new jdbcBlob(data1);
// jdbcBlob blob2 = new jdbcBlob(pattern);
//
// for (int i = -1; i <= data1.length + 1; i++) {
// System.out.println(blob1.position(pattern, i));
// }
//
// System.out.println("--------------------------------");
//
// for (int i = -1; i <= data1.length + 1; i++) {
// System.out.println(blob1.position(blob2, i));
// }
//
// System.out.println("--------------------------------");
//
// new jdbcBlob(null);
// }
}
Other HSQLDB examples (source code examples)
Here is a short list of links related to this HSQLDB jdbcBlob.java source code file: