EMMA Coverage Report (generated Wed Jun 28 22:15:27 PDT 2006)
[all classes][org.apache.derby.impl.jdbc]

COVERAGE SUMMARY FOR SOURCE FILE [EmbedBlob.java]

nameclass, %method, %block, %line, %
EmbedBlob.java100% (1/1)76%  (13/17)93%  (804/861)91%  (182.6/200)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class EmbedBlob100% (1/1)76%  (13/17)93%  (804/861)91%  (182.6/200)
<static initializer> 100% (1/1)100% (3/3)100% (1/1)
EmbedBlob (DataValueDescriptor, EmbedConnection): void 100% (1/1)97%  (72/74)99%  (18.9/19)
checkMatch (Blob): boolean 100% (1/1)81%  (29/36)73%  (11/15)
checkMatch (byte []): boolean 100% (1/1)100% (22/22)100% (5/5)
finalize (): void 100% (1/1)100% (8/8)100% (3/3)
getBinaryStream (): InputStream 100% (1/1)97%  (63/65)99%  (13.8/14)
getBytes (long, int): byte [] 100% (1/1)97%  (170/175)94%  (32/34)
handleMyExceptions (Throwable): SQLException 100% (1/1)100% (16/16)100% (4/4)
length (): long 100% (1/1)98%  (80/82)99%  (17.8/18)
position (Blob, long): long 100% (1/1)84%  (122/145)86%  (29.2/34)
position (byte [], long): long 100% (1/1)95%  (123/130)93%  (27.9/30)
read (): int 100% (1/1)100% (33/33)100% (7/7)
setBinaryStream (long): OutputStream 0%   (0/1)0%   (0/2)0%   (0/1)
setBytes (long, byte []): int 0%   (0/1)0%   (0/2)0%   (0/1)
setBytes (long, byte [], int, int): int 0%   (0/1)0%   (0/2)0%   (0/1)
setPosition (long): void 100% (1/1)98%  (63/64)99%  (11.9/12)
truncate (long): void 0%   (0/1)0%   (0/2)0%   (0/1)

