File D:\maven-qcr-plugin-testsunitaires\qcr4java\h2-1.3.170-sources\target\site\qc\lecode\jdbc\JdbcBlob.java.html

1 /*
2 * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
3 * Version 1.0, and under the Eclipse Public License, Version 1.0
4 * (http://h2database.com/html/license.html).
5 * Initial Developer: H2 Group
6 */
7 package org.h2.jdbc;
8
9 import java.io.BufferedInputStream;
10 import java.io.BufferedOutputStream;
11 import java.io.ByteArrayInputStream;
12 import java.io.ByteArrayOutputStream;
13 import java.io.IOException;
14 import java.io.InputStream;
15 import java.io.OutputStream;
16 import java.io.PipedInputStream;
17 import java.io.PipedOutputStream;
18 import java.sql.Blob;
19 import java.sql.SQLException;
20 import org.h2.constant.ErrorCode;
21 import org.h2.engine.Constants;
22 import org.h2.message.DbException;
23 import org.h2.message.TraceObject;
24 import org.h2.util.Task;
25 import org.h2.util.IOUtils;
26 import org.h2.value.Value;
27
28 /**
29 * Represents a BLOB value.
30 */
31 public 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 * @throws SQLException
50 */
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 * @throws SQLException
72 */
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 * @throws SQLException
84 */
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 public int setBytes(long pos, byte[] bytes) throws SQLException {
115 try {
116 if (isDebugEnabled()) {
117 debugCode("setBytes("+pos+", "+quoteBytes(bytes)+");");
118 }
119 checkClosed();
120 if (pos != 1) {
121 throw DbException.getInvalidValueException("pos", pos);
122 }
123 value = conn.createBlob(new ByteArrayInputStream(bytes), -1);
124 return bytes.length;
125 } catch (Exception e) {
126 throw logAndConvert(e);
127 }
128 }
129
130 /**
131 * [Not supported] Sets some bytes of the object.
132 *
133 * @param pos the write position
134 * @param bytes the bytes to set
135 * @param offset the bytes offset
136 * @param len the number of bytes to write
137 * @return how many bytes have been written
138 * @throws SQLException
139 */
140 public int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException {
141 throw unsupported("LOB update");
142 }
143
144 /**
145 * Returns the input stream.
146 *
147 * @return the input stream
148 * @throws SQLException
149 */
150 public InputStream getBinaryStream() throws SQLException {
151 try {
152 debugCodeCall("getBinaryStream");
153 checkClosed();
154 return value.getInputStream();
155 } catch (Exception e) {
156 throw logAndConvert(e);
157 }
158 }
159
160 /**
161 * Get a writer to update the Blob. This is only supported for new, empty
162 * Blob objects that were created with Connection.createBlob(). The Blob is
163 * created in a separate thread, and the object is only updated when
164 * OutputStream.close() is called. The position must be 1, meaning the whole
165 * Blob data is set.
166 *
167 * @param pos where to start writing (the first byte is at position 1)
168 * @return an output stream
169 */
170 public OutputStream setBinaryStream(long pos) throws SQLException {
171 try {
172 if (isDebugEnabled()) {
173 debugCode("setBinaryStream("+pos+");");
174 }
175 checkClosed();
176 if (pos != 1) {
177 throw DbException.getInvalidValueException("pos", pos);
178 }
179 if (value.getPrecision() != 0) {
180 throw DbException.getInvalidValueException("length", value.getPrecision());
181 }
182 final JdbcConnection c = conn;
183 final PipedInputStream in = new PipedInputStream();
184 final Task task = new Task() {
185 public void call() {
186 value = c.createBlob(in, -1);
187 }
188 };
189 PipedOutputStream out = new PipedOutputStream(in) {
190 public void close() throws IOException {
191 super.close();
192 try {
193 task.get();
194 } catch (Exception e) {
195 throw DbException.convertToIOException(e);
196 }
197 }
198 };
199 task.execute();
200 return new BufferedOutputStream(out);
201 } catch (Exception e) {
202 throw logAndConvert(e);
203 }
204 }
205
206 /**
207 * [Not supported] Searches a pattern and return the position.
208 *
209 * @param pattern the pattern to search
210 * @param start the index, the first byte is at position 1
211 * @return the position (first byte is at position 1), or -1 for not found
212 * @throws SQLException
213 */
214 public long position(byte[] pattern, long start) throws SQLException {
215 if (isDebugEnabled()) {
216 debugCode("position("+quoteBytes(pattern)+", "+start+");");
217 }
218 if (Constants.BLOB_SEARCH) {
219 try {
220 checkClosed();
221 if (pattern == null) {
222 return -1;
223 }
224 if (pattern.length == 0) {
225 return 1;
226 }
227 // TODO performance: blob pattern search is slow
228 BufferedInputStream in = new BufferedInputStream(value.getInputStream());
229 IOUtils.skipFully(in, start - 1);
230 int pos = 0;
231 int patternPos = 0;
232 while (true) {
233 int x = in.read();
234 if (x < 0) {
235 break;
236 }
237 if (x == (pattern[patternPos] & 0xff)) {
238 if (patternPos == 0) {
239 in.mark(pattern.length);
240 }
241 if (patternPos == pattern.length) {
242 return pos - patternPos;
243 }
244 patternPos++;
245 } else {
246 if (patternPos > 0) {
247 in.reset();
248 pos -= patternPos;
249 }
250 }
251 pos++;
252 }
253 return -1;
254 } catch (Exception e) {
255 throw logAndConvert(e);
256 }
257 }
258 throw unsupported("LOB search");
259 }
260
261 /**
262 * [Not supported] Searches a pattern and return the position.
263 *
264 * @param blobPattern the pattern to search
265 * @param start the index, the first byte is at position 1
266 * @return the position (first byte is at position 1), or -1 for not found
267 * @throws SQLException
268 */
269 public long position(Blob blobPattern, long start) throws SQLException {
270 if (isDebugEnabled()) {
271 debugCode("position(blobPattern, "+start+");");
272 }
273 if (Constants.BLOB_SEARCH) {
274 try {
275 checkClosed();
276 if (blobPattern == null) {
277 return -1;
278 }
279 ByteArrayOutputStream out = new ByteArrayOutputStream();
280 InputStream in = blobPattern.getBinaryStream();
281 while (true) {
282 int x = in.read();
283 if (x < 0) {
284 break;
285 }
286 out.write(x);
287 }
288 return position(out.toByteArray(), start);
289 } catch (Exception e) {
290 throw logAndConvert(e);
291 }
292 }
293 throw unsupported("LOB subset");
294 }
295
296 /**
297 * Release all resources of this object.
298 */
299 public void free() {
300 debugCodeCall("free");
301 value = null;
302 }
303
304 /**
305 * [Not supported] Returns the input stream, starting from an offset.
306 *
307 * @param pos where to start reading
308 * @param length the number of bytes that will be read
309 * @return the input stream to read
310 * @throws SQLException
311 */
312 public InputStream getBinaryStream(long pos, long length) throws SQLException {
313 throw unsupported("LOB update");
314 }
315
316 private void checkClosed() {
317 conn.checkClosed();
318 if (value == null) {
319 throw DbException.get(ErrorCode.OBJECT_CLOSED);
320 }
321 }
322
323 /**
324 * INTERNAL
325 */
326 public String toString() {
327 return getTraceObjectName() + ": " + (value == null ? "null" : value.getTraceSQL());
328 }
329
330 }
331