|
|
What this is
This file is included in the DevDaily.com
"Java Source Code
Warehouse" project. The intent of this project is to help you "Learn
Java by Example" TM.
Other links
The source code
/* Copyright (c) 2001-2004, 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 JavaTM
* programming language of an SQL BLOB value.
*
* 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.
*
*
*
* HSQLDB-Specific Information:
*
* Including 1.7.2, 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.
*
* Currently, the interface methods for updating a BLOB value are
* unsupported. However, the truncate method is supported for local use.
*
*
*
* @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.
*
* 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 jdbcUtil.sqlException(Trace.INVALID_JDBC_ARGUMENT, "null");
}
this.data = data; // (byte[]) data.clone();
}
/**
* Returns the number of bytes in the BLOB value
* designated by this Blob object.
*
* @return length of the BLOB in bytes
* @exception SQLException if there is an error accessing the
* length of the 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 BLOB value that this
* Blob object represents, as an array of bytes. This
* byte array contains up to length
* consecutive bytes starting at position pos.
*
*
*
* 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.
*
*
* @param pos the ordinal position of the first byte in the
* 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 length
* consecutive bytes from the BLOB value designated
* by this Blob object, starting with the
* byte at position pos
* @exception SQLException if there is an error accessing the
* 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 jdbcUtil.sqlException(Trace.INVALID_JDBC_ARGUMENT,
"pos: " + (pos + 1));
}
if (length < 0 || length > dlen - pos) {
throw jdbcUtil.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 BLOB value designated by this
* Blob instance as a stream.
*
* @return a stream containing the BLOB data
* @exception SQLException if there is an error accessing the
* 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
* pattern begins within the BLOB
* value that this Blob object represents. The
* search for pattern begins at position
* 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
* 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 BLOB value
* designated by this Blob object at which
* pattern begins. The search begins at position
* start.
*
* @param pattern the Blob object designating
* the BLOB value for which to search
* @param start the position in the 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
* 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 BLOB value that
* this Blob object represents, starting at position
* pos, and returns the number of bytes written.
*
*
*
* HSQLDB-Specific Information:
*
* HSLQDB 1.7.2 does not support this feature.
*
* Calling this method always throws an SQLException.
*
*
*
* @param pos the position in the BLOB object at which
* to start writing
* @param bytes the array of bytes to be written to the BLOB
* value that this Blob object represents
* @return the number of bytes written
* @exception SQLException if there is an error accessing the
* BLOB value
* @see #getBytes
*
* @since JDK 1.4, HSQLDB 1.7.2
*/
public int setBytes(long pos, byte[] bytes) throws SQLException {
throw jdbcUtil.notSupported;
}
/**
* 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.
* Writing starts at position pos in the BLOB
* value; len bytes from the given byte array are written.
*
*
*
* HSQLDB-Specific Information:
*
* HSLQDB 1.7.2 does not support this feature.
*
* Calling this method always throws an SQLException.
*
*
*
* @param pos the position in the BLOB object at which
* to start writing
* @param bytes the array of bytes to be written to this BLOB
* object
* @param offset the offset into the array bytes at which
* to start reading the bytes to be set
* @param len the number of bytes to be written to the BLOB
* value from the array of bytes bytes
* @return the number of bytes written
* @exception SQLException if there is an error accessing the
* 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 jdbcUtil.notSupported;
}
/**
* Retrieves a stream that can be used to write to the BLOB
* value that this Blob object represents. The stream begins
* at position pos.
*
*
*
* HSQLDB-Specific Information:
*
* HSQLDB 1.7.2 does not support this feature.
*
* Calling this method always throws an SQLException.
*
*
*
* @param pos the position in the BLOB value at which
* to start writing
* @return a java.io.OutputStream object to which data can
* be written
* @exception SQLException if there is an error accessing the
* BLOB value
* @see #getBinaryStream
*
* @since JDK 1.4, HSQLDB 1.7.2
*/
public OutputStream setBinaryStream(long pos) throws SQLException {
throw jdbcUtil.notSupported;
}
/**
* Truncates the BLOB value that this Blob
* object represents to be len bytes in length.
*
*
*
* 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.
*
*
*
* @param len the length, in bytes, to which the BLOB value
* that this Blob object represents should be truncated
* @exception SQLException if there is an error accessing the
* 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 jdbcUtil.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;
}
// 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);
// }
}
|