comparison src/main/java/org/monetdb/jdbc/MonetClob.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
parents src/main/java/nl/cwi/monetdb/jdbc/MonetClob.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.InputStream;
12 import java.io.Reader;
13 import java.io.StringReader;
14 import java.sql.Clob;
15 import java.sql.SQLException;
16 import java.sql.SQLFeatureNotSupportedException;
17
18 /**
19 * The MonetClob class implements the {@link java.sql.Clob} interface.
20 *
21 * Because MonetDB/SQL currently has no support for streams, this class is a
22 * shallow wrapper of a {@link StringBuilder}. 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 * sole reason for a Clob: 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 MonetClob implements Clob {
31 private StringBuilder buf;
32
33 protected MonetClob(final String in) {
34 buf = new StringBuilder(in);
35 }
36
37 /* internal utility method */
38 private final void checkBufIsNotNull() throws SQLException {
39 if (buf == null)
40 throw new SQLException("This MonetClob has been freed", "M1M20");
41 }
42
43 //== begin interface Clob
44
45 /**
46 * This method frees the Clob object and releases the resources the
47 * resources that it holds. The object is invalid once the free
48 * method is called.
49 *
50 * After free has been called, any attempt to invoke a method other
51 * than free will result in a SQLException being thrown. If free is
52 * called multiple times, the subsequent calls to free are treated
53 * as a no-op.
54 */
55 @Override
56 public void free() {
57 buf = null;
58 }
59
60 /**
61 * Retrieves the CLOB value designated by this Clob object as an
62 * ascii stream.
63 *
64 * @return a java.io.InputStream object containing the CLOB data
65 * @throws SQLException - if there is an error accessing the CLOB value
66 */
67 @Override
68 public InputStream getAsciiStream() throws SQLException {
69 checkBufIsNotNull();
70 return new java.io.ByteArrayInputStream(buf.toString().getBytes());
71 }
72
73 /**
74 * Retrieves the CLOB value designated by this Clob object as a
75 * java.io.Reader object (or as a stream of characters).
76 *
77 * @return a java.io.Reader object containing the CLOB data
78 * @throws SQLException - if there is an error accessing the CLOB value
79 */
80 @Override
81 public Reader getCharacterStream() throws SQLException {
82 checkBufIsNotNull();
83 return new StringReader(buf.toString());
84 }
85
86 /**
87 * Returns a Reader object that contains a partial Clob value,
88 * starting with the character specified by pos, which is length
89 * characters in length.
90 *
91 * @param pos the offset to the first character of the partial value
92 * to be retrieved. The first character in the Clob is at position 1.
93 * @param length the length in characters of the partial value to be retrieved.
94 * @return Reader through which the partial Clob value can be read.
95 * @throws SQLException - if pos is less than 1
96 * or if pos is greater than the number of characters in the Clob
97 * or if pos + length is greater than the number of characters in the Clob
98 */
99 @Override
100 public Reader getCharacterStream(final long pos, final long length) throws SQLException {
101 // as length will be casted to int, check it for too big value first
102 if (length < 0 || length > Integer.MAX_VALUE) {
103 throw new SQLException("Invalid length value: " + length, "M1M05");
104 }
105 // buf and input argument pos will be checked in method getSubString(long, int)
106 return new StringReader(getSubString(pos, (int)length));
107 }
108
109 /**
110 * Retrieves a copy of the specified substring in the CLOB value
111 * designated by this Clob object. The substring begins at
112 * position pos and has up to length consecutive characters.
113 *
114 * @param pos the first character of the substring to be
115 * extracted. The first character is at position 1.
116 * @param length the number of consecutive characters to be copied
117 * @return a String that is the specified substring in the
118 * CLOB value designated by this Clob object
119 * @throws SQLException - if pos is less than 1
120 * or if pos is greater than the number of characters in the Clob
121 * or if pos + length is greater than the number of characters in the Clob
122 * @throws SQLException - if there is an error accessing the CLOB value
123 */
124 @Override
125 public String getSubString(final long pos, final int length) throws SQLException {
126 checkBufIsNotNull();
127 if (pos == 1L && length == buf.length()) {
128 // the whole string is requested
129 return buf.toString();
130 }
131 if (pos < 1 || pos > buf.length()) {
132 throw new SQLException("Invalid pos value: " + pos, "M1M05");
133 }
134 if (length < 0 || pos -1 + length > buf.length()) {
135 throw new SQLException("Invalid length value: " + length, "M1M05");
136 }
137 try {
138 return buf.substring((int)(pos - 1), (int)(pos - 1 + length));
139 } catch (IndexOutOfBoundsException e) {
140 throw new SQLException(e.getMessage(), "M1M05");
141 }
142 }
143
144 /**
145 * Retrieves the number of characters in the CLOB value designated
146 * by this Clob object.
147 *
148 * @return length of the CLOB in characters
149 * @throws SQLException if there is an error accessing the length
150 * of the CLOB value
151 */
152 @Override
153 public long length() throws SQLException {
154 checkBufIsNotNull();
155 return (long)buf.length();
156 }
157
158 /**
159 * Retrieves the character position at which the specified Clob
160 * object searchstr appears in this Clob object. The search
161 * begins at position start.
162 *
163 * @param searchstr the Clob object for which to search
164 * @param start the position at which to begin searching;
165 * the first position is 1
166 * @return the position at which the Clob object appears or
167 * -1 if it is not present; the first position is 1
168 * @throws SQLException - if there is an error accessing the CLOB value
169 */
170 @Override
171 public long position(final Clob searchstr, final long start) throws SQLException {
172 if (searchstr == null) {
173 throw new SQLException("Missing searchstr object", "M1M05");
174 }
175 // buf and input argument start will be checked in method position(String, long)
176 return position(searchstr.toString(), start);
177 }
178
179 /**
180 * Retrieves the character position at which the specified
181 * substring searchstr appears in the SQL CLOB value represented
182 * by this Clob object. The search begins at position start.
183 *
184 * @param searchstr the substring for which to search
185 * @param start the position at which to begin searching;
186 * the first position is 1
187 * @return the position at which the substring appears or
188 * -1 if it is not present; the first position is 1
189 * @throws SQLException - if there is an error accessing the CLOB value
190 */
191 @Override
192 public long position(final String searchstr, final long start) throws SQLException {
193 checkBufIsNotNull();
194 if (searchstr == null) {
195 throw new SQLException("Missing searchstr object", "M1M05");
196 }
197 if (start < 1 || start > buf.length()) {
198 throw new SQLException("Invalid start value: " + start, "M1M05");
199 }
200 return (long)(buf.indexOf(searchstr, (int)(start - 1)));
201 }
202
203 /**
204 * Retrieves a stream to be used to write Ascii characters to the CLOB value that this
205 * Clob object represents, starting at position pos. Characters written to the stream
206 * will overwrite the existing characters in the Clob object starting at the position pos.
207 * If the end of the Clob value is reached while writing characters to the stream,
208 * then the length of the Clob value will be increased to accomodate the extra characters.
209 *
210 * Note: If the value specified for pos is greater then the length+1 of the CLOB value
211 * then the behavior is undefined. Some JDBC drivers may throw a SQLException while
212 * other drivers may support this operation.
213 *
214 * @param pos - the position at which to start writing to this CLOB object; The first position is 1
215 * @return the stream to which ASCII encoded characters can be written
216 * @throws SQLException - if there is an error accessing the CLOB value or if pos is less than 1
217 * @throws SQLFeatureNotSupportedException - if the JDBC driver does not support this method
218 */
219 @Override
220 public java.io.OutputStream setAsciiStream(final long pos) throws SQLException {
221 throw MonetWrapper.newSQLFeatureNotSupportedException("setAsciiStream");
222 }
223
224 /**
225 * Retrieves a stream to be used to write a stream of Unicode characters to the CLOB value that
226 * this Clob object represents, starting at position pos. Characters written to the stream
227 * will overwrite the existing characters in the Clob object starting at the position pos.
228 * If the end of the Clob value is reached while writing characters to the stream,
229 * then the length of the Clob value will be increased to accomodate the extra characters.
230 *
231 * Note: If the value specified for pos is greater then the length+1 of the CLOB value
232 * then the behavior is undefined. Some JDBC drivers may throw a SQLException while
233 * other drivers may support this operation.
234 *
235 * @param pos - the position at which to start writing to this CLOB object; The first position is 1
236 * @return the stream to which Unicode encoded characters can be written
237 * @throws SQLException - if there is an error accessing the CLOB value or if pos is less than 1
238 * @throws SQLFeatureNotSupportedException - if the JDBC driver does not support this method
239 */
240 @Override
241 public java.io.Writer setCharacterStream(final long pos) throws SQLException {
242 throw MonetWrapper.newSQLFeatureNotSupportedException("setCharacterStream");
243 }
244
245 /**
246 * Writes the given Java String to the CLOB value that this Clob object designates at the position pos.
247 * The string will overwrite the existing characters in the Clob object starting at the position pos.
248 * If the end of the Clob value is reached while writing the given string,
249 * then the length of the Clob value will be increased to accomodate the extra characters.
250 *
251 * @param pos the position at which to start writing to the CLOB value that this Clob object represents
252 * @param str the string to be written to the CLOB value that this Clob designates
253 * @return the number of characters written
254 * @throws SQLException if there is an error accessing the CLOB value or if pos is less than 1
255 */
256 @Override
257 public int setString(final long pos, final String str) throws SQLException {
258 // buf and input arguments will be checked in method setString(long, String, int, int)
259 final int len = (str != null) ? str.length() : 0;
260 return setString(pos, str, 0, len);
261 }
262
263 /**
264 * Writes len characters of str, starting at character offset, to the CLOB value that this Clob represents.
265 * The string will overwrite the existing characters in the Clob object starting at the position pos.
266 * If the end of the Clob value is reached while writing the given string,
267 * then the length of the Clob value will be increased to accomodate the extra characters.
268 *
269 * @param pos the position at which to start writing to this CLOB object
270 * @param str the string to be written to the CLOB value that this Clob object represents
271 * @param offset the offset into str to start reading the characters to be written
272 * @param len the number of characters to be written
273 * @return the number of characters written
274 * @throws SQLException if there is an error accessing the CLOB value or if pos is less than 1
275 */
276 @Override
277 public int setString(final long pos, final String str, final int offset, final int len)
278 throws SQLException
279 {
280 checkBufIsNotNull();
281 if (str == null) {
282 throw new SQLException("Missing str object", "M1M05");
283 }
284 if (pos < 1 || pos > Integer.MAX_VALUE) {
285 throw new SQLException("Invalid pos value: " + pos, "M1M05");
286 }
287 if (offset < 0 || offset > str.length()) {
288 throw new SQLException("Invalid offset value: " + offset, "M1M05");
289 }
290 if (len < 1 || (offset + len) > str.length()) {
291 throw new SQLException("Invalid len value: " + len, "M1M05");
292 }
293 if (((int) pos + len) > buf.capacity()) {
294 // enlarge the buffer before filling it
295 buf.ensureCapacity((int) pos + len);
296 }
297 buf.replace((int) pos - 1, (int) pos + len, str.substring(offset, (offset + len)));
298 return len;
299 }
300
301 /**
302 * Truncates the CLOB value that this Clob designates to
303 * have a length of len characters.
304 *
305 * @param len the length, in bytes, to which the CLOB value should be truncated
306 * @throws SQLException if there is an error accessing the
307 * CLOB value or if len is less than 0
308 */
309 @Override
310 public void truncate(final long len) throws SQLException {
311 checkBufIsNotNull();
312 if (len < 0 || len > buf.length()) {
313 throw new SQLException("Invalid len value: " + len, "M1M05");
314 }
315 buf.setLength((int)len);
316 // reduce storage used for the character sequence.
317 buf.trimToSize();
318 }
319
320
321 /**
322 * Returns a String from this MonetClob buf.
323 *
324 * @return the String this MonetClob wraps or empty string when this MonetClob was freed.
325 */
326 public String toString() {
327 if (buf == null)
328 return "";
329 return buf.toString();
330 }
331 }