KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hsqldb > jdbc > jdbcBlob


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

30
31
32 package org.hsqldb.jdbc;
33
34 import java.io.ByteArrayInputStream JavaDoc;
35 import java.io.InputStream JavaDoc;
36 import java.io.OutputStream JavaDoc;
37 import java.sql.Blob JavaDoc;
38 import java.sql.SQLException JavaDoc;
39
40 import org.hsqldb.Trace;
41
42 // boucherb@users 2004-04-xx - patch 1.7.2 - position and truncate methods
43
// implemented; minor changes for moderate thread
44
// safety and optimal performance
45
// boucherb@users 2004-04-xx - doc 1.7.2 - javadocs updated; methods put in
46
// correct (historical, interface declared) order
47

48 /**
49  * The representation (mapping) in the Java<sup><font size=-2>TM</font></sup>
50  * programming language of an SQL BLOB value. <p>
51  *
52  * Provides methods for getting the length of an SQL BLOB (Binary Large Object)
53  * value, for materializing a BLOB value on the client, and for determining the
54  * position of an octet sequence (byte pattern) within a BLOB value. <p>
55  *
56  * <!-- start Release-specific documentation -->
57  * <div class="ReleaseSpecificDocumentation">
58  * <h3>HSQLDB-Specific Information:</h3> <p>
59  *
60  * Including 1.8.x, the HSQLDB driver does not implement Blob using an SQL
61  * locator(BLOB). That is, an HSQLDB Blob object does not contain a logical
62  * pointer to SQL BLOB data; rather it directly contains a representation of
63  * the data (a byte array). As a result, an HSQLDB Blob object is itself
64  * valid beyond the duration of the transaction in which is was created,
65  * although it does not necessarily represent a corresponding value
66  * on the database. <p>
67  *
68  * Currently, the interface methods for updating a BLOB value are
69  * unsupported. However, the truncate method is supported for local use.
70  * </div>
71  * <!-- start Release-specific documentation -->
72  *
73  * @author james house jhouse@part.net
74  * @author boucherb@users
75  * @version 1.7.2
76  * @since JDK 1.2, HSQLDB 1.7.2
77  */

