EMMA Coverage Report (generated Sun Mar 01 22:06:14 CET 2015)
[all classes][org.h2.jdbc]

COVERAGE SUMMARY FOR SOURCE FILE [JdbcBlob.java]

nameclass, %method, %block, %line, %
JdbcBlob.java100% (3/3)100% (18/18)86%  (320/374)80%  (63.8/80)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class JdbcBlob$2100% (1/1)100% (2/2)82%  (18/22)71%  (5/7)
close (): void 100% (1/1)67%  (8/12)67%  (4/6)
JdbcBlob$2 (JdbcBlob, PipedInputStream, Task): void 100% (1/1)100% (10/10)100% (1/1)
     
class JdbcBlob100% (1/1)100% (14/14)85%  (280/330)80%  (57.8/72)
getBinaryStream (): InputStream 100% (1/1)64%  (9/14)60%  (3/5)
checkClosed (): void 100% (1/1)70%  (7/10)75%  (3/4)
setBinaryStream (long): OutputStream 100% (1/1)77%  (56/73)73%  (11/15)
setBytes (long, byte []): int 100% (1/1)80%  (39/49)67%  (6/9)
getBytes (long, int): byte [] 100% (1/1)82%  (46/56)82%  (9.8/12)
length (): long 100% (1/1)84%  (26/31)78%  (7/9)
JdbcBlob (JdbcConnection, Value, int): void 100% (1/1)100% (16/16)100% (5/5)
free (): void 100% (1/1)100% (7/7)100% (3/3)
getBinaryStream (long, long): InputStream 100% (1/1)100% (4/4)100% (1/1)
position (Blob, long): long 100% (1/1)100% (19/19)100% (3/3)
position (byte [], long): long 100% (1/1)100% (24/24)100% (3/3)
setBytes (long, byte [], int, int): int 100% (1/1)100% (4/4)100% (1/1)
toString (): String 100% (1/1)100% (19/19)100% (1/1)
truncate (long): void 100% (1/1)100% (4/4)100% (1/1)
     
class JdbcBlob$1100% (1/1)100% (2/2)100% (22/22)100% (3/3)
JdbcBlob$1 (JdbcBlob, JdbcConnection, PipedInputStream): void 100% (1/1)100% (12/12)100% (1/1)
call (): void 100% (1/1)100% (10/10)100% (2/2)

