Mercurial > hg > monetdb-java
comparison src/main/java/org/monetdb/jdbc/MonetBlob.java @ 391:f523727db392
Moved Java classes from packages starting with nl.cwi.monetdb.* to package org.monetdb.*
This naming complies to the Java Package Naming convention as MonetDB's main website is www.monetdb.org.
author | Martin van Dinther <martin.van.dinther@monetdbsolutions.com> |
---|---|
date | Thu, 12 Nov 2020 22:02:01 +0100 (2020-11-12) |
parents | src/main/java/nl/cwi/monetdb/jdbc/MonetBlob.java@54137aeb1f92 |
children | bf9f6b6ecf40 |
comparison
equal
deleted
inserted
replaced
390:6199e0be3c6e | 391:f523727db392 |
---|---|
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 - 2020 MonetDB B.V. | |
7 */ | |
8 | |
9 package org.monetdb.jdbc; | |
10 | |
11 import java.io.ByteArrayInputStream; | |
12 import java.io.InputStream; | |
13 import java.io.OutputStream; | |
14 import java.sql.Blob; | |
15 import java.sql.SQLException; | |
16 import java.sql.SQLFeatureNotSupportedException; | |
17 | |
18 /** | |
19 * The MonetBlob class implements the {@link java.sql.Blob} interface. | |
20 * | |
21 * Because MonetDB/SQL currently has no support for streams, this class is a | |
22 * shallow wrapper of a byte[]. It is more or less supplied to | |
23 * enable an application that depends on it to run. It may be obvious | |
24 * that it is a real resource expensive workaround that contradicts the | |
25 * benefits for a Blob: avoidance of huge resource consumption. | |
26 * <b>Use of this class is highly discouraged.</b> | |
27 * | |
28 * @author Fabian Groffen | |
29 */ | |
30 public final class MonetBlob implements Blob { | |
31 private byte[] buf; | |
32 | |
33 /* constructors */ | |
34 protected MonetBlob(final byte[] data) { | |
35 buf = data; | |
36 } | |
37 | |
38 protected MonetBlob(final String hexString) { | |
39 buf = hexStrToByteArray(hexString); | |
40 } | |
41 | |
42 | |
43 /* class utility methods */ | |
44 static final byte[] hexStrToByteArray(final String hexString) { | |
45 // unpack the HEX (BLOB) notation to real bytes | |
46 final int len = hexString.length() / 2; | |
47 final byte[] buf = new byte[len]; | |
48 for (int i = 0; i < len; i++) { | |
49 // was buf[i] = (byte)Integer.parseInt(hexString.substring(2 * i, (2 * i) + 2), 16); | |
50 buf[i] = (byte) ((Character.digit(hexString.charAt(2 * i), 16) << 4) | |
51 + Character.digit(hexString.charAt((2 * i) +1), 16)); | |
52 } | |
53 return buf; | |
54 } | |
55 | |
56 /* internal utility method */ | |
57 private final void checkBufIsNotNull() throws SQLException { | |
58 if (buf == null) | |
59 throw new SQLException("This MonetBlob has been freed", "M1M20"); | |
60 } | |
61 | |
62 //== begin interface Blob | |
63 | |
64 /** | |
65 * This method frees the Blob object and releases the resources that | |
66 * it holds. The object is invalid once the free method is called. | |
67 * | |
68 * After free has been called, any attempt to invoke a method other | |
69 * than free will result in a SQLException being thrown. If free is | |
70 * called multiple times, the subsequent calls to free are treated | |
71 * as a no-op. | |
72 * | |
73 * @throws SQLException if an error occurs releasing the Blob's resources | |
74 */ | |
75 @Override | |
76 public void free() throws SQLException { | |
77 buf = null; | |
78 } | |
79 | |
80 /** | |
81 * Retrieves the BLOB value designated by this Blob instance as a stream. | |
82 * | |
83 * @return a stream containing the BLOB data | |
84 * @throws SQLException if there is an error accessing the BLOB value | |
85 */ | |
86 @Override | |
87 public InputStream getBinaryStream() throws SQLException { | |
88 checkBufIsNotNull(); | |
89 return new ByteArrayInputStream(buf); | |
90 } | |
91 | |
92 /** | |
93 * Returns an InputStream object that contains a partial Blob value, | |
94 * starting with the byte specified by pos, which is length bytes in | |
95 * length. | |
96 * | |
97 * @param pos the offset to the first byte of the partial value to | |
98 * be retrieved. The first byte in the Blob is at position 1 | |
99 * @param length the length in bytes of the partial value to be retrieved | |
100 * @return InputStream through which the partial Blob value can be read. | |
101 * @throws SQLException if pos is less than 1 or if pos is | |
102 * greater than the number of bytes in the Blob or if pos + | |
103 * length is greater than the number of bytes in the Blob | |
104 */ | |
105 @Override | |
106 public InputStream getBinaryStream(final long pos, final long length) | |
107 throws SQLException | |
108 { | |
109 checkBufIsNotNull(); | |
110 if (pos < 1 || pos > buf.length) { | |
111 throw new SQLException("Invalid pos value: " + pos, "M1M05"); | |
112 } | |
113 if (length < 0 || pos - 1 + length > buf.length) { | |
114 throw new SQLException("Invalid length value: " + length, "M1M05"); | |
115 } | |
116 return new ByteArrayInputStream(buf, (int) pos - 1, (int) length); | |
117 } | |
118 | |
119 /** | |
120 * Retrieves all or part of the BLOB value that this Blob object | |
121 * represents, as an array of bytes. This byte array contains up to | |
122 * length consecutive bytes starting at position pos. | |
123 * | |
124 * @param pos the ordinal position of the first byte in the BLOB | |
125 * value to be extracted; the first byte is at position 1. | |
126 * @param length the number of consecutive bytes to be copied | |
127 * @return a byte array containing up to length consecutive bytes | |
128 * from the BLOB value designated by this Blob object, | |
129 * starting with the byte at position pos. | |
130 * @throws SQLException if there is an error accessing the BLOB value | |
131 */ | |
132 @Override | |
133 public byte[] getBytes(final long pos, final int length) throws SQLException { | |
134 checkBufIsNotNull(); | |
135 if (pos < 1 || pos > buf.length) { | |
136 throw new SQLException("Invalid pos value: " + pos, "M1M05"); | |
137 } | |
138 if (length < 0 || pos - 1 + length > buf.length) { | |
139 throw new SQLException("Invalid length value: " + length, "M1M05"); | |
140 } | |
141 | |
142 try { | |
143 return java.util.Arrays.copyOfRange(buf, (int) pos - 1, (int) pos - 1 + length); | |
144 } catch (IndexOutOfBoundsException e) { | |
145 throw new SQLException(e.getMessage(), "M0M10"); | |
146 } | |
147 } | |
148 | |
149 /** | |
150 * Returns the number of bytes in the BLOB value designated by this | |
151 * Blob object. | |
152 * | |
153 * @return length of the BLOB in bytes | |
154 * @throws SQLException if there is an error accessing the length | |
155 * of the BLOB value | |
156 */ | |
157 @Override | |
158 public long length() throws SQLException { | |
159 checkBufIsNotNull(); | |
160 return (long)buf.length; | |
161 } | |
162 | |
163 /** | |
164 * Retrieves the byte position in the BLOB value designated by this | |
165 * Blob object at which pattern begins. The search begins at position start. | |
166 * | |
167 * @param pattern the Blob object designating the BLOB value for | |
168 * which to search | |
169 * @param start the position in the BLOB value at which to begin | |
170 * searching; the first position is 1 | |
171 * @return the position at which the pattern begins, else -1 | |
172 * @throws SQLException if there is an error accessing the BLOB value | |
173 */ | |
174 @Override | |
175 public long position(final Blob pattern, final long start) throws SQLException { | |
176 if (pattern == null) { | |
177 throw new SQLException("Missing pattern object", "M1M05"); | |
178 } | |
179 // buf and input argument start will be checked in method position(byte{}, long) | |
180 return position(pattern.getBytes(1L, (int)pattern.length()), start); | |
181 } | |
182 | |
183 /** | |
184 * Retrieves the byte position at which the specified byte array | |
185 * pattern begins within the BLOB value that this Blob object | |
186 * represents. The search for pattern begins at position start. | |
187 * | |
188 * @param pattern the byte array for which to search | |
189 * @param start the position at which to begin searching; | |
190 * the first position is 1 | |
191 * @return the position at which the pattern appears, else -1 | |
192 * @throws SQLException if there is an error accessing the BLOB value | |
193 */ | |
194 @Override | |
195 public long position(final byte[] pattern, final long start) throws SQLException { | |
196 checkBufIsNotNull(); | |
197 if (pattern == null) { | |
198 throw new SQLException("Missing pattern object", "M1M05"); | |
199 } | |
200 if (start < 1 || start > buf.length) { | |
201 throw new SQLException("Invalid start value: " + start, "M1M05"); | |
202 } | |
203 try { | |
204 final int patternLength = pattern.length; | |
205 final int maxPos = buf.length - patternLength; | |
206 for (int i = (int)(start - 1); i < maxPos; i++) { | |
207 int j; | |
208 for (j = 0; j < patternLength; j++) { | |
209 if (buf[i + j] != pattern[j]) | |
210 break; | |
211 } | |
212 if (j == patternLength) | |
213 // found a match | |
214 return i; | |
215 } | |
216 } catch (IndexOutOfBoundsException e) { | |
217 throw new SQLException(e.getMessage(), "M0M10"); | |
218 } | |
219 return -1; | |
220 } | |
221 | |
222 /** | |
223 * Retrieves a stream that can be used to write to the BLOB value | |
224 * that this Blob object represents. The stream begins at position | |
225 * pos. The bytes written to the stream will overwrite the existing | |
226 * bytes in the Blob object starting at the position pos. If the end | |
227 * of the Blob value is reached while writing to the stream, then | |
228 * the length of the Blob value will be increased to accomodate the | |
229 * extra bytes. | |
230 * | |
231 * @param pos the position in the BLOB value at which to start | |
232 * writing; the first position is 1 | |
233 * @return a java.io.OutputStream object to which data can be written | |
234 * @throws SQLException if there is an error accessing the BLOB | |
235 * value or if pos is less than 1 | |
236 * @throws SQLFeatureNotSupportedException if the JDBC driver does | |
237 * not support this method | |
238 */ | |
239 @Override | |
240 public OutputStream setBinaryStream(final long pos) throws SQLException { | |
241 throw MonetWrapper.newSQLFeatureNotSupportedException("setBinaryStream"); | |
242 } | |
243 | |
244 /** | |
245 * Writes the given array of bytes to the BLOB value that this Blob | |
246 * object represents, starting at position pos, and returns the | |
247 * number of bytes written. | |
248 * | |
249 * @param pos the position in the BLOB object at which to start writing | |
250 * @param bytes the array of bytes to be written to the BLOB value | |
251 * that this Blob object represents | |
252 * @return the number of bytes written | |
253 * @throws SQLException if there is an error accessing the | |
254 * BLOB value or if pos is less than 1 | |
255 */ | |
256 @Override | |
257 public int setBytes(final long pos, final byte[] bytes) throws SQLException { | |
258 // buf and input arguments will be checked in method setBytes(long, byte{}, int, int) | |
259 final int len = (bytes != null) ? bytes.length : 0; | |
260 return setBytes(pos, bytes, 1, len); | |
261 } | |
262 | |
263 /** | |
264 * Writes all or part of the given byte array to the BLOB value that | |
265 * this Blob object represents and returns the number of bytes written. | |
266 * Writing starts at position pos in the BLOB value; len bytes from | |
267 * the given byte array are written. | |
268 * | |
269 * @param pos the position in the BLOB object at which to start writing | |
270 * @param bytes the array of bytes to be written to this BLOB object | |
271 * @param offset the offset into the array bytes at which to start | |
272 * reading the bytes to be set | |
273 * @param len the number of bytes to be written to the BLOB value | |
274 * from the array of bytes bytes | |
275 * @return the number of bytes written | |
276 * @throws SQLException if there is an error accessing the | |
277 * BLOB value or if pos is less than 1 | |
278 */ | |
279 @Override | |
280 public int setBytes(final long pos, final byte[] bytes, int offset, final int len) | |
281 throws SQLException | |
282 { | |
283 checkBufIsNotNull(); | |
284 if (bytes == null) { | |
285 throw new SQLException("Missing bytes[] object", "M1M05"); | |
286 } | |
287 if (pos < 1 || pos > buf.length) { | |
288 throw new SQLException("Invalid pos value: " + pos, "M1M05"); | |
289 } | |
290 if (len < 0 || pos + len > buf.length) { | |
291 throw new SQLException("Invalid len value: " + len, "M1M05"); | |
292 } | |
293 if (offset < 0 || offset > bytes.length) { | |
294 throw new SQLException("Invalid offset value: " + offset, "M1M05"); | |
295 } | |
296 | |
297 try { | |
298 offset--; | |
299 /* transactions? what are you talking about? */ | |
300 for (int i = (int)pos; i < len; i++) | |
301 buf[i] = bytes[offset + i]; | |
302 } catch (IndexOutOfBoundsException e) { | |
303 throw new SQLException(e.getMessage(), "M0M10"); | |
304 } | |
305 return len; | |
306 } | |
307 | |
308 /** | |
309 * Truncates the BLOB value that this Blob object represents to be | |
310 * len bytes in length. | |
311 * | |
312 * @param len the length, in bytes, to which the BLOB value | |
313 * should be truncated | |
314 * @throws SQLException if there is an error accessing the BLOB value | |
315 */ | |
316 @Override | |
317 public void truncate(final long len) throws SQLException { | |
318 checkBufIsNotNull(); | |
319 if (len < 0 || len > buf.length) { | |
320 throw new SQLException("Invalid len value: " + len, "M1M05"); | |
321 } | |
322 if (buf.length > len) { | |
323 buf = java.util.Arrays.copyOf(buf, (int)len); | |
324 } | |
325 } | |
326 } |