1/*
2 
3   Derby - Class org.apache.derby.impl.jdbc.EmbedBlob
4 
5   Copyright 2000, 2004 The Apache Software Foundation or its licensors, as applicable.
6 
7   Licensed under the Apache License, Version 2.0 (the "License");
8   you may not use this file except in compliance with the License.
9   You may obtain a copy of the License at
10 
11      http://www.apache.org/licenses/LICENSE-2.0
12 
13   Unless required by applicable law or agreed to in writing, software
14   distributed under the License is distributed on an "AS IS" BASIS,
15   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   See the License for the specific language governing permissions and
17   limitations under the License.
18 
19 */
20 
21 
22package org.apache.derby.impl.jdbc;
23 
24import org.apache.derby.iapi.reference.SQLState;
25import org.apache.derby.iapi.error.StandardException;
26import org.apache.derby.iapi.services.sanity.SanityManager;
27import org.apache.derby.iapi.types.DataValueDescriptor;
28import org.apache.derby.iapi.types.Resetable;
29import org.apache.derby.impl.jdbc.ConnectionChild;
30import org.apache.derby.impl.jdbc.EmbedConnection;
31import org.apache.derby.impl.jdbc.Util;
32import org.apache.derby.iapi.services.io.NewByteArrayInputStream;
33import org.apache.derby.iapi.services.io.InputStreamUtil;
34import org.apache.derby.iapi.services.io.ArrayInputStream;
35 
36import java.sql.SQLException;
37import java.sql.Blob;
38import java.io.InputStream;
39import java.io.EOFException;
40import java.io.IOException;
41 
42/**
43    Implements java.sql.Blob (see the JDBC 2.0 spec).
44    A blob sits on top of a BINARY, VARBINARY or LONG VARBINARY column.
45    If its data is small (less than 1 page) it is a byte array taken from
46    the SQLBit class. If it is large (more than 1 page) it is a long column
47    in the database. The long column is accessed as a stream, and is implemented
48    in store as an OverflowInputStream.  The Resetable interface allows sending
49    messages to that stream to initialize itself (reopen its container and
50    lock the corresponding row) and to reset itself to the beginning. 
51 
52    NOTE: In the case that the data is large, it is represented as a stream.
53    This stream is returned to the user in the getBinaryStream() method.
54    This means that we have limited control over the state of the stream,
55    since the user can read bytes from it at any time.  Thus all methods
56    here reset the stream to the beginning before doing any work.
57    CAVEAT: The methods may not behave correctly if a user sets up
58    multiple threads and sucks data from the stream (returned from
59    getBinaryStream()) at the same time as calling the Blob methods.
60 
61  <P><B>Supports</B>
62   <UL>
63   <LI> JSR169 - no subsetting for java.sql.Blob
64   <LI> JDBC 2.0
65   <LI> JDBC 3.0 - no new dependencies on new JDBC 3.0 or JDK 1.4 classes,
66        new update methods can safely be added into implementation.
67   </UL>
68 
69 */
70 
71final class EmbedBlob extends ConnectionChild implements Blob
72{
73    // blob is either bytes or stream
74    private boolean         isBytes;
75    private InputStream     myStream;
76    
77    /*
78     * Length of the BLOB if known. Set to -1 if
79     * the current length of the BLOB is not known.
80     */
81    private long myLength = -1;
82    
83    private byte[]          myBytes;
84    // note: cannot control position of the stream since user can do a getBinaryStream
85    private long            pos;
86    // this stream sits on top of myStream
87    private BinaryToRawStream biStream;
88 
89    // buffer for reading in blobs from a stream (long column)
90    // and trashing them (to set the position of the stream etc.)
91    private static int BLOB_BUF_SIZE = 4096;
92    private byte buf[];
93    
94    //This boolean variable indicates whether the Blob object has
95    //been invalidated by calling free() on it
96    private boolean isValid = true;
97 
98     /**
99     * This constructor is used to create a empty Blob object. It is used by the
100     * Connection interface method createBlob().
101     * 
102     * @param blobBytes A byte array containing the data to be stores in the 
103     *        Blob.
104     *
105     * @param con The EmbedConnection object associated with this Blob object.
106     *
107     */
108    
109     EmbedBlob(byte [] blobBytes,EmbedConnection con) {
110         super(con);
111         myBytes = blobBytes;
112         isBytes = true;
113         myLength = myBytes.length;
114     }
115     
116    /*
117      This constructor should only be called by EmbedResultSet.getBlob
118    */
119    protected EmbedBlob(DataValueDescriptor dvd, EmbedConnection con)
120        throws StandardException
121    {
122        super(con);
123        // if the underlying column is null, ResultSet.getBlob will return null,
124        // never should get this far
125        if (SanityManager.DEBUG)
126            SanityManager.ASSERT(!dvd.isNull(), "blob is created on top of a null column");
127 
128        myStream = dvd.getStream();
129        if (myStream == null)
130        {
131            isBytes = true;
132            // copy bytes into memory so that blob can live after result set
133            // is closed
134            byte[] dvdBytes = dvd.getBytes();
135 
136            if (SanityManager.DEBUG)
137                SanityManager.ASSERT(dvdBytes != null,"blob has a null value underneath");
138 
139            myLength = dvdBytes.length;
140            myBytes = new byte[dvdBytes.length];
141            System.arraycopy(dvdBytes, 0, myBytes, 0, dvdBytes.length);
142        }
143        else
144        {
145            isBytes = false;
146 
147            /*
148             We are expecting this stream to be a FormatIdInputStream with an
149             OverflowInputStream inside. FormatIdInputStream implements
150             Resetable. This should be the case when retrieving
151             data from a long column. However, SQLBit, which is the class
152             implementing the getStream() method for dvd.getStream(), does not
153             guarantee this for us
154             */
155            if (SanityManager.DEBUG)
156                SanityManager.ASSERT(myStream instanceof Resetable);
157 
158            try {
159                ((Resetable) myStream).initStream();
160            } catch (StandardException se) {
161                if (se.getMessageId().equals(SQLState.DATA_CONTAINER_CLOSED)) {
162                    throw StandardException
163                            .newException(SQLState.BLOB_ACCESSED_AFTER_COMMIT);
164                }
165            }
166            // set up the buffer for trashing the bytes to set the position of
167            // the
168            // stream, only need a buffer when we have a long column
169            buf = new byte[BLOB_BUF_SIZE];
170        }
171        pos = 0;
172    }
173 
174 
175    /*
176        Sets the position of the stream to position newPos, where position 0 is
177        the beginning of the stream.
178 
179        @param newPos the position to set to
180        @exception StandardException (BLOB_SETPOSITION_FAILED) throws this if
181        the stream runs out before we get to newPos
182    */
183    private void setPosition(long newPos)
184        throws StandardException, IOException
185    {
186        if (SanityManager.DEBUG)
187            SanityManager.ASSERT(newPos >= 0);
188        if (isBytes)
189            pos = newPos;
190        else
191        {
192            // Always resets the stream to the beginning first, because user can
193            // influence the state of the stream without letting us know.
194            ((Resetable)myStream).resetStream();
195            // PT could try to save creating a new object each time
196            biStream = new BinaryToRawStream(myStream, this);
197            pos = 0;
198            while (pos < newPos)
199            {
200                int size = biStream.read(
201                    buf,0,(int) Math.min((newPos-pos), (long) BLOB_BUF_SIZE));
202                if (size <= 0)   // ran out of stream
203                    throw StandardException.newException(SQLState.BLOB_LENGTH_TOO_LONG);
204                pos += size;
205            }
206        }
207    }
208 
209 
210    /*
211        Reads one byte, either from the byte array or else from the stream.
212    */
213    private int read()
214        throws IOException
215    {
216        int c;
217        if (isBytes)
218        {
219            if (pos >= myBytes.length)
220                return -1;
221            else
222                c = myBytes[(int) pos];
223        }
224        else
225            c = biStream.read();
226        pos++;
227        return c;
228    }
229 
230  /**
231   * Returns the number of bytes in the <code>BLOB</code> value
232   * designated by this <code>Blob</code> object.
233   * @return length of the <code>BLOB</code> in bytes
234   * @exception SQLException if there is an error accessing the
235   * length of the <code>BLOB</code>
236   */
237    // PT stream part may get pushed to store
238    public long length()
239        throws SQLException
240    {
241        //call checkValidity to exit by throwing a SQLException if
242        //the Blob object has been freed by calling free() on it
243        checkValidity();
244        
245        if (myLength != -1)
246            return myLength;
247        
248        boolean pushStack = false;
249        try
250        {
251           // we have a stream
252            synchronized (getConnectionSynchronization())
253            {
254                pushStack = !getEmbedConnection().isClosed();
255                if (pushStack)
256                    setupContextStack();
257 
258                setPosition(0);
259                // If possible get the length from the encoded
260                // length at the front of the raw stream.
261                if ((myLength = biStream.getLength()) != -1) {
262                    biStream.close();
263                   return myLength;
264                }
265                
266                // Otherwise have to read the entire stream!
267                for (;;)
268                {
269                    int size = biStream.read(buf);
270                    if (size == -1)
271                        break;
272                    pos += size;
273                }
274                // Save for future uses.
275                myLength = pos;
276                biStream.close();
277                return pos;
278            }
279        }
280        catch (Throwable t)
281        {
282                        throw handleMyExceptions(t);
283        }
284        finally
285        {
286            if (pushStack)
287                restoreContextStack();
288        }
289    }
290 
291 
292  /**
293   * Returns as an array of bytes part or all of the <code>BLOB</code>
294   * value that this <code>Blob</code> object designates.  The byte
295   * array contains up to <code>length</code> consecutive bytes
296   * starting at position <code>pos</code>.
297   * @param startPos the ordinal position of the first byte in the
298   * <code>BLOB</code> value to be extracted; the first byte is at
299   * position 1
300   * @param length is the number of consecutive bytes to be copied
301   * @return a byte array containing up to <code>length</code>
302   * consecutive bytes from the <code>BLOB</code> value designated
303   * by this <code>Blob</code> object, starting with the
304   * byte at position <code>pos</code>.
305   * @exception SQLException if there is an error accessing the
306   * <code>BLOB</code>
307   NOTE: return new byte[0] if startPos is too large
308   */
309   // PT stream part may get pushed to store
310 
311    public byte[] getBytes(long startPos, int length)
312        throws SQLException
313    {
314        //call checkValidity to exit by throwing a SQLException if
315        //the Blob object has been freed by calling free() on it
316        checkValidity();
317        
318        boolean pushStack = false;
319        try
320        {
321            if (startPos < 1)
322                throw StandardException.newException(
323                    SQLState.BLOB_BAD_POSITION, new Long(startPos));
324            if (length <= 0)
325                throw StandardException.newException(
326                    SQLState.BLOB_NONPOSITIVE_LENGTH, new Integer(length));
327 
328            byte[] result;
329            // if we have a byte array, not a stream
330            if (isBytes)
331            {
332                // if blob length is less than pos bytes, raise an exception
333                if (myBytes.length < startPos)
334                    throw StandardException.newException(
335                        SQLState.BLOB_POSITION_TOO_LARGE, new Long(startPos));
336                // cannot go over length of array
337                int lengthFromPos = myBytes.length - (int) startPos + 1;
338                int actualLength = length > lengthFromPos ? lengthFromPos : length;
339                result = new byte[actualLength];
340                System.arraycopy(myBytes, ((int) startPos) - 1, result, 0, actualLength);
341            }
342            else // we have a stream
343            {
344                synchronized (getConnectionSynchronization())
345                {
346                    pushStack = !getEmbedConnection().isClosed();
347                    if (pushStack)
348                        setupContextStack();
349 
350                    setPosition(startPos-1);
351                    // read length bytes into a string
352                    result = new byte[length];
353                    int n = InputStreamUtil.readLoop(biStream,result,0,length);
354                    pos += n;
355                    /*
356                     According to the spec, if there are only n < length bytes
357                     to return, we should just return these bytes. Rather than
358                     return them in an array of size length, where the trailing
359                     bytes are not initialized, and the user cannot tell how
360                     many bytes were actually returned, we should return an
361                     array of n bytes.
362                     */
363                    if (n < length)
364                    {
365                        byte[] result2 = new byte[n];
366                        System.arraycopy(result,0,result2,0,n);
367                        return result2;
368                    }
369                }
370            }
371            return result;
372        }
373        catch (StandardException e)
374        {  // if this is a setPosition exception then we ran out of Blob
375            if (e.getMessageId().equals(SQLState.BLOB_LENGTH_TOO_LONG))
376                e = StandardException.newException(
377                    SQLState.BLOB_POSITION_TOO_LARGE, new Long(startPos));
378            throw handleMyExceptions(e);
379        }
380        catch (Throwable t)
381        {
382                        throw handleMyExceptions(t);
383        }
384        finally
385        {
386            if (pushStack)
387                restoreContextStack();
388        }
389 
390    }
391 
392 
393  /**
394   * Retrieves the <code>BLOB</code> designated by this
395   * <code>Blob</code> instance as a stream.
396   * @return a stream containing the <code>BLOB</code> data
397   * @exception SQLException if there is an error accessing the
398   * <code>BLOB</code>
399   */
400    public java.io.InputStream getBinaryStream()
401        throws SQLException
402    {
403        //call checkValidity to exit by throwing a SQLException if
404        //the Blob object has been freed by calling free() on it
405        checkValidity();
406        
407        boolean pushStack = false;
408        try
409        {
410            // if we have byte array, not a stream
411            if (isBytes)
412            {
413                return new NewByteArrayInputStream(myBytes);
414            }
415            else
416            { 
417                // have a stream
418 
419                synchronized (getConnectionSynchronization())
420                {
421                    pushStack = !getEmbedConnection().isClosed();
422                    if (pushStack)
423                        setupContextStack();
424 
425                    setPosition(0);
426                    return biStream;
427                }
428            }
429        }
430        catch (Throwable t)
431        {
432                        throw handleMyExceptions(t);
433        }
434        finally
435        {
436            if (pushStack)
437                restoreContextStack();
438        }
439    }
440 
441 
442  /**
443   * Determines the byte position at which the specified byte
444   * <code>pattern</code> begins within the <code>BLOB</code>
445   * value that this <code>Blob</code> object represents.  The
446   * search for <code>pattern</code. begins at position
447   * <code>start</code>
448   * @param pattern the byte array for which to search
449   * @param start the position at which to begin searching; the
450   *        first position is 1
451   * @return the position at which the pattern appears, else -1.
452   * @exception SQLException if there is an error accessing the
453   * <code>BLOB</code>
454   */
455    public long position(byte[] pattern, long start)
456        throws SQLException
457    {
458        //call checkValidity to exit by throwing a SQLException if
459        //the Blob object has been freed by calling free() on it
460        checkValidity();
461        
462        boolean pushStack = false;
463        try
464        {
465            if (start < 1)
466                throw StandardException.newException(
467                    SQLState.BLOB_BAD_POSITION, new Long(start));
468            if (pattern == null)
469                throw StandardException.newException(SQLState.BLOB_NULL_PATTERN_OR_SEARCH_STR);
470            if (pattern.length == 0)
471                return start; // match DB2's SQL LOCATE function
472 
473            synchronized (getConnectionSynchronization())
474            {
475                pushStack = !getEmbedConnection().isClosed();
476                if (pushStack)
477                    setupContextStack();
478 
479                setPosition(start-1);
480                // look for first character
481                int lookFor = pattern[0];
482                long curPos;
483                int c;
484                while (true)
485                {
486                    c = read();
487                    if (c == -1)  // run out of stream
488                        return -1;
489                    if (c == lookFor)
490                    {
491                        curPos = pos;
492                        if (checkMatch(pattern))
493                            return curPos;
494                        else
495                            setPosition(curPos);
496                    }
497                }
498            }
499        }
500        catch (StandardException e)
501        {  // if this is a setPosition exception then not found
502            if (e.getMessageId().equals(SQLState.BLOB_LENGTH_TOO_LONG))
503                return -1;
504            else
505                throw handleMyExceptions(e);
506        }
507        catch (Throwable t)
508        {
509                        throw handleMyExceptions(t);
510        }
511        finally
512        {
513            if (pushStack)
514                restoreContextStack();
515        }
516 
517    }
518 
519 
520    /*
521     check whether pattern (starting from the second byte) appears inside
522     posStream (at the current position)
523     @param posStream the stream to search inside
524     @param pattern the byte array passed in by the user to search with
525     @return true if match, false otherwise
526     */
527    private boolean checkMatch(byte[] pattern)
528        throws IOException
529    {
530       // check whether rest matches
531       // might improve performance by reading more
532        for (int i = 1; i < pattern.length; i++)
533        {
534            int b = read();
535            if ((b < 0) || (b != pattern[i]))  // mismatch or stream runs out
536                return false;
537        }
538        return true;
539    }
540 
541  /**
542   * Determines the byte position in the <code>BLOB</code> value
543   * designated by this <code>Blob</code> object at which
544   * <code>pattern</code> begins.  The search begins at position
545   * <code>start</code>.
546   * @param pattern the <code>Blob</code> object designating
547   * the <code>BLOB</code> value for which to search
548   * @param start the position in the <code>BLOB</code> value
549   *        at which to begin searching; the first position is 1
550   * @return the position at which the pattern begins, else -1
551   * @exception SQLException if there is an error accessing the
552   * <code>BLOB</code>
553   */
554    public long position(Blob pattern, long start)
555        throws SQLException
556    {
557        //call checkValidity to exit by throwing a SQLException if
558        //the Blob object has been freed by calling free() on it
559        checkValidity();
560        
561        boolean pushStack = false;
562        try
563        {
564            if (start < 1)
565                throw StandardException.newException(
566                    SQLState.BLOB_BAD_POSITION, new Long(start));
567            if (pattern == null)
568                throw StandardException.newException(SQLState.BLOB_NULL_PATTERN_OR_SEARCH_STR);
569            synchronized (getConnectionSynchronization())
570            {
571                pushStack = !getEmbedConnection().isClosed();
572                if (pushStack)
573                    setupContextStack();
574 
575                setPosition(start-1);
576                // look for first character
577                byte[] b;
578                try
579                { // pattern is not necessarily a cloudscape Blob
580                    b = pattern.getBytes(1,1);
581                }
582                catch (SQLException e)
583                {
584                    throw StandardException.newException(SQLState.BLOB_UNABLE_TO_READ_PATTERN);
585                }
586                if (b == null || b.length < 1)  // the 'empty' blob
587                    return start; // match DB2's SQL LOCATE function
588                int lookFor = b[0];
589                int c;
590                long curPos;
591                while (true)
592                {
593                    c = read();
594                    if (c == -1)  // run out of stream
595                        return -1;
596                    if (c == lookFor)
597                    {
598                        curPos = pos;
599                        if (checkMatch(pattern))
600                            return curPos;
601                        else
602                            setPosition(curPos);
603                    }
604                }
605            }
606        }
607        catch (StandardException e)
608        {  // if this is a setPosition exception then not found
609            if (e.getMessageId().equals(SQLState.BLOB_LENGTH_TOO_LONG))
610                return -1;
611            else
612                throw handleMyExceptions(e);
613        }
614        catch (Throwable t)
615        {
616                        throw handleMyExceptions(t);
617        }
618        finally
619        {
620            if (pushStack)
621                restoreContextStack();
622        }
623 
624    }
625 
626 
627    /*
628     check whether pattern (starting from the second byte) appears inside
629     posStream (at the current position)
630     @param posStream the stream to search inside
631     @param pattern the blob passed in by the user to search with
632     @return true if match, false otherwise
633     */
634    private boolean checkMatch(Blob pattern)
635        throws IOException
636    {
637        // check whether rest matches
638        // might improve performance by reading buffer at a time
639        InputStream pStream;
640        try
641        {
642            pStream = pattern.getBinaryStream();
643        }
644        catch (SQLException e)
645        {
646            return false;
647        }
648        if (pStream == null)
649            return false;
650        // throw away first character since we already read it in the calling
651        // method
652        int b1 = pStream.read();
653        if (b1 < 0)
654            return false;
655        while (true)
656        {
657            b1 = pStream.read();
658            if (b1 < 0)  // search blob runs out
659                return true;
660            int b2 = read();
661            if ((b1 != b2) || (b2 < 0))  // mismatch or stream runs out
662                return false;
663        }
664    }
665 
666    /*
667      Convert exceptions where needed before calling handleException to convert
668      them to SQLExceptions.
669    */
670        private SQLException handleMyExceptions(Throwable t)
671        throws SQLException
672    {
673        if (t instanceof StandardException)
674        {
675            // container closed means the blob or clob was accessed after commit
676            if (((StandardException) t).getMessageId().equals(SQLState.DATA_CONTAINER_CLOSED))
677            {
678                t = StandardException.newException(SQLState.BLOB_ACCESSED_AFTER_COMMIT);
679            }
680        }
681        return handleException(t);
682        }
683 
684 
685   /*
686    If we have a stream, release the resources associated with it.
687    */
688    protected void finalize()
689    {
690        if (!isBytes)
691            ((Resetable)myStream).closeStream();
692    }
693 
694        /**
695    Following methods are for the new JDBC 3.0 methods in java.sql.Blob
696    (see the JDBC 3.0 spec). We have the JDBC 3.0 methods in Local20
697    package, so we don't have to have a new class in Local30.
698    The new JDBC 3.0 methods don't make use of any new JDBC3.0 classes and
699    so this will work fine in jdbc2.0 configuration.
700        */
701 
702        /////////////////////////////////////////////////////////////////////////
703        //
704        //        JDBC 3.0        -        New public methods
705        //
706        /////////////////////////////////////////////////////////////////////////
707 
708        /**
709    * JDBC 3.0
710    *
711    * Writes the given array of bytes to the BLOB value that this Blob object
712    * represents, starting at position pos, and returns the number of bytes written.
713    *
714    * @param pos - the position in the BLOB object at which to start writing
715    * @param bytes - the array of bytes to be written to the BLOB value that this
716    * Blob object represents
717    * @return the number of bytes written
718    * @exception SQLException Feature not implemented for now.
719        */
720        public int setBytes(long pos,
721                                        byte[] bytes)
722    throws SQLException
723        {
724                throw Util.notImplemented();
725        }
726 
727        /**
728    * JDBC 3.0
729    *
730    * Writes all or part of the given array of byte array to the BLOB value that
731    * this Blob object represents and returns the number of bytes written.
732    * Writing starts at position pos in the BLOB value; len bytes from the given
733    * byte array are written.
734    *
735    * @param pos - the position in the BLOB object at which to start writing
736    * @param bytes - the array of bytes to be written to the BLOB value that this
737    * Blob object represents
738    * @param offset - the offset into the array bytes at which to start reading
739    * the bytes to be set
740    * @param len - the number of bytes to be written to the BLOB value from the
741    * array of bytes bytes
742    * @return the number of bytes written
743    * @exception SQLException Feature not implemented for now.
744        */
745        public int setBytes(long pos,
746                                        byte[] bytes, int offset,
747                                        int len)
748    throws SQLException
749        {
750                throw Util.notImplemented();
751        }
752 
753        /**
754    * JDBC 3.0
755    *
756    * Retrieves a stream that can be used to write to the BLOB value that this
757    * Blob object represents. The stream begins at position pos. 
758    *
759    * @param pos - the position in the BLOB object at which to start writing
760    * @return a java.io.OutputStream object to which data can be written 
761    * @exception SQLException Feature not implemented for now.
762        */
763        public java.io.OutputStream setBinaryStream(long pos)
764    throws SQLException
765        {
766                throw Util.notImplemented();
767        }
768 
769        /**
770    * JDBC 3.0
771    *
772    * Truncates the BLOB value that this Blob object represents to be len bytes
773    * in length.
774    *
775    * @param len - the length, in bytes, to which the BLOB value that this Blob
776    * object represents should be truncated
777    * @exception SQLException Feature not implemented for now.
778        */
779        public void truncate(long len)
780    throws SQLException
781        {
782                throw Util.notImplemented();
783        }
784 
785    /////////////////////////////////////////////////////////////////////////
786    //
787    //        JDBC 4.0        -        New public methods
788    //
789    /////////////////////////////////////////////////////////////////////////
790    /**
791     * This method frees the <code>Blob</code> object and releases the resources that 
792     * it holds. The object is invalid once the <code>free</code>
793     * method is called. If <code>free</code> is called multiple times, the subsequent
794     * calls to <code>free</code> are treated as a no-op.
795     * 
796     * @throws SQLException if an error occurs releasing
797     * the Blob's resources
798     */
799    public void free()
800        throws SQLException {
801        //calling free() on a already freed object is treated as a no-op
802        if (!isValid) return;
803        
804        //now that free has been called the Blob object is no longer
805        //valid
806        isValid = false;
807        
808        //initialialize length to default value -1
809        myLength = -1;
810        
811        //if it is a stream then close it.
812        //if a array of bytes then initialize it to null
813        //to free up space
814        if (!isBytes)
815            ((Resetable)myStream).closeStream();
816        else
817            myBytes = null;
818    }
819    
820    /**
821     * Returns an <code>InputStream</code> object that contains a partial 
822     * <code>Blob</code> value, starting with the byte specified by pos, 
823     * which is length bytes in length.
824     *
825     * @param pos the offset to the first byte of the partial value to be 
826     *      retrieved. The first byte in the <code>Blob</code> is at 
827     *      position 1
828     * @param length the length in bytes of the partial value to be retrieved
829     * @return through which the partial <code>Blob</code> value can be read. 
830     * @throws SQLException if pos is less than 1 or if pos is greater than 
831     *      the number of bytes in the <code>Blob</code> or if pos + length is
832     *      greater than the number of bytes in the <code>Blob</code>
833     */
834    public InputStream getBinaryStream(long pos, long length)
835        throws SQLException {
836        throw Util.notImplemented();
837    }
838    
839    /*
840     * Checks is isValid is true. If it is not true throws 
841     * a SQLException stating that a method has been called on
842     * an invalid LOB object
843     *
844     * throws SQLException if isvalid is not true.
845     */
846    private void checkValidity() throws SQLException{
847        if(!isValid)
848            throw newSQLException(SQLState.LOB_OBJECT_INVALID);
849    }
850}

[all classes][org.apache.derby.impl.jdbc]
EMMA 2.0.5312 (C) Vladimir Roubtsov