1/*
2 * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
3 * and the EPL 1.0 (http://h2database.com/html/license.html).
4 * Initial Developer: H2 Group
5 */
6package org.h2.jdbc;
7 
8import java.io.BufferedInputStream;
9import java.io.BufferedOutputStream;
10import java.io.ByteArrayInputStream;
11import java.io.ByteArrayOutputStream;
12import java.io.IOException;
13import java.io.InputStream;
14import java.io.OutputStream;
15import java.io.PipedInputStream;
16import java.io.PipedOutputStream;
17import java.sql.Blob;
18import java.sql.SQLException;
19 
20import org.h2.api.ErrorCode;
21import org.h2.engine.Constants;
22import org.h2.message.DbException;
23import org.h2.message.TraceObject;
24import org.h2.util.Task;
25import org.h2.util.IOUtils;
26import org.h2.value.Value;
27 
28/**
29 * Represents a BLOB value.
30 */
31public class JdbcBlob extends TraceObject implements Blob {
32 
33    Value value;
34    private final JdbcConnection conn;
35 
36    /**
37     * INTERNAL
38     */
39    public JdbcBlob(JdbcConnection conn, Value value, int id) {
40        setTrace(conn.getSession().getTrace(), TraceObject.BLOB, id);
41        this.conn = conn;
42        this.value = value;
43    }
44 
45    /**
46     * Returns the length.
47     *
48     * @return the length
49     */
50    @Override
51    public long length() throws SQLException {
52        try {
53            debugCodeCall("length");
54            checkClosed();
55            if (value.getType() == Value.BLOB) {
56                long precision = value.getPrecision();
57                if (precision > 0) {
58                    return precision;
59                }
60            }
61            return IOUtils.copyAndCloseInput(value.getInputStream(), null);
62        } catch (Exception e) {
63            throw logAndConvert(e);
64        }
65    }
66 
67    /**
68     * [Not supported] Truncates the object.
69     *
70     * @param len the new length
71     */
72    @Override
73    public void truncate(long len) throws SQLException {
74        throw unsupported("LOB update");
75    }
76 
77    /**
78     * Returns some bytes of the object.
79     *
80     * @param pos the index, the first byte is at position 1
81     * @param length the number of bytes
82     * @return the bytes, at most length bytes
83     */
84    @Override
85    public byte[] getBytes(long pos, int length) throws SQLException {
86        try {
87            if (isDebugEnabled()) {
88                debugCode("getBytes("+pos+", "+length+");");
89            }
90            checkClosed();
91            ByteArrayOutputStream out = new ByteArrayOutputStream();
92            InputStream in = value.getInputStream();
93            try {
94                IOUtils.skipFully(in, pos - 1);
95                IOUtils.copy(in, out, length);
96            } finally {
97                in.close();
98            }
99            return out.toByteArray();
100        } catch (Exception e) {
101            throw logAndConvert(e);
102        }
103    }
104 
105    /**
106     * Fills the Blob. This is only supported for new, empty Blob objects that
107     * were created with Connection.createBlob(). The position
108     * must be 1, meaning the whole Blob data is set.
109     *
110     * @param pos where to start writing (the first byte is at position 1)
111     * @param bytes the bytes to set
112     * @return the length of the added data
113     */
114    @Override
115    public int setBytes(long pos, byte[] bytes) throws SQLException {
116        try {
117            if (isDebugEnabled()) {
118                debugCode("setBytes("+pos+", "+quoteBytes(bytes)+");");
119            }
120            checkClosed();
121            if (pos != 1) {
122                throw DbException.getInvalidValueException("pos", pos);
123            }
124            value = conn.createBlob(new ByteArrayInputStream(bytes), -1);
125            return bytes.length;
126        } catch (Exception e) {
127            throw logAndConvert(e);
128        }
129    }
130 
131    /**
132     * [Not supported] Sets some bytes of the object.
133     *
134     * @param pos the write position
135     * @param bytes the bytes to set
136     * @param offset the bytes offset
137     * @param len the number of bytes to write
138     * @return how many bytes have been written
139     */
140    @Override
141    public int setBytes(long pos, byte[] bytes, int offset, int len)
142            throws SQLException {
143        throw unsupported("LOB update");
144    }
145 
146    /**
147     * Returns the input stream.
148     *
149     * @return the input stream
150     */
151    @Override
152    public InputStream getBinaryStream() throws SQLException {
153        try {
154            debugCodeCall("getBinaryStream");
155            checkClosed();
156            return value.getInputStream();
157        } catch (Exception e) {
158            throw logAndConvert(e);
159        }
160    }
161 
162    /**
163     * Get a writer to update the Blob. This is only supported for new, empty
164     * Blob objects that were created with Connection.createBlob(). The Blob is
165     * created in a separate thread, and the object is only updated when
166     * OutputStream.close() is called. The position must be 1, meaning the whole
167     * Blob data is set.
168     *
169     * @param pos where to start writing (the first byte is at position 1)
170     * @return an output stream
171     */
172    @Override
173    public OutputStream setBinaryStream(long pos) throws SQLException {
174        try {
175            if (isDebugEnabled()) {
176                debugCode("setBinaryStream("+pos+");");
177            }
178            checkClosed();
179            if (pos != 1) {
180                throw DbException.getInvalidValueException("pos", pos);
181            }
182            if (value.getPrecision() != 0) {
183                throw DbException.getInvalidValueException("length", value.getPrecision());
184            }
185            final JdbcConnection c = conn;
186            final PipedInputStream in = new PipedInputStream();
187            final Task task = new Task() {
188                @Override
189                public void call() {
190                    value = c.createBlob(in, -1);
191                }
192            };
193            PipedOutputStream out = new PipedOutputStream(in) {
194                @Override
195                public void close() throws IOException {
196                    super.close();
197                    try {
198                        task.get();
199                    } catch (Exception e) {
200                        throw DbException.convertToIOException(e);
201                    }
202                }
203            };
204            task.execute();
205            return new BufferedOutputStream(out);
206        } catch (Exception e) {
207            throw logAndConvert(e);
208        }
209    }
210 
211    /**
212     * [Not supported] Searches a pattern and return the position.
213     *
214     * @param pattern the pattern to search
215     * @param start the index, the first byte is at position 1
216     * @return the position (first byte is at position 1), or -1 for not found
217     */
218    @Override
219    public long position(byte[] pattern, long start) throws SQLException {
220        if (isDebugEnabled()) {
221            debugCode("position("+quoteBytes(pattern)+", "+start+");");
222        }
223        if (Constants.BLOB_SEARCH) {
224            try {
225                checkClosed();
226                if (pattern == null) {
227                    return -1;
228                }
229                if (pattern.length == 0) {
230                    return 1;
231                }
232                // TODO performance: blob pattern search is slow
233                BufferedInputStream in = new BufferedInputStream(value.getInputStream());
234                IOUtils.skipFully(in, start - 1);
235                int pos = 0;
236                int patternPos = 0;
237                while (true) {
238                    int x = in.read();
239                    if (x < 0) {
240                        break;
241                    }
242                    if (x == (pattern[patternPos] & 0xff)) {
243                        if (patternPos == 0) {
244                            in.mark(pattern.length);
245                        }
246                        if (patternPos == pattern.length) {
247                            return pos - patternPos;
248                        }
249                        patternPos++;
250                    } else {
251                        if (patternPos > 0) {
252                            in.reset();
253                            pos -= patternPos;
254                        }
255                    }
256                    pos++;
257                }
258                return -1;
259            } catch (Exception e) {
260                throw logAndConvert(e);
261            }
262        }
263        throw unsupported("LOB search");
264    }
265 
266    /**
267     * [Not supported] Searches a pattern and return the position.
268     *
269     * @param blobPattern the pattern to search
270     * @param start the index, the first byte is at position 1
271     * @return the position (first byte is at position 1), or -1 for not found
272     */
273    @Override
274    public long position(Blob blobPattern, long start) throws SQLException {
275        if (isDebugEnabled()) {
276            debugCode("position(blobPattern, "+start+");");
277        }
278        if (Constants.BLOB_SEARCH) {
279            try {
280                checkClosed();
281                if (blobPattern == null) {
282                    return -1;
283                }
284                ByteArrayOutputStream out = new ByteArrayOutputStream();
285                InputStream in = blobPattern.getBinaryStream();
286                while (true) {
287                    int x = in.read();
288                    if (x < 0) {
289                        break;
290                    }
291                    out.write(x);
292                }
293                return position(out.toByteArray(), start);
294            } catch (Exception e) {
295                throw logAndConvert(e);
296            }
297        }
298        throw unsupported("LOB subset");
299    }
300 
301    /**
302     * Release all resources of this object.
303     */
304    @Override
305    public void free() {
306        debugCodeCall("free");
307        value = null;
308    }
309 
310    /**
311     * [Not supported] Returns the input stream, starting from an offset.
312     *
313     * @param pos where to start reading
314     * @param length the number of bytes that will be read
315     * @return the input stream to read
316     */
317    @Override
318    public InputStream getBinaryStream(long pos, long length) throws SQLException {
319        throw unsupported("LOB update");
320    }
321 
322    private void checkClosed() {
323        conn.checkClosed();
324        if (value == null) {
325            throw DbException.get(ErrorCode.OBJECT_CLOSED);
326        }
327    }
328 
329    /**
330     * INTERNAL
331     */
332    @Override
333    public String toString() {
334        return getTraceObjectName() + ": " +
335                (value == null ? "null" : value.getTraceSQL());
336    }
337 
338}

[all classes][org.h2.jdbc]
EMMA 2.0.5312 (C) Vladimir Roubtsov