comparison src/main/java/nl/cwi/monetdb/jdbc/MonetBlob.java @ 0:a5a898f6886c

Copy of MonetDB java directory changeset e6e32756ad31.
author Sjoerd Mullender <sjoerd@acm.org>
date Wed, 21 Sep 2016 09:34:48 +0200 (2016-09-21)
parents
children 7e0d71a22677 e092fa8d9ab7
comparison
equal deleted inserted replaced
-1:000000000000 0:a5a898f6886c
1 /*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2016 MonetDB B.V.
7 */
8
9 package nl.cwi.monetdb.jdbc;
10
11 import java.sql.*;
12 import java.util.Arrays;
13 import java.io.*;
14
15 /**
16 * The MonetBlob class implements the {@link java.sql.Blob} interface. Because
17 * MonetDB/SQL currently has no support for streams, this class is a
18 * shallow wrapper of a byte[]. It is more or less supplied to
19 * enable an application that depends on it to run. It may be obvious
20 * that it is a real resource expensive workaround that contradicts the
21 * benefits for a Blob: avoidance of huge resource consumption.
22 *
23 * @author Fabian Groffen
24 */
25 public class MonetBlob implements Blob {
26 private byte[] buf;
27
28 protected MonetBlob(byte[] data) {
29 buf = data;
30 }
31
32 static MonetBlob create(String in) {
33 int len = in.length() / 2;
34 byte[] buf = new byte[len];
35 for (int i = 0; i < len; i++)
36 buf[i] = (byte)Integer.parseInt(in.substring(2 * i, (2 * i) + 2), 16);
37 return new MonetBlob(buf);
38 }
39
40
41 //== begin interface Blob
42
43 /**
44 * This method frees the Blob object and releases the resources that
45 * it holds. The object is invalid once the free method is called.
46 *
47 * After free has been called, any attempt to invoke a method other
48 * than free will result in a SQLException being thrown. If free is
49 * called multiple times, the subsequent calls to free are treated
50 * as a no-op.
51 *
52 * @throws SQLException if an error occurs releasing the Blob's
53 * resources
54 * @throws SQLFeatureNotSupportedException - if the JDBC driver does
55 * not support this method
56 */
57 @Override
58 public void free() throws SQLException {
59 buf = null;
60 }
61
62 /**
63 * Retrieves the BLOB value designated by this Blob instance as a
64 * stream.
65 *
66 * @return a stream containing the BLOB data
67 * @throws SQLException if there is an error accessing the BLOB value
68 * @throws SQLFeatureNotSupportedException if the JDBC driver does
69 * not support this method
70 */
71 @Override
72 public InputStream getBinaryStream() throws SQLException {
73 if (buf == null)
74 throw new SQLException("This Blob object has been freed", "M1M20");
75 return new ByteArrayInputStream(buf);
76 }
77
78 /**
79 * Returns an InputStream object that contains a partial Blob value,
80 * starting with the byte specified by pos, which is length bytes in
81 * length.
82 *
83 * @param pos the offset to the first byte of the partial value to
84 * be retrieved. The first byte in the Blob is at position 1
85 * @param length the length in bytes of the partial value to be
86 * retrieved
87 * @return InputStream through which the partial Blob value can be
88 * read.
89 * @throws SQLException if pos is less than 1 or if pos is
90 * greater than the number of bytes in the Blob or if pos +
91 * length is greater than the number of bytes in the Blob
92 * @throws SQLFeatureNotSupportedException if the JDBC driver does
93 * not support this method
94 */
95 @Override
96 public InputStream getBinaryStream(long pos, long length)
97 throws SQLException
98 {
99 if (buf == null)
100 throw new SQLException("This Blob object has been freed", "M1M20");
101 if (pos < 1)
102 throw new SQLException("pos is less than 1", "M1M05");
103 if (pos - 1 > buf.length)
104 throw new SQLException("pos is greater than the number of bytes in the Blob", "M1M05");
105 if (pos - 1 + length > buf.length)
106 throw new SQLException("pos + length is greater than the number of bytes in the Blob", "M1M05");
107 return new ByteArrayInputStream(buf, (int)(pos - 1), (int)length);
108 }
109
110 /**
111 * Retrieves all or part of the BLOB value that this Blob object
112 * represents, as an array of bytes. This byte array contains up to
113 * length consecutive bytes starting at position pos.
114 *
115 * @param pos the ordinal position of the first byte in the BLOB
116 * value to be extracted; the first byte is at position 1.
117 * @param length the number of consecutive bytes to be copied
118 * @return a byte array containing up to length consecutive bytes
119 * from the BLOB value designated by this Blob object,
120 * starting with the byte at position pos.
121 * @throws SQLException if there is an error accessing the
122 * BLOB value
123 */
124 @Override
125 public byte[] getBytes(long pos, int length) throws SQLException {
126 if (buf == null)
127 throw new SQLException("This Blob object has been freed", "M1M20");
128 try {
129 return Arrays.copyOfRange(buf, (int) pos - 1, (int) pos - 1 + length);
130 } catch (IndexOutOfBoundsException e) {
131 throw new SQLException(e.getMessage(), "M0M10");
132 }
133 }
134
135 /**
136 * Returns the number of bytes in the BLOB value designated by this
137 * Blob object.
138 *
139 * @return length of the BLOB in bytes
140 * @throws SQLException if there is an error accessing the length
141 * of the BLOB value
142 */
143 @Override
144 public long length() throws SQLException {
145 if (buf == null)
146 throw new SQLException("This Blob object has been freed", "M1M20");
147 return (long)buf.length;
148 }
149
150 /**
151 * Retrieves the byte position in the BLOB value designated by this
152 * Blob object at which pattern begins. The search begins at
153 * position start.
154 *
155 * @param pattern the Blob object designating the BLOB value for
156 * which to search
157 * @param start the position in the BLOB value at which to begin
158 * searching; the first position is 1
159 * @return the position at which the pattern begins, else -1
160 * @throws SQLException if there is an error accessing the
161 * BLOB value
162 */
163 @Override
164 public long position(Blob pattern, long start) throws SQLException {
165 return position(pattern.getBytes(1L, (int)pattern.length()), start);
166 }
167
168 /**
169 * Retrieves the byte position at which the specified byte array
170 * pattern begins within the BLOB value that this Blob object
171 * represents. The search for pattern begins at position start.
172 *
173 * @param pattern the byte array for which to search
174 * @param start the position at which to begin searching;
175 * the first position is 1
176 * @return the position at which the pattern appears, else -1
177 * @throws SQLException if there is an error accessing the
178 * BLOB value
179 */
180 @Override
181 public long position(byte[] pattern, long start) throws SQLException {
182 if (buf == null)
183 throw new SQLException("This Blob object has been freed", "M1M20");
184 try {
185 for (int i = (int)(start - 1); i < buf.length - pattern.length; i++) {
186 int j;
187 for (j = 0; j < pattern.length; j++) {
188 if (buf[i + j] != pattern[j])
189 break;
190 }
191 if (j == pattern.length)
192 return i;
193 }
194 } catch (IndexOutOfBoundsException e) {
195 throw new SQLException(e.getMessage(), "M0M10");
196 }
197 return -1;
198 }
199
200 /**
201 * Retrieves a stream that can be used to write to the BLOB value
202 * that this Blob object represents. The stream begins at position
203 * pos. The bytes written to the stream will overwrite the existing
204 * bytes in the Blob object starting at the position pos. If the end
205 * of the Blob value is reached while writing to the stream, then
206 * the length of the Blob value will be increased to accomodate the
207 * extra bytes.
208 *
209 * @param pos the position in the BLOB value at which to start
210 * writing; the first position is 1
211 * @return a java.io.OutputStream object to which data can be
212 * written
213 * @throws SQLException if there is an error accessing the BLOB
214 * value or if pos is less than 1
215 * @throws SQLFeatureNotSupportedException if the JDBC driver does
216 * not support this method
217 */
218 @Override
219 public OutputStream setBinaryStream(long pos) throws SQLException {
220 if (buf == null)
221 throw new SQLException("This Blob object has been freed", "M1M20");
222 if (pos < 1)
223 throw new SQLException("pos is less than 1", "M1M05");
224 throw new SQLFeatureNotSupportedException("Operation setBinaryStream(long pos) currently not supported", "0A000");
225 }
226
227 /**
228 * Writes the given array of bytes to the BLOB value that this Blob
229 * object represents, starting at position pos, and returns the
230 * number of bytes written.
231 *
232 * @param pos the position in the BLOB object at which to start
233 * writing
234 * @param bytes the array of bytes to be written to the BLOB value
235 * that this Blob object represents
236 * @return the number of bytes written
237 * @throws SQLException if there is an error accessing the
238 * BLOB value
239 */
240 @Override
241 public int setBytes(long pos, byte[] bytes) throws SQLException {
242 return setBytes(pos, bytes, 1, bytes.length);
243 }
244
245 /**
246 * Writes all or part of the given byte array to the BLOB value that
247 * this Blob object represents and returns the number of bytes
248 * written. Writing starts at position pos in the BLOB value; len
249 * bytes from the given byte array are written.
250 *
251 * @param pos the position in the BLOB object at which to start
252 * writing
253 * @param bytes the array of bytes to be written to this BLOB
254 * object
255 * @param offset the offset into the array bytes at which to start
256 * reading the bytes to be set
257 * @param len the number of bytes to be written to the BLOB value
258 * from the array of bytes bytes
259 * @return the number of bytes written
260 * @throws SQLException if there is an error accessing the
261 * BLOB value
262 */
263 @Override
264 public int setBytes(long pos, byte[] bytes, int offset, int len)
265 throws SQLException
266 {
267 if (buf == null)
268 throw new SQLException("This Blob object has been freed", "M1M20");
269 try {
270 /* transactions? what are you talking about? */
271 for (int i = (int)pos; i < len; i++)
272 buf[i] = bytes[offset - 1 + i];
273 } catch (IndexOutOfBoundsException e) {
274 throw new SQLException(e.getMessage(), "M0M10");
275 }
276 return len;
277 }
278
279 /**
280 * Truncates the BLOB value that this Blob object represents to be
281 * len bytes in length.
282 *
283 * @param len the length, in bytes, to which the BLOB value
284 * should be truncated
285 * @throws SQLException if there is an error accessing the
286 * BLOB value
287 */
288 @Override
289 public void truncate(long len) throws SQLException {
290 if (buf == null)
291 throw new SQLException("This Blob object has been freed", "M1M20");
292 if (buf.length > len) {
293 byte[] newbuf = new byte[(int)len];
294 for (int i = 0; i < len; i++)
295 newbuf[i] = buf[i];
296 buf = newbuf;
297 }
298 }
299 }