43 * from a <code>SerialClob</code> object or to locate the start of 44 * a pattern of characters. 45 * 46 * @author Jonathan Bruce 47 */ 48 public class SerialClob implements Clob, Serializable, Cloneable { 49 50 /** 51 * A serialized array of characters containing the data of the SQL 52 * <code>CLOB</code> value that this <code>SerialClob</code> object 53 * represents. 54 * 55 * @serial 56 */ 57 private char buf[]; 58 59 /** 60 * Internal Clob representation if SerialClob is initialized with a 61 * Clob. Null if SerialClob is initialized with a char[]. 62 */ 63 private final Clob clob; 64 65 /** 66 * The length in characters of this <code>SerialClob</code> object's 67 * internal array of characters. 68 * 69 * @serial 70 */ 71 private long len; 72 73 /** 74 * The original length in characters of this <code>SerialClob</code> 75 * object's internal array of characters. 76 * 77 * @serial 78 */ 79 private final long origLen; 80 81 /** 82 * Constructs a <code>SerialClob</code> object that is a serialized version of 83 * the given <code>char</code> array. 84 * <p> 85 * The new <code>SerialClob</code> object is initialized with the data from the 86 * <code>char</code> array, thus allowing disconnected <code>RowSet</code> 87 * objects to establish a serialized <code>Clob</code> object without touching 88 * the data source. 89 * 90 * @param ch the char array representing the <code>Clob</code> object to be 91 * serialized 92 * @throws SerialException if an error occurs during serialization 93 * @throws SQLException if a SQL error occurs 94 */ 95 public SerialClob(char ch[]) throws SerialException, SQLException { 96 97 // %%% JMB. Agreed. Add code here to throw a SQLException if no 98 // support is available for locatorsUpdateCopy=false 99 // Serializing locators is not supported. 162 163 try (Reader reader = new BufferedReader(charStream)) { 164 do { 165 read = reader.read(buf, offset, (int)(len - offset)); 166 offset += read; 167 } while (read > 0); 168 } 169 } catch (java.io.IOException ex) { 170 throw new SerialException("SerialClob: " + ex.getMessage()); 171 } 172 173 origLen = len; 174 } 175 176 /** 177 * Retrieves the number of characters in this <code>SerialClob</code> 178 * object's array of characters. 179 * 180 * @return a <code>long</code> indicating the length in characters of this 181 * <code>SerialClob</code> object's array of character 182 * @throws SerialException if an error occurs 183 */ 184 public long length() throws SerialException { 185 return len; 186 } 187 188 /** 189 * Returns this <code>SerialClob</code> object's data as a stream 190 * of Unicode characters. Unlike the related method, <code>getAsciiStream</code>, 191 * a stream is produced regardless of whether the <code>SerialClob</code> object 192 * was created with a <code>Clob</code> object or a <code>char</code> array. 193 * 194 * @return a <code>java.io.Reader</code> object containing this 195 * <code>SerialClob</code> object's data 196 * @throws SerialException if an error occurs 197 */ 198 public java.io.Reader getCharacterStream() throws SerialException { 199 return (java.io.Reader) new CharArrayReader(buf); 200 } 201 202 /** 203 * Retrieves the <code>CLOB</code> value designated by this <code>SerialClob</code> 204 * object as an ascii stream. This method forwards the <code>getAsciiStream</code> 205 * call to the underlying <code>Clob</code> object in the event that this 206 * <code>SerialClob</code> object is instantiated with a <code>Clob</code> 207 * object. If this <code>SerialClob</code> object is instantiated with 208 * a <code>char</code> array, a <code>SerialException</code> object is thrown. 209 * 210 * @return a <code>java.io.InputStream</code> object containing 211 * this <code>SerialClob</code> object's data 212 * @throws SerialException if this <code>SerialClob</code> object was not instantiated 213 * with a <code>Clob</code> object 214 * @throws SQLException if there is an error accessing the 215 * <code>CLOB</code> value represented by the <code>Clob</code> object that was 216 * used to create this <code>SerialClob</code> object 217 */ 218 public java.io.InputStream getAsciiStream() throws SerialException, SQLException { 219 if (this.clob != null) { 220 return this.clob.getAsciiStream(); 221 } else { 222 throw new SerialException("Unsupported operation. SerialClob cannot " + 223 "return a the CLOB value as an ascii stream, unless instantiated " + 224 "with a fully implemented Clob object."); 225 } 226 } 227 228 /** 229 * Returns a copy of the substring contained in this 230 * <code>SerialClob</code> object, starting at the given position 231 * and continuing for the specified number or characters. 232 * 233 * @param pos the position of the first character in the substring 234 * to be copied; the first character of the 235 * <code>SerialClob</code> object is at position 236 * <code>1</code>; must not be less than <code>1</code>, 237 * and the sum of the starting position and the length 238 * of the substring must be less than the length of this 239 * <code>SerialClob</code> object 240 * @param length the number of characters in the substring to be 241 * returned; must not be greater than the length of 242 * this <code>SerialClob</code> object, and the 243 * sum of the starting position and the length 244 * of the substring must be less than the length of this 245 * <code>SerialClob</code> object 246 * @return a <code>String</code> object containing a substring of 247 * this <code>SerialClob</code> object beginning at the 248 * given position and containing the specified number of 249 * consecutive characters 250 * @throws SerialException if either of the arguments is out of bounds 251 */ 252 public String getSubString(long pos, int length) throws SerialException { 253 254 if (pos < 1 || pos > this.length()) { 255 throw new SerialException("Invalid position in BLOB object set"); 256 } 257 258 if ((pos-1) + length > this.length()) { 259 throw new SerialException("Invalid position and substring length"); 260 } 261 262 try { 263 return new String(buf, (int)pos - 1, length); 264 265 } catch (StringIndexOutOfBoundsException e) { 266 throw new SerialException("StringIndexOutOfBoundsException: " + 267 e.getMessage()); 268 } 269 270 } 271 272 /** 273 * Returns the position in this <code>SerialClob</code> object 274 * where the given <code>String</code> object begins, starting 275 * the search at the specified position. This method returns 276 * <code>-1</code> if the pattern is not found. 277 * 278 * @param searchStr the <code>String</code> object for which to 279 * search 280 * @param start the position in this <code>SerialClob</code> object 281 * at which to start the search; the first position is 282 * <code>1</code>; must not be less than <code>1</code> nor 283 * greater than the length of this <code>SerialClob</code> object 284 * @return the position at which the given <code>String</code> object 285 * begins, starting the search at the specified position; 286 * <code>-1</code> if the given <code>String</code> object is 287 * not found or the starting position is out of bounds; position 288 * numbering for the return value starts at <code>1</code> 289 * @throws SerialException if an error occurs locating the String signature 290 * @throws SQLException if there is an error accessing the Blob value 291 * from the database. 292 */ 293 public long position(String searchStr, long start) 294 throws SerialException, SQLException { 295 296 if (start < 1 || start > len) { 297 return -1; 298 } 299 300 char pattern[] = searchStr.toCharArray(); 301 302 int pos = (int)start-1; 303 int i = 0; 304 long patlen = pattern.length; 305 306 while (pos < len) { 307 if (pattern[i] == buf[pos]) { 308 if (i + 1 == patlen) { 309 return (pos + 1) - (patlen - 1); 310 } 311 i++; pos++; // increment pos, and i 312 313 } else if (pattern[i] != buf[pos]) { 314 pos++; // increment pos only 315 } 316 } 317 return -1; // not found 318 } 319 320 /** 321 * Returns the position in this <code>SerialClob</code> object 322 * where the given <code>Clob</code> signature begins, starting 323 * the search at the specified position. This method returns 324 * <code>-1</code> if the pattern is not found. 325 * 326 * @param searchStr the <code>Clob</code> object for which to search 327 * @param start the position in this <code>SerialClob</code> object 328 * at which to begin the search; the first position is 329 * <code>1</code>; must not be less than <code>1</code> nor 330 * greater than the length of this <code>SerialClob</code> object 331 * @return the position at which the given <code>Clob</code> 332 * object begins in this <code>SerialClob</code> object, 333 * at or after the specified starting position 334 * @throws SerialException if an error occurs locating the Clob signature 335 * @throws SQLException if there is an error accessing the Blob value 336 * from the database 337 */ 338 public long position(Clob searchStr, long start) 339 throws SerialException, SQLException { 340 341 return position(searchStr.getSubString(1,(int)searchStr.length()), start); 342 } 343 344 /** 345 * Writes the given Java <code>String</code> to the <code>CLOB</code> 346 * value that this <code>SerialClob</code> object represents, at the position 347 * <code>pos</code>. 348 * 349 * @param pos the position at which to start writing to the <code>CLOB</code> 350 * value that this <code>SerialClob</code> object represents; the first 351 * position is <code>1</code>; must not be less than <code>1</code> nor 352 * greater than the length of this <code>SerialClob</code> object 353 * @param str the string to be written to the <code>CLOB</code> 354 * value that this <code>SerialClob</code> object represents 355 * @return the number of characters written 356 * @throws SerialException if there is an error accessing the 357 * <code>CLOB</code> value; if an invalid position is set; if an 358 * invalid offset value is set; if number of bytes to be written 359 * is greater than the <code>SerialClob</code> length; or the combined 360 * values of the length and offset is greater than the Clob buffer 361 */ 362 public int setString(long pos, String str) throws SerialException { 363 return (setString(pos, str, 0, str.length())); 364 } 365 366 /** 367 * Writes <code>len</code> characters of <code>str</code>, starting 368 * at character <code>offset</code>, to the <code>CLOB</code> value 369 * that this <code>Clob</code> represents. 370 * 371 * @param pos the position at which to start writing to the <code>CLOB</code> 372 * value that this <code>SerialClob</code> object represents; the first 373 * position is <code>1</code>; must not be less than <code>1</code> nor 374 * greater than the length of this <code>SerialClob</code> object 375 * @param str the string to be written to the <code>CLOB</code> 376 * value that this <code>Clob</code> object represents 377 * @param offset the offset into <code>str</code> to start reading 378 * the characters to be written 379 * @param length the number of characters to be written 380 * @return the number of characters written 381 * @throws SerialException if there is an error accessing the 382 * <code>CLOB</code> value; if an invalid position is set; if an 383 * invalid offset value is set; if number of bytes to be written 384 * is greater than the <code>SerialClob</code> length; or the combined 385 * values of the length and offset is greater than the Clob buffer 386 */ 387 public int setString(long pos, String str, int offset, int length) 388 throws SerialException { 389 String temp = str.substring(offset); 390 char cPattern[] = temp.toCharArray(); 391 392 if (offset < 0 || offset > str.length()) { 393 throw new SerialException("Invalid offset in byte array set"); 394 } 395 396 if (pos < 1 || pos > this.length()) { 397 throw new SerialException("Invalid position in BLOB object set"); 398 } 399 400 if ((long)(length) > origLen) { 401 throw new SerialException("Buffer is not sufficient to hold the value"); 402 } 403 404 if ((length + offset) > str.length()) { 405 // need check to ensure length + offset !> bytes.length 406 throw new SerialException("Invalid OffSet. Cannot have combined offset " + 407 " and length that is greater that the Blob buffer"); 408 } 412 while ( i < length || (offset + i +1) < (str.length() - offset ) ) { 413 this.buf[(int)pos + i ] = cPattern[offset + i ]; 414 i++; 415 } 416 return i; 417 } 418 419 /** 420 * Retrieves a stream to be used to write Ascii characters to the 421 * <code>CLOB</code> value that this <code>SerialClob</code> object represents, 422 * starting at position <code>pos</code>. This method forwards the 423 * <code>setAsciiStream()</code> call to the underlying <code>Clob</code> object in 424 * the event that this <code>SerialClob</code> object is instantiated with a 425 * <code>Clob</code> object. If this <code>SerialClob</code> object is instantiated 426 * with a <code>char</code> array, a <code>SerialException</code> object is thrown. 427 * 428 * @param pos the position at which to start writing to the 429 * <code>CLOB</code> object 430 * @return the stream to which ASCII encoded characters can be written 431 * @throws SerialException if SerialClob is not instantiated with a 432 * Clob object that supports <code>setAsciiStream</code> 433 * @throws SQLException if there is an error accessing the 434 * <code>CLOB</code> value 435 * @see #getAsciiStream 436 */ 437 public java.io.OutputStream setAsciiStream(long pos) 438 throws SerialException, SQLException { 439 if (this.clob != null) { 440 return this.clob.setAsciiStream(pos); 441 } else { 442 throw new SerialException("Unsupported operation. SerialClob cannot " + 443 "return a writable ascii stream\n unless instantiated with a Clob object " + 444 "that has a setAsciiStream() implementation"); 445 } 446 } 447 448 /** 449 * Retrieves a stream to be used to write a stream of Unicode characters 450 * to the <code>CLOB</code> value that this <code>SerialClob</code> object 451 * represents, at position <code>pos</code>. This method forwards the 452 * <code>setCharacterStream()</code> call to the underlying <code>Clob</code> 453 * object in the event that this <code>SerialClob</code> object is instantiated with a 454 * <code>Clob</code> object. If this <code>SerialClob</code> object is instantiated with 455 * a <code>char</code> array, a <code>SerialException</code> is thrown. 456 * 457 * @param pos the position at which to start writing to the 458 * <code>CLOB</code> value 459 * 460 * @return a stream to which Unicode encoded characters can be written 461 * @throws SerialException if the SerialClob is not instantiated with 462 * a Clob object that supports <code>setCharacterStream</code> 463 * @throws SQLException if there is an error accessing the 464 * <code>CLOB</code> value 465 * @see #getCharacterStream 466 */ 467 public java.io.Writer setCharacterStream(long pos) 468 throws SerialException, SQLException { 469 if (this.clob != null) { 470 return this.clob.setCharacterStream(pos); 471 } else { 472 throw new SerialException("Unsupported operation. SerialClob cannot " + 473 "return a writable character stream\n unless instantiated with a Clob object " + 474 "that has a setCharacterStream implementation"); 475 } 476 } 477 478 /** 479 * Truncates the <code>CLOB</code> value that this <code>SerialClob</code> 480 * object represents so that it has a length of <code>len</code> 481 * characters. 482 * <p> 483 * Truncating a <code>SerialClob</code> object to length 0 has the effect of 484 * clearing its contents. 485 * 486 * @param length the length, in bytes, to which the <code>CLOB</code> 487 * value should be truncated 488 * @throws SQLException if there is an error accessing the 489 * <code>CLOB</code> value 490 */ 491 public void truncate(long length) throws SerialException { 492 if (length > len) { 493 throw new SerialException 494 ("Length more than what can be truncated"); 495 } else { 496 len = length; 497 // re-size the buffer 498 499 if (len == 0) { 500 buf = new char[] {}; 501 } else { 502 buf = (this.getSubString(1, (int)len)).toCharArray(); 503 } 504 505 } 506 } 507 508 509 public Reader getCharacterStream(long pos, long length) throws SQLException { 510 throw new java.lang.UnsupportedOperationException("Not supported"); 511 } 512 513 public void free() throws SQLException { 514 throw new java.lang.UnsupportedOperationException("Not supported"); 515 } 516 517 /** 518 * The identifier that assists in the serialization of this <code>SerialClob</code> 519 * object. 520 */ 521 static final long serialVersionUID = -1662519690087375313L; 522 } | 43 * from a <code>SerialClob</code> object or to locate the start of 44 * a pattern of characters. 45 * 46 * @author Jonathan Bruce 47 */ 48 public class SerialClob implements Clob, Serializable, Cloneable { 49 50 /** 51 * A serialized array of characters containing the data of the SQL 52 * <code>CLOB</code> value that this <code>SerialClob</code> object 53 * represents. 54 * 55 * @serial 56 */ 57 private char buf[]; 58 59 /** 60 * Internal Clob representation if SerialClob is initialized with a 61 * Clob. Null if SerialClob is initialized with a char[]. 62 */ 63 private Clob clob; 64 65 /** 66 * The length in characters of this <code>SerialClob</code> object's 67 * internal array of characters. 68 * 69 * @serial 70 */ 71 private long len; 72 73 /** 74 * The original length in characters of this <code>SerialClob</code> 75 * object's internal array of characters. 76 * 77 * @serial 78 */ 79 private long origLen; 80 81 private boolean isFree =false; 82 83 /** 84 * Constructs a <code>SerialClob</code> object that is a serialized version of 85 * the given <code>char</code> array. 86 * <p> 87 * The new <code>SerialClob</code> object is initialized with the data from the 88 * <code>char</code> array, thus allowing disconnected <code>RowSet</code> 89 * objects to establish a serialized <code>Clob</code> object without touching 90 * the data source. 91 * 92 * @param ch the char array representing the <code>Clob</code> object to be 93 * serialized 94 * @throws SerialException if an error occurs during serialization 95 * @throws SQLException if a SQL error occurs 96 */ 97 public SerialClob(char ch[]) throws SerialException, SQLException { 98 99 // %%% JMB. Agreed. Add code here to throw a SQLException if no 100 // support is available for locatorsUpdateCopy=false 101 // Serializing locators is not supported. 164 165 try (Reader reader = new BufferedReader(charStream)) { 166 do { 167 read = reader.read(buf, offset, (int)(len - offset)); 168 offset += read; 169 } while (read > 0); 170 } 171 } catch (java.io.IOException ex) { 172 throw new SerialException("SerialClob: " + ex.getMessage()); 173 } 174 175 origLen = len; 176 } 177 178 /** 179 * Retrieves the number of characters in this <code>SerialClob</code> 180 * object's array of characters. 181 * 182 * @return a <code>long</code> indicating the length in characters of this 183 * <code>SerialClob</code> object's array of character 184 * @throws SerialException if an error occurs or 185 * called after free() has been called. 186 */ 187 public long length() throws SerialException { 188 isFreed(); 189 return len; 190 } 191 192 /** 193 * Returns this <code>SerialClob</code> object's data as a stream 194 * of Unicode characters. Unlike the related method, <code>getAsciiStream</code>, 195 * a stream is produced regardless of whether the <code>SerialClob</code> object 196 * was created with a <code>Clob</code> object or a <code>char</code> array. 197 * 198 * @return a <code>java.io.Reader</code> object containing this 199 * <code>SerialClob</code> object's data 200 * @throws SerialException if an error occurs or 201 * called after free() has been called. 202 */ 203 public java.io.Reader getCharacterStream() throws SerialException { 204 isFreed(); 205 return (java.io.Reader) new CharArrayReader(buf); 206 } 207 208 /** 209 * Retrieves the <code>CLOB</code> value designated by this <code>SerialClob</code> 210 * object as an ascii stream. This method forwards the <code>getAsciiStream</code> 211 * call to the underlying <code>Clob</code> object in the event that this 212 * <code>SerialClob</code> object is instantiated with a <code>Clob</code> 213 * object. If this <code>SerialClob</code> object is instantiated with 214 * a <code>char</code> array, a <code>SerialException</code> object is thrown. 215 * 216 * @return a <code>java.io.InputStream</code> object containing 217 * this <code>SerialClob</code> object's data 218 * @throws SerialException if this <code>SerialClob</code> object was not instantiated 219 * with a <code>Clob</code> object or called after free() has been 220 * called. 221 * @throws SQLException 222 * if there is an error accessing the 223 * <code>CLOB</code> value represented by the <code>Clob</code> object that was 224 * used to create this <code>SerialClob</code> object 225 */ 226 public java.io.InputStream getAsciiStream() throws SerialException, SQLException { 227 isFreed(); 228 if (this.clob != null) { 229 return this.clob.getAsciiStream(); 230 } else { 231 throw new SerialException("Unsupported operation. SerialClob cannot " + 232 "return a the CLOB value as an ascii stream, unless instantiated " + 233 "with a fully implemented Clob object."); 234 } 235 } 236 237 /** 238 * Returns a copy of the substring contained in this 239 * <code>SerialClob</code> object, starting at the given position 240 * and continuing for the specified number or characters. 241 * 242 * @param pos the position of the first character in the substring 243 * to be copied; the first character of the 244 * <code>SerialClob</code> object is at position 245 * <code>1</code>; must not be less than <code>1</code>, 246 * and the sum of the starting position and the length 247 * of the substring must be less than the length of this 248 * <code>SerialClob</code> object 249 * @param length the number of characters in the substring to be 250 * returned; must not be greater than the length of 251 * this <code>SerialClob</code> object, and the 252 * sum of the starting position and the length 253 * of the substring must be less than the length of this 254 * <code>SerialClob</code> object 255 * @return a <code>String</code> object containing a substring of 256 * this <code>SerialClob</code> object beginning at the 257 * given position and containing the specified number of 258 * consecutive characters 259 * @throws SerialException if either of the arguments is out of bounds or called 260 * after free() has been called. 261 */ 262 public String getSubString(long pos, int length) throws SerialException { 263 isFreed(); 264 265 if (pos < 1 || pos > this.length()) { 266 throw new SerialException("Invalid position in BLOB object set"); 267 } 268 269 if ((pos-1) + length > this.length()) { 270 throw new SerialException("Invalid position and substring length"); 271 } 272 273 try { 274 return new String(buf, (int)pos - 1, length); 275 276 } catch (StringIndexOutOfBoundsException e) { 277 throw new SerialException("StringIndexOutOfBoundsException: " + 278 e.getMessage()); 279 } 280 281 } 282 283 /** 284 * Returns the position in this <code>SerialClob</code> object 285 * where the given <code>String</code> object begins, starting 286 * the search at the specified position. This method returns 287 * <code>-1</code> if the pattern is not found. 288 * 289 * @param searchStr the <code>String</code> object for which to 290 * search 291 * @param start the position in this <code>SerialClob</code> object 292 * at which to start the search; the first position is 293 * <code>1</code>; must not be less than <code>1</code> nor 294 * greater than the length of this <code>SerialClob</code> object 295 * @return the position at which the given <code>String</code> object 296 * begins, starting the search at the specified position; 297 * <code>-1</code> if the given <code>String</code> object is 298 * not found or the starting position is out of bounds; position 299 * numbering for the return value starts at <code>1</code> 300 * @throws SerialException if an error occurs locating the String signature 301 * or called after free() has been called. 302 * @throws SQLException if there is an error accessing the Blob value 303 * from the database. 304 */ 305 public long position(String searchStr, long start) 306 throws SerialException, SQLException { 307 isFreed(); 308 309 if (start < 1 || start > len) { 310 return -1; 311 } 312 313 char pattern[] = searchStr.toCharArray(); 314 315 int pos = (int)start-1; 316 int i = 0; 317 long patlen = pattern.length; 318 319 while (pos < len) { 320 if (pattern[i] == buf[pos]) { 321 if (i + 1 == patlen) { 322 return (pos + 1) - (patlen - 1); 323 } 324 i++; pos++; // increment pos, and i 325 326 } else if (pattern[i] != buf[pos]) { 327 pos++; // increment pos only 328 } 329 } 330 return -1; // not found 331 } 332 333 /** 334 * Returns the position in this <code>SerialClob</code> object 335 * where the given <code>Clob</code> signature begins, starting 336 * the search at the specified position. This method returns 337 * <code>-1</code> if the pattern is not found. 338 * 339 * @param searchStr the <code>Clob</code> object for which to search 340 * @param start the position in this <code>SerialClob</code> object 341 * at which to begin the search; the first position is 342 * <code>1</code>; must not be less than <code>1</code> nor 343 * greater than the length of this <code>SerialClob</code> object 344 * @return the position at which the given <code>Clob</code> 345 * object begins in this <code>SerialClob</code> object, 346 * at or after the specified starting position 347 * @throws SerialException if an error occurs locating the Clob signature 348 * or called after free() has been called. 349 * @throws SQLException if there is an error accessing the Blob value 350 * from the database 351 */ 352 public long position(Clob searchStr, long start) 353 throws SerialException, SQLException { 354 isFreed(); 355 356 return position(searchStr.getSubString(1,(int)searchStr.length()), start); 357 } 358 359 /** 360 * Writes the given Java <code>String</code> to the <code>CLOB</code> 361 * value that this <code>SerialClob</code> object represents, at the position 362 * <code>pos</code>. 363 * 364 * @param pos the position at which to start writing to the <code>CLOB</code> 365 * value that this <code>SerialClob</code> object represents; the first 366 * position is <code>1</code>; must not be less than <code>1</code> nor 367 * greater than the length of this <code>SerialClob</code> object 368 * @param str the string to be written to the <code>CLOB</code> 369 * value that this <code>SerialClob</code> object represents 370 * @return the number of characters written 371 * @throws SerialException if there is an error accessing the 372 * <code>CLOB</code> value; if an invalid position is set; if an 373 * invalid offset value is set; if number of bytes to be written 374 * is greater than the <code>SerialClob</code> length; or the combined 375 * values of the length and offset is greater than the Clob buffer or 376 * called after free() has been called. 377 */ 378 public int setString(long pos, String str) throws SerialException { 379 isFreed(); 380 381 return (setString(pos, str, 0, str.length())); 382 } 383 384 /** 385 * Writes <code>len</code> characters of <code>str</code>, starting 386 * at character <code>offset</code>, to the <code>CLOB</code> value 387 * that this <code>Clob</code> represents. 388 * 389 * @param pos the position at which to start writing to the <code>CLOB</code> 390 * value that this <code>SerialClob</code> object represents; the first 391 * position is <code>1</code>; must not be less than <code>1</code> nor 392 * greater than the length of this <code>SerialClob</code> object 393 * @param str the string to be written to the <code>CLOB</code> 394 * value that this <code>Clob</code> object represents 395 * @param offset the offset into <code>str</code> to start reading 396 * the characters to be written 397 * @param length the number of characters to be written 398 * @return the number of characters written 399 * @throws SerialException if there is an error accessing the 400 * <code>CLOB</code> value; if an invalid position is set; if an 401 * invalid offset value is set; if number of bytes to be written 402 * is greater than the <code>SerialClob</code> length; or the combined 403 * values of the length and offset is greater than the Clob buffer or 404 * called after free() has been called. 405 */ 406 public int setString(long pos, String str, int offset, int length) 407 throws SerialException { 408 isFreed(); 409 410 String temp = str.substring(offset); 411 char cPattern[] = temp.toCharArray(); 412 413 if (offset < 0 || offset > str.length()) { 414 throw new SerialException("Invalid offset in byte array set"); 415 } 416 417 if (pos < 1 || pos > this.length()) { 418 throw new SerialException("Invalid position in BLOB object set"); 419 } 420 421 if ((long)(length) > origLen) { 422 throw new SerialException("Buffer is not sufficient to hold the value"); 423 } 424 425 if ((length + offset) > str.length()) { 426 // need check to ensure length + offset !> bytes.length 427 throw new SerialException("Invalid OffSet. Cannot have combined offset " + 428 " and length that is greater that the Blob buffer"); 429 } 433 while ( i < length || (offset + i +1) < (str.length() - offset ) ) { 434 this.buf[(int)pos + i ] = cPattern[offset + i ]; 435 i++; 436 } 437 return i; 438 } 439 440 /** 441 * Retrieves a stream to be used to write Ascii characters to the 442 * <code>CLOB</code> value that this <code>SerialClob</code> object represents, 443 * starting at position <code>pos</code>. This method forwards the 444 * <code>setAsciiStream()</code> call to the underlying <code>Clob</code> object in 445 * the event that this <code>SerialClob</code> object is instantiated with a 446 * <code>Clob</code> object. If this <code>SerialClob</code> object is instantiated 447 * with a <code>char</code> array, a <code>SerialException</code> object is thrown. 448 * 449 * @param pos the position at which to start writing to the 450 * <code>CLOB</code> object 451 * @return the stream to which ASCII encoded characters can be written 452 * @throws SerialException if SerialClob is not instantiated with a 453 * Clob object that supports <code>setAsciiStream</code> or 454 * called after free() has been called. 455 * @throws SQLException if there is an error accessing the 456 * <code>CLOB</code> value 457 * @see #getAsciiStream 458 */ 459 public java.io.OutputStream setAsciiStream(long pos) 460 throws SerialException, SQLException { 461 isFreed(); 462 463 if (this.clob != null) { 464 return this.clob.setAsciiStream(pos); 465 } else { 466 throw new SerialException("Unsupported operation. SerialClob cannot " + 467 "return a writable ascii stream\n unless instantiated with a Clob object " + 468 "that has a setAsciiStream() implementation"); 469 } 470 } 471 472 /** 473 * Retrieves a stream to be used to write a stream of Unicode characters 474 * to the <code>CLOB</code> value that this <code>SerialClob</code> object 475 * represents, at position <code>pos</code>. This method forwards the 476 * <code>setCharacterStream()</code> call to the underlying <code>Clob</code> 477 * object in the event that this <code>SerialClob</code> object is instantiated with a 478 * <code>Clob</code> object. If this <code>SerialClob</code> object is instantiated with 479 * a <code>char</code> array, a <code>SerialException</code> is thrown. 480 * 481 * @param pos the position at which to start writing to the 482 * <code>CLOB</code> value 483 * 484 * @return a stream to which Unicode encoded characters can be written 485 * @throws SerialException if the SerialClob is not instantiated with 486 * a Clob object that supports <code>setCharacterStream</code> or 487 * called after free() has been called. 488 * @throws SQLException if there is an error accessing the 489 * <code>CLOB</code> value 490 * @see #getCharacterStream 491 */ 492 public java.io.Writer setCharacterStream(long pos) 493 throws SerialException, SQLException { 494 isFreed(); 495 496 if (this.clob != null) { 497 return this.clob.setCharacterStream(pos); 498 } else { 499 throw new SerialException("Unsupported operation. SerialClob cannot " + 500 "return a writable character stream\n unless instantiated with a Clob object " + 501 "that has a setCharacterStream implementation"); 502 } 503 } 504 505 /** 506 * Truncates the <code>CLOB</code> value that this <code>SerialClob</code> 507 * object represents so that it has a length of <code>len</code> 508 * characters. 509 * <p> 510 * Truncating a <code>SerialClob</code> object to length 0 has the effect of 511 * clearing its contents. 512 * 513 * @param length the length, in bytes, to which the <code>CLOB</code> 514 * value should be truncated 515 * @throws SQLException if there is an error accessing the 516 * <code>CLOB</code> value 517 * @throws SerialException if called after free() has been called. 518 */ 519 public void truncate(long length) throws SerialException { 520 isFreed(); 521 522 if (length > len) { 523 throw new SerialException("Length more than what can be truncated"); 524 } else { 525 len = length; 526 // re-size the buffer 527 528 if (len == 0) { 529 buf = new char[] {}; 530 } else { 531 buf = (this.getSubString(1, (int) len)).toCharArray(); 532 } 533 534 } 535 } 536 537 /** 538 * Returns a <code>Reader</code> object that contains a partial 539 * <code>Clob</code> value, starting with the character specified by 540 * pos, which is length characters in length. 541 * 542 * @param pos 543 * the offset to the first character of the partial value 544 * to be retrieved. The first character in the 545 * <code>Clob</code> is at position 1. 546 * @param length 547 * the length in characters of the partial value to be 548 * retrieved. 549 * 550 * @return Reader through which the partial <code>Clob</code> value 551 * can be read. 552 * @throws SQLException 553 * if pos is less than 1 or if pos is greater than the 554 * number of characters in the <code>Clob</code> or if 555 * pos + length is greater than the number of characters 556 * in the <code>Clob</code> 557 * @throws SQLFeatureNotSupportedException 558 * if the JDBC driver does not support this method 559 * @throws SerialException if called after free() has been called. 560 */ 561 public Reader getCharacterStream(long pos, long length) throws SQLException { 562 isFreed(); 563 564 if (pos < 1 || pos > len) { 565 throw new SerialException("Invalid pos in getCharacterStream"); 566 } 567 if ((pos - 1) + length > len) { 568 throw new SerialException("pos + length greater than total number of bytes"); 569 } 570 return (java.io.Reader) new CharArrayReader(buf, (int) pos -1, (int)length); 571 } 572 573 /** 574 * This method frees the <code>Clob</code> object and releases the 575 * resources the resources that it holds. The object is invalid once 576 * the <code>free</code> method is called. After <code>free</code> 577 * has been called, any attempt to invoke a method other than 578 * <code>free</code> will result in a <code>SQLException</code> being 579 * thrown. If <code>free</code> is called multiple times, the 580 * subsequent calls to <code>free<c/ode> are treated as a no-op. 581 * 582 * @throws SQLException if an error occurs releasing the <code>Clob</code>'s 583 * resources 584 * @throws SQLFeatureNotSupportedException if the JDBC driver does 585 * not support this method 586 */ 587 public void free() throws SQLException { 588 if (isFree == false) { 589 len = -1; 590 origLen = -1; 591 buf = null; 592 593 if (clob != null) { 594 clob.free(); 595 clob = null; 596 } 597 598 isFree = true; 599 } 600 } 601 602 private void isFreed() throws SerialException { 603 if (isFree == true) { 604 throw new SerialException( 605 "Unsupported operation. SerialClob cannot " 606 + "execute this operation when it has already been freed by free()"); 607 } 608 } 609 610 /** 611 * The identifier that assists in the serialization of this <code>SerialClob</code> 612 * object. 613 */ 614 static final long serialVersionUID = -1662519690087375313L; 615 } |