49 * <code>SerialBlob</code> object as an array of bytes or as a stream. |
49 * <code>SerialBlob</code> object as an array of bytes or as a stream. |
50 * They also make it possible to locate a given pattern of bytes or a |
50 * They also make it possible to locate a given pattern of bytes or a |
51 * <code>Blob</code> object within a <code>SerialBlob</code> object |
51 * <code>Blob</code> object within a <code>SerialBlob</code> object |
52 * and to update or truncate a <code>Blob</code> object. |
52 * and to update or truncate a <code>Blob</code> object. |
53 * |
53 * |
|
54 * <h4> Thread safety </h4> |
|
55 * |
|
56 * <p> A SerialBlob is not safe for use by multiple concurrent threads. If a |
|
57 * SerialBlob is to be used by more than one thread then access to the SerialBlob |
|
58 * should be controlled by appropriate synchronization. |
|
59 * |
54 * @author Jonathan Bruce |
60 * @author Jonathan Bruce |
55 */ |
61 */ |
56 public class SerialBlob implements Blob, Serializable, Cloneable { |
62 public class SerialBlob implements Blob, Serializable, Cloneable { |
57 |
63 |
58 /** |
64 /** |
158 * to the length of this <code>SerialBlob</code> object |
164 * to the length of this <code>SerialBlob</code> object |
159 * @param length the number of bytes to be copied |
165 * @param length the number of bytes to be copied |
160 * @return an array of bytes that is a copy of a region of this |
166 * @return an array of bytes that is a copy of a region of this |
161 * <code>SerialBlob</code> object, starting at the given |
167 * <code>SerialBlob</code> object, starting at the given |
162 * position and containing the given number of consecutive bytes |
168 * position and containing the given number of consecutive bytes |
163 * @throws SerialException if the given starting position is out of bounds |
169 * @throws SerialException if the given starting position is out of bounds; |
|
170 * if {@code free} had previously been called on this object |
164 */ |
171 */ |
165 public byte[] getBytes(long pos, int length) throws SerialException { |
172 public byte[] getBytes(long pos, int length) throws SerialException { |
|
173 isValid(); |
166 if (length > len) { |
174 if (length > len) { |
167 length = (int)len; |
175 length = (int)len; |
168 } |
176 } |
169 |
177 |
170 if (pos < 1 || len - pos < 0 ) { |
178 if (pos < 1 || len - pos < 0 ) { |
201 * a stream is produced regardless of whether the <code>SerialBlob</code> |
211 * a stream is produced regardless of whether the <code>SerialBlob</code> |
202 * was created with a <code>Blob</code> object or a <code>byte</code> array. |
212 * was created with a <code>Blob</code> object or a <code>byte</code> array. |
203 * |
213 * |
204 * @return a <code>java.io.InputStream</code> object that contains |
214 * @return a <code>java.io.InputStream</code> object that contains |
205 * this <code>SerialBlob</code> object's array of bytes |
215 * this <code>SerialBlob</code> object's array of bytes |
206 * @throws SerialException if an error occurs |
216 * @throws SerialException if an error occurs; |
|
217 * if {@code free} had previously been called on this object |
207 * @see #setBinaryStream |
218 * @see #setBinaryStream |
208 */ |
219 */ |
209 public java.io.InputStream getBinaryStream() throws SerialException { |
220 public java.io.InputStream getBinaryStream() throws SerialException { |
210 InputStream stream = new ByteArrayInputStream(buf); |
221 isValid(); |
211 return stream; |
222 InputStream stream = new ByteArrayInputStream(buf); |
|
223 return stream; |
212 } |
224 } |
213 |
225 |
214 /** |
226 /** |
215 * Returns the position in this <code>SerialBlob</code> object where |
227 * Returns the position in this <code>SerialBlob</code> object where |
216 * the given pattern of bytes begins, starting the search at the |
228 * the given pattern of bytes begins, starting the search at the |
225 * @return the position in this <code>SerialBlob</code> object |
237 * @return the position in this <code>SerialBlob</code> object |
226 * where the given pattern begins, starting at the specified |
238 * where the given pattern begins, starting at the specified |
227 * position; <code>-1</code> if the pattern is not found |
239 * position; <code>-1</code> if the pattern is not found |
228 * or the given starting position is out of bounds; position |
240 * or the given starting position is out of bounds; position |
229 * numbering for the return value starts at <code>1</code> |
241 * numbering for the return value starts at <code>1</code> |
230 * @throws SerialException if an error occurs when serializing the blob |
242 * @throws SerialException if an error occurs when serializing the blob; |
|
243 * if {@code free} had previously been called on this object |
231 * @throws SQLException if there is an error accessing the <code>BLOB</code> |
244 * @throws SQLException if there is an error accessing the <code>BLOB</code> |
232 * value from the database |
245 * value from the database |
233 */ |
246 */ |
234 public long position(byte[] pattern, long start) |
247 public long position(byte[] pattern, long start) |
235 throws SerialException, SQLException { |
248 throws SerialException, SQLException { |
|
249 isValid(); |
236 if (start < 1 || start > len) { |
250 if (start < 1 || start > len) { |
237 return -1; |
251 return -1; |
238 } |
252 } |
239 |
253 |
240 int pos = (int)start-1; // internally Blobs are stored as arrays. |
254 int pos = (int)start-1; // internally Blobs are stored as arrays. |
268 * @return the position in this <code>SerialBlob</code> object |
282 * @return the position in this <code>SerialBlob</code> object |
269 * where the given <code>Blob</code> object begins, starting |
283 * where the given <code>Blob</code> object begins, starting |
270 * at the specified position; <code>-1</code> if the pattern is |
284 * at the specified position; <code>-1</code> if the pattern is |
271 * not found or the given starting position is out of bounds; |
285 * not found or the given starting position is out of bounds; |
272 * position numbering for the return value starts at <code>1</code> |
286 * position numbering for the return value starts at <code>1</code> |
273 * @throws SerialException if an error occurs when serializing the blob |
287 * @throws SerialException if an error occurs when serializing the blob; |
|
288 * if {@code free} had previously been called on this object |
274 * @throws SQLException if there is an error accessing the <code>BLOB</code> |
289 * @throws SQLException if there is an error accessing the <code>BLOB</code> |
275 * value from the database |
290 * value from the database |
276 */ |
291 */ |
277 public long position(Blob pattern, long start) |
292 public long position(Blob pattern, long start) |
278 throws SerialException, SQLException { |
293 throws SerialException, SQLException { |
|
294 isValid(); |
279 return position(pattern.getBytes(1, (int)(pattern.length())), start); |
295 return position(pattern.getBytes(1, (int)(pattern.length())), start); |
280 } |
296 } |
281 |
297 |
282 /** |
298 /** |
283 * Writes the given array of bytes to the <code>BLOB</code> value that |
299 * Writes the given array of bytes to the <code>BLOB</code> value that |
291 * @param bytes the array of bytes to be written to the <code>BLOB</code> |
307 * @param bytes the array of bytes to be written to the <code>BLOB</code> |
292 * value that this <code>Blob</code> object represents |
308 * value that this <code>Blob</code> object represents |
293 * @return the number of bytes written |
309 * @return the number of bytes written |
294 * @throws SerialException if there is an error accessing the |
310 * @throws SerialException if there is an error accessing the |
295 * <code>BLOB</code> value; or if an invalid position is set; if an |
311 * <code>BLOB</code> value; or if an invalid position is set; if an |
296 * invalid offset value is set |
312 * invalid offset value is set; |
|
313 * if {@code free} had previously been called on this object |
297 * @throws SQLException if there is an error accessing the <code>BLOB</code> |
314 * @throws SQLException if there is an error accessing the <code>BLOB</code> |
298 * value from the database |
315 * value from the database |
299 * @see #getBytes |
316 * @see #getBytes |
300 */ |
317 */ |
301 public int setBytes(long pos, byte[] bytes) |
318 public int setBytes(long pos, byte[] bytes) |
326 * @return the number of bytes written |
343 * @return the number of bytes written |
327 * @throws SerialException if there is an error accessing the |
344 * @throws SerialException if there is an error accessing the |
328 * <code>BLOB</code> value; if an invalid position is set; if an |
345 * <code>BLOB</code> value; if an invalid position is set; if an |
329 * invalid offset value is set; if number of bytes to be written |
346 * invalid offset value is set; if number of bytes to be written |
330 * is greater than the <code>SerialBlob</code> length; or the combined |
347 * is greater than the <code>SerialBlob</code> length; or the combined |
331 * values of the length and offset is greater than the Blob buffer |
348 * values of the length and offset is greater than the Blob buffer; |
|
349 * if {@code free} had previously been called on this object |
332 * @throws SQLException if there is an error accessing the <code>BLOB</code> |
350 * @throws SQLException if there is an error accessing the <code>BLOB</code> |
333 * value from the database. |
351 * value from the database. |
334 * @see #getBytes |
352 * @see #getBytes |
335 */ |
353 */ |
336 public int setBytes(long pos, byte[] bytes, int offset, int length) |
354 public int setBytes(long pos, byte[] bytes, int offset, int length) |
337 throws SerialException, SQLException { |
355 throws SerialException, SQLException { |
338 |
356 |
|
357 isValid(); |
339 if (offset < 0 || offset > bytes.length) { |
358 if (offset < 0 || offset > bytes.length) { |
340 throw new SerialException("Invalid offset in byte array set"); |
359 throw new SerialException("Invalid offset in byte array set"); |
341 } |
360 } |
342 |
361 |
343 if (pos < 1 || pos > this.length()) { |
362 if (pos < 1 || pos > this.length()) { |
376 * @return a <code>java.io.OutputStream</code> object to which data can |
395 * @return a <code>java.io.OutputStream</code> object to which data can |
377 * be written |
396 * be written |
378 * @throws SQLException if there is an error accessing the |
397 * @throws SQLException if there is an error accessing the |
379 * <code>BLOB</code> value |
398 * <code>BLOB</code> value |
380 * @throws SerialException if the SerialBlob in not instantiated with a |
399 * @throws SerialException if the SerialBlob in not instantiated with a |
381 * <code>Blob</code> object that supports <code>setBinaryStream()</code> |
400 * <code>Blob</code> object that supports <code>setBinaryStream()</code>; |
|
401 * if {@code free} had previously been called on this object |
382 * @see #getBinaryStream |
402 * @see #getBinaryStream |
383 */ |
403 */ |
384 public java.io.OutputStream setBinaryStream(long pos) |
404 public java.io.OutputStream setBinaryStream(long pos) |
385 throws SerialException, SQLException { |
405 throws SerialException, SQLException { |
|
406 isValid(); |
386 if (this.blob != null) { |
407 if (this.blob != null) { |
387 return this.blob.setBinaryStream(pos); |
408 return this.blob.setBinaryStream(pos); |
388 } else { |
409 } else { |
389 throw new SerialException("Unsupported operation. SerialBlob cannot " + |
410 throw new SerialException("Unsupported operation. SerialBlob cannot " + |
390 "return a writable binary stream, unless instantiated with a Blob object " + |
411 "return a writable binary stream, unless instantiated with a Blob object " + |
398 * |
419 * |
399 * @param length the length, in bytes, to which the <code>BLOB</code> |
420 * @param length the length, in bytes, to which the <code>BLOB</code> |
400 * value that this <code>Blob</code> object represents should be |
421 * value that this <code>Blob</code> object represents should be |
401 * truncated |
422 * truncated |
402 * @throws SerialException if there is an error accessing the Blob value; |
423 * @throws SerialException if there is an error accessing the Blob value; |
403 * or the length to truncate is greater that the SerialBlob length |
424 * or the length to truncate is greater that the SerialBlob length; |
|
425 * if {@code free} had previously been called on this object |
404 */ |
426 */ |
405 public void truncate(long length) throws SerialException { |
427 public void truncate(long length) throws SerialException { |
406 |
428 |
407 if (length > len) { |
429 isValid(); |
408 throw new SerialException |
430 if (length > len) { |
409 ("Length more than what can be truncated"); |
431 throw new SerialException |
410 } else if((int)length == 0) { |
432 ("Length more than what can be truncated"); |
411 buf = new byte[0]; |
433 } else if((int)length == 0) { |
412 len = length; |
434 buf = new byte[0]; |
413 } else { |
435 len = length; |
414 len = length; |
436 } else { |
415 buf = this.getBytes(1, (int)len); |
437 len = length; |
416 } |
438 buf = this.getBytes(1, (int)len); |
417 } |
439 } |
418 |
440 } |
419 |
441 |
420 /** |
442 |
421 * Returns an <code>InputStream</code> object that contains a partial <code>Blob</code> value, |
443 /** |
422 * starting with the byte specified by pos, which is length bytes in length. |
444 * Returns an |
423 * |
445 * <code>InputStream</code> object that contains a partial |
424 * @param pos the offset to the first byte of the partial value to be retrieved. |
446 * {@code Blob} value, starting with the byte specified by pos, which is |
425 * The first byte in the <code>Blob</code> is at position 1 |
447 * length bytes in length. |
|
448 * |
|
449 * @param pos the offset to the first byte of the partial value to be |
|
450 * retrieved. The first byte in the {@code Blob} is at position 1 |
426 * @param length the length in bytes of the partial value to be retrieved |
451 * @param length the length in bytes of the partial value to be retrieved |
427 * @return <code>InputStream</code> through which the partial <code>Blob</code> value can be read. |
452 * @return |
428 * @throws SQLException if pos is less than 1 or if pos is greater than the number of bytes |
453 * <code>InputStream</code> through which the partial {@code Blob} value can |
429 * in the <code>Blob</code> or if pos + length is greater than the number of bytes |
454 * be read. |
430 * in the <code>Blob</code> |
455 * @throws SQLException if pos is less than 1 or if pos is greater than the |
|
456 * number of bytes in the {@code Blob} or if pos + length is greater than |
|
457 * the number of bytes in the {@code Blob} |
|
458 * @throws SerialException if the {@code free} method had been previously |
|
459 * called on this object |
431 * |
460 * |
432 * @since 1.6 |
461 * @since 1.6 |
433 */ |
462 */ |
434 public InputStream getBinaryStream(long pos,long length) throws SQLException { |
463 public InputStream getBinaryStream(long pos, long length) throws SQLException { |
435 throw new java.lang.UnsupportedOperationException("Not supported"); |
464 isValid(); |
436 } |
465 if (pos < 1 || pos > this.length()) { |
437 |
466 throw new SerialException("Invalid position in BLOB object set"); |
438 |
467 } |
439 /** |
468 if (length < 1 || length > len - pos + 1) { |
440 * This method frees the <code>Blob</code> object and releases the resources that it holds. |
469 throw new SerialException("length is < 1 or pos + length >" |
441 * <code>Blob</code> object. The object is invalid once the <code>free</code> |
470 + "total number of bytes"); |
442 * method is called. If <code>free</code> is called multiple times, the subsequent |
471 } |
443 * calls to <code>free</code> are treated as a no-op. |
472 return new ByteArrayInputStream(buf, (int) pos - 1, (int) length); |
444 * |
473 } |
445 * @throws SQLException if an error occurs releasing |
474 |
446 * the Blob's resources |
475 |
|
476 /** |
|
477 * This method frees the {@code SeriableBlob} object and releases the |
|
478 * resources that it holds. The object is invalid once the {@code free} |
|
479 * method is called. <p> If {@code free} is called multiple times, the |
|
480 * subsequent calls to {@code free} are treated as a no-op. </P> |
|
481 * |
|
482 * @throws SQLException if an error occurs releasing the Blob's resources |
447 * @since 1.6 |
483 * @since 1.6 |
448 */ |
484 */ |
449 public void free() throws SQLException { |
485 public void free() throws SQLException { |
450 throw new java.lang.UnsupportedOperationException("Not supported"); |
486 if (buf != null) { |
|
487 buf = null; |
|
488 if (blob != null) { |
|
489 blob.free(); |
|
490 } |
|
491 blob = null; |
|
492 } |
451 } |
493 } |
452 |
494 |
453 /** |
495 /** |
454 * Compares this SerialBlob to the specified object. The result is {@code |
496 * Compares this SerialBlob to the specified object. The result is {@code |
455 * true} if and only if the argument is not {@code null} and is a {@code |
497 * true} if and only if the argument is not {@code null} and is a {@code |