78 public class jdbcBlob implements Blob JavaDoc {
79
80     volatile byte[] data;
81
82     /**
83      * Constructs a new jdbcBlob instance wrapping the given octet sequence. <p>
84      *
85      * This constructor is used internally to retrieve result set values as
86      * Blob objects, yet it must be public to allow access from other packages.
87      * As such (in the interest of efficiency) this object maintains a reference
88      * to the given octet sequence rather than making a copy; special care
89      * should be taken by extenal clients never to use this constructor with a
90      * byte array object that may later be modified extenally.
91      *
92      * @param data the octet sequence representing the Blob value
93      * @throws SQLException if the argument is null
94      */

95     public jdbcBlob(final byte[] data) throws SQLException JavaDoc {
96
97         if (data == null) {
98             throw Util.sqlException(Trace.INVALID_JDBC_ARGUMENT, "null");
99         }
100
101         this.data = data; // (byte[]) data.clone();
102
}
103
104     /**
105      * Returns the number of bytes in the <code>BLOB</code> value
106      * designated by this <code>Blob</code> object.
107      *
108      * @return length of the <code>BLOB</code> in bytes
109      * @exception SQLException if there is an error accessing the
110      * length of the <code>BLOB</code>
111      *
112      * @since JDK 1.2, HSQLDB 1.7.2
113      */

114     public long length() throws SQLException JavaDoc {
115
116         final byte[] ldata = data;
117
118         return ldata.length;
119     }
120
121     /**
122      * Retrieves all or part of the <code>BLOB</code> value that this
123      * <code>Blob</code> object represents, as an array of bytes. This
124      * <code>byte</code> array contains up to <code>length</code>
125      * consecutive bytes starting at position <code>pos</code>. <p>
126      *
127      * <!-- start release-specific documentation -->
128      * <div class="ReleaseSpecificDocumentation">
129      * <h3>HSQLDB-Specific Information:</h3> <p>
130      *
131      * The official specification above is ambiguous in that it does not
132      * precisely indicate the policy to be observed when
133      * pos > this.length() - length. One policy would be to retrieve the
134      * octets from pos to this.length(). Another would be to throw an
135      * exception. HSQLDB observes the later policy.
136      * </div>
137      *
138      * @param pos the ordinal position of the first byte in the
139      * <code>BLOB</code> value to be extracted; the first byte is at
140      * position 1
141      * @param length the number of consecutive bytes to be copied
142      * @return a byte array containing up to <code>length</code>
143      * consecutive bytes from the <code>BLOB</code> value designated
144      * by this <code>Blob</code> object, starting with the
145      * byte at position <code>pos</code>
146      * @exception SQLException if there is an error accessing the
147      * <code>BLOB</code> value
148      * @see #setBytes
149      *
150      * @since JDK 1.2, HSQLDB 1.7.2
151      */

152     public byte[] getBytes(long pos, final int length) throws SQLException JavaDoc {
153
154         final byte[] ldata = data;
155         final int dlen = ldata.length;
156
157         pos--;
158
159         if (pos < 0 || pos > dlen) {
160             throw Util.sqlException(Trace.INVALID_JDBC_ARGUMENT,
161                                     "pos: " + (pos + 1));
162         }
163
164         if (length < 0 || length > dlen - pos) {
165             throw Util.sqlException(Trace.INVALID_JDBC_ARGUMENT,
166                                     "length: " + length);
167         }
168
169         final byte[] out = new byte[length];
170
171         System.arraycopy(ldata, (int) pos, out, 0, length);
172
173         return out;
174     }
175
176     /**
177      * Retrieves the <code>BLOB</code> value designated by this
178      * <code>Blob</code> instance as a stream.
179      *
180      * @return a stream containing the <code>BLOB</code> data
181      * @exception SQLException if there is an error accessing the
182      * <code>BLOB</code> value
183      * @see #setBinaryStream
184      *
185      * @since JDK 1.2, HSQLDB 1.7.2
186      */

187     public InputStream JavaDoc getBinaryStream() throws SQLException JavaDoc {
188
189         final byte[] ldata = data;
190
191         return new ByteArrayInputStream JavaDoc(ldata);
192     }
193
194     /**
195      * Retrieves the byte position at which the specified byte array
196      * <code>pattern</code> begins within the <code>BLOB</code>
197      * value that this <code>Blob</code> object represents. The
198      * search for <code>pattern</code> begins at position
199      * <code>start</code>. <p>
200      *
201      * @param pattern the byte array for which to search
202      * @param start the position at which to begin searching; the
203      * first position is 1
204      * @return the position at which the pattern appears, else -1
205      * @exception SQLException if there is an error accessing the
206      * <code>BLOB</code>
207      *
208      * @since JDK 1.2, HSQLDB 1.7.2
209      */

210     public long position(final byte[] pattern,
211                          long start) throws SQLException JavaDoc {
212
213         final byte[] ldata = data;
214         final int dlen = ldata.length;
215
216         if (start > dlen || pattern == null) {
217             return -1;
218         } else if (start < 1) {
219             start = 0;
220         } else {
221             start--;
222         }
223
224         final int plen = pattern.length;
225
226         if (plen == 0 || start > dlen - plen) {
227             return -1;
228         }
229
230         final int stop = dlen - plen;
231         final byte b0 = pattern[0];
232
233         outer_loop:
234         for (int i = (int) start; i <= stop; i++) {
235             if (ldata[i] != b0) {
236                 continue;
237             }
238
239             int len = plen;
240             int doffset = i;
241             int poffset = 0;
242             boolean match = true;
243
244             while (len-- > 0) {
245                 if (ldata[doffset++] != pattern[poffset++]) {
246                     continue outer_loop;
247                 }
248             }
249
250             return i + 1;
251         }
252
253         return -1;
254     }
255
256     /**
257      * Retrieves the byte position in the <code>BLOB</code> value
258      * designated by this <code>Blob</code> object at which
259      * <code>pattern</code> begins. The search begins at position
260      * <code>start</code>.
261      *
262      * @param pattern the <code>Blob</code> object designating
263      * the <code>BLOB</code> value for which to search
264      * @param start the position in the <code>BLOB</code> value
265      * at which to begin searching; the first position is 1
266      * @return the position at which the pattern begins, else -1
267      * @exception SQLException if there is an error accessing the
268      * <code>BLOB</code> value
269      *
270      * @since JDK 1.2, HSQLDB 1.7.2
271      */

272     public long position(final Blob JavaDoc pattern, long start) throws SQLException JavaDoc {
273
274         final byte[] ldata = data;
275         final int dlen = ldata.length;
276
277         if (start > dlen || pattern == null) {
278             return -1;
279         } else if (start < 1) {
280             start = 0;
281         } else {
282             start--;
283         }
284
285         final long plen = pattern.length();
286
287         if (plen == 0 || start > ((long) dlen) - plen) {
288             return -1;
289         }
290
291         // by now, we know plen <= Integer.MAX_VALUE
292
final int iplen = (int) plen;
293         byte[] bap;
294
295         if (pattern instanceof jdbcBlob) {
296             bap = ((jdbcBlob) pattern).data;
297         } else {
298             bap = pattern.getBytes(1, iplen);
299         }
300
301         final int stop = dlen - iplen;
302         final byte b0 = bap[0];
303
304         outer_loop:
305         for (int i = (int) start; i <= stop; i++) {
306             if (ldata[i] != b0) {
307                 continue;
308             }
309
310             int len = iplen;
311             int doffset = i;
312             int poffset = 0;
313
314             while (len-- > 0) {
315                 if (ldata[doffset++] != bap[poffset++]) {
316                     continue outer_loop;
317                 }
318             }
319
320             return i + 1;
321         }
322
323         return -1;
324     }
325
326     // -------------------------- JDBC 3.0 -----------------------------------
327

328     /**
329      * Writes the given array of bytes to the <code>BLOB</code> value that
330      * this <code>Blob</code> object represents, starting at position
331      * <code>pos</code>, and returns the number of bytes written. <p>
332      *
333      * <!-- start release-specific documentation -->
334      * <div class="ReleaseSpecificDocumentation">
335      * <h3>HSQLDB-Specific Information:</h3> <p>
336      *
337      * HSLQDB 1.7.2 does not support this feature. <p>
338      *
339      * Calling this method always throws an <code>SQLException</code>.
340      * </div>
341      * <!-- end release-specific documentation -->
342      *
343      * @param pos the position in the <code>BLOB</code> object at which
344      * to start writing
345      * @param bytes the array of bytes to be written to the <code>BLOB</code>
346      * value that this <code>Blob</code> object represents
347      * @return the number of bytes written
348      * @exception SQLException if there is an error accessing the
349      * <code>BLOB</code> value
350      * @see #getBytes
351      *
352      * @since JDK 1.4, HSQLDB 1.7.2
353      */

354     public int setBytes(long pos, byte[] bytes) throws SQLException JavaDoc {
355         throw Util.notSupported();
356     }
357
358     /**
359      * Writes all or part of the given <code>byte</code> array to the
360      * <code>BLOB</code> value that this <code>Blob</code> object represents
361      * and returns the number of bytes written.
362      * Writing starts at position <code>pos</code> in the <code>BLOB</code>
363      * value; <code>len</code> bytes from the given byte array are written. <p>
364      *
365      * <!-- start release-specific documentation -->
366      * <div class="ReleaseSpecificDocumentation">
367      * <h3>HSQLDB-Specific Information:</h3> <p>
368      *
369      * HSLQDB 1.7.2 does not support this feature. <p>
370      *
371      * Calling this method always throws an <code>SQLException</code>.
372      * </div>
373      * <!-- end release-specific documentation -->
374      *
375      * @param pos the position in the <code>BLOB</code> object at which
376      * to start writing
377      * @param bytes the array of bytes to be written to this <code>BLOB</code>
378      * object
379      * @param offset the offset into the array <code>bytes</code> at which
380      * to start reading the bytes to be set
381      * @param len the number of bytes to be written to the <code>BLOB</code>
382      * value from the array of bytes <code>bytes</code>
383      * @return the number of bytes written
384      * @exception SQLException if there is an error accessing the
385      * <code>BLOB</code> value
386      * @see #getBytes
387      *
388      * @since JDK 1.4, HSQLDB 1.7.2
389      */

390     public int setBytes(long pos, byte[] bytes, int offset,
391                         int len) throws SQLException JavaDoc {
392         throw Util.notSupported();
393     }
394
395     /**
396      * Retrieves a stream that can be used to write to the <code>BLOB</code>
397      * value that this <code>Blob</code> object represents. The stream begins
398      * at position <code>pos</code>. <p>
399      *
400      * <!-- start release-specific documentation -->
401      * <div class="ReleaseSpecificDocumentation">
402      * <h3>HSQLDB-Specific Information:</h3> <p>
403      *
404      * HSQLDB 1.7.2 does not support this feature. <p>
405      *
406      * Calling this method always throws an <code>SQLException</code>.
407      * </div>
408      * <!-- end release-specific documentation -->
409      *
410      * @param pos the position in the <code>BLOB</code> value at which
411      * to start writing
412      * @return a <code>java.io.OutputStream</code> object to which data can
413      * be written
414      * @exception SQLException if there is an error accessing the
415      * <code>BLOB</code> value
416      * @see #getBinaryStream
417      *
418      * @since JDK 1.4, HSQLDB 1.7.2
419      */

420     public OutputStream JavaDoc setBinaryStream(long pos) throws SQLException JavaDoc {
421         throw Util.notSupported();
422     }
423
424     /**
425      * Truncates the <code>BLOB</code> value that this <code>Blob</code>
426      * object represents to be <code>len</code> bytes in length.
427      *
428      * <!-- start release-specific documentation -->
429      * <div class="ReleaseSpecificDocumentation">
430      * <h3>HSQLDB-Specific Information:</h3> <p>
431      *
432      * This operation affects only the client-side value; it has no effect upon
433      * the value as it is stored in the database.
434      * </div>
435      * <!-- end release-specific documentation -->
436      *
437      * @param len the length, in bytes, to which the <code>BLOB</code> value
438      * that this <code>Blob</code> object represents should be truncated
439      * @exception SQLException if there is an error accessing the
440      * <code>BLOB</code> value
441      *
442      * @since JDK 1.4, HSQLDB 1.7.2
443      */

444     public void truncate(final long len) throws SQLException JavaDoc {
445
446         final byte[] ldata = data;
447
448         if (len < 0 || len > ldata.length) {
449             throw Util.sqlException(Trace.INVALID_JDBC_ARGUMENT,
450                                     Long.toString(len));
451         }
452
453         if (len == ldata.length) {
454             return;
455         }
456
457         byte[] newData = new byte[(int) len];
458
459         System.arraycopy(ldata, 0, newData, 0, (int) len);
460
461         data = newData;
462     }
463
464 // public static void main(String[] args) throws Exception {
465
//
466
// System.out.println("--------------------------------");
467
// System.out.println((new jdbcBlob(new byte[0])).position(new byte[]{1}, 1));
468
// System.out.println((new jdbcBlob(new byte[]{1})).position(new byte[0], 1));
469
// System.out.println((new jdbcBlob(new byte[]{1})).position((byte[])null, 1));
470
//
471
// System.out.println("--------------------------------");
472
// byte[] data1 = new byte[]{0,1,2,1,2,3,2,3,4,2,3,4,5,2,3,4,5,0,1,2,
473
// 1,2,3,2,3,4,2,3,4,5,2,3,4};
474
// byte[] pattern = new byte[]{2,3,4,5};
475
//
476
// jdbcBlob blob1 = new jdbcBlob(data1);
477
// jdbcBlob blob2 = new jdbcBlob(pattern);
478
//
479
// for (int i = -1; i <= data1.length + 1; i++) {
480
// System.out.println(blob1.position(pattern, i));
481
// }
482
//
483
// System.out.println("--------------------------------");
484
//
485
// for (int i = -1; i <= data1.length + 1; i++) {
486
// System.out.println(blob1.position(blob2, i));
487
// }
488
//
489
// System.out.println("--------------------------------");
490
//
491
// new jdbcBlob(null);
492
// }
493
}
494
Popular Tags