src/share/classes/javax/sql/rowset/serial/SerialClob.java

Print this page




  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 }