Line | Hits | Source |
---|---|---|
1 | /* | |
2 | * Copyright (C) 2006 TopCoder Inc., All Rights Reserved. | |
3 | */ | |
4 | package com.topcoder.document.index.persistence.impl.db; | |
5 | ||
6 | import com.topcoder.document.index.persistence.IndexPersistenceException; | |
7 | ||
8 | import java.sql.Blob; | |
9 | import java.sql.Connection; | |
10 | import java.sql.PreparedStatement; | |
11 | import java.sql.ResultSet; | |
12 | import java.sql.ResultSetMetaData; | |
13 | import java.sql.SQLException; | |
14 | import java.util.ArrayList; | |
15 | import java.util.Arrays; | |
16 | import java.util.List; | |
17 | ||
18 | ||
19 | /** | |
20 | * This class contains utility methods used only by the database package of this component. This class is | |
21 | * package-visible as all methods are solely used from this package. | |
22 | * | |
23 | * @author TCSDEVELOPER | |
24 | * @version 1.0 | |
25 | */ | |
26 | class DatabaseUtils { | |
27 | /** | |
28 | * This constant provides the {@link DataType} instance that can be used in {@link #doQuery(java.sql.Connection, | |
29 | * String, Object[], DatabaseUtils.DataType[])} and {@link #doSingleValueQuery(java.sql.Connection, String, | |
30 | * Object[], DatabaseUtils.DataType)} to specify that a {@link java.sql.ResultSet} column of a query result should | |
31 | * be returned as a non-<tt>null</tt> value of type {@link String}. | |
32 | * <p/> | |
33 | * The query execution throws an exception case the {@link java.sql.ResultSet} value was <tt>null</tt>. | |
34 | */ | |
35 | 1 | static final DataType STRING_TYPE = new StringType(); |
36 | /** | |
37 | * This constant provides the {@link DataType} instance that can be used in {@link #doQuery(java.sql.Connection, | |
38 | * String, Object[], DatabaseUtils.DataType[])} and {@link #doSingleValueQuery(java.sql.Connection, String, | |
39 | * Object[], DatabaseUtils.DataType)} to specify that a {@link java.sql.ResultSet} column of a query result should | |
40 | * be returned as a non-<tt>null</tt> value of type <tt>byte[]</tt> | |
41 | * <p/> | |
42 | * The query execution throws an exception case the {@link java.sql.ResultSet} value was <tt>null</tt>. | |
43 | */ | |
44 | 1 | static final DataType BYTE_ARRAY_TYPE = new ByteArrayType(); |
45 | /** | |
46 | * This constant provides the {@link DataType} instance that can be used in {@link #doQuery(java.sql.Connection, | |
47 | * String, Object[], DatabaseUtils.DataType[])} and {@link #doSingleValueQuery(java.sql.Connection, String, | |
48 | * Object[], DatabaseUtils.DataType)} to specify that a {@link ResultSet} column of a query result should be | |
49 | * returned as non-<tt>null</tt> value of type {@link Integer}. | |
50 | * <p/> | |
51 | * The query execution throws an exception case the {@link java.sql.ResultSet} value was <tt>null</tt>. | |
52 | */ | |
53 | 1 | static final DataType INTEGER_TYPE = new IntegerType(); |
54 | ||
55 | /** | |
56 | * As this class is a utility class, a private constructor is added to avoid class instantiation. | |
57 | */ | |
58 | 0 | private DatabaseUtils() { |
59 | 0 | } |
60 | ||
61 | /** | |
62 | * This method performs the given retrieval (i.e. non-DML) query on the given connection using the given query | |
63 | * arguments. The {@link java.sql.ResultSet} returned from the query is fetched into a List of <tt>Object[]</tt>s | |
64 | * and then returned. This approach assured that all resources (the {@link java.sql.PreparedStatement} and the | |
65 | * {@link java.sql.ResultSet}) allocated in this method are also de-allocated in this method. | |
66 | * <p/> | |
67 | * <b>Note:</b> The given connection is not closed or committed in this method, but is rolled back upon any error | |
68 | * | |
69 | * @param connection the connection to perform the query on | |
70 | * @param persistence the AbstractDBIndexPersistence instance that can be used to perform rollback operations on the | |
71 | * given connection in case an error is encountered | |
72 | * @param queryString the query to be performed (a {@link java.sql.PreparedStatement} is created from it) | |
73 | * @param queryArgs the arguments to be used in the query (i.e. to be set to the created {@link | |
74 | * PreparedStatement}) | |
75 | * @param columnTypes the types as which to return the result set columns, use the values {@link #STRING_TYPE}, | |
76 | * {@link #BYTE_ARRAY_TYPE} or {@link #INTEGER_TYPE} in the construction of the given array | |
77 | * | |
78 | * @return the result of the query as List containing an <tt>Object[]</tt> for each {@link java.sql.ResultSet} row | |
79 | * The elements of the array are of the type represented by the {@link DataType} specified at the | |
80 | * corresponding index in the given columnTypes array (or <tt>null</tt> in case the resultSet value was | |
81 | * <tt>null</tt>) | |
82 | * | |
83 | * @throws IndexPersistenceException in case the query fails | |
84 | * @throws IllegalArgumentException in case any arg is <tt>null</tt> or the given query String was an empty | |
85 | * (trim'd) string or the column types count does not match the result set column | |
86 | * count or column types contained a <tt>null</tt> value | |
87 | * @see DatabaseUtils#doDMLQuery(java.sql.Connection, AbstractDBIndexPersistence, String, Object[]) | |
88 | * @see DatabaseUtils#doSingleValueQuery(Connection, AbstractDBIndexPersistence, String, Object[], | |
89 | * DatabaseUtils.DataType) | |
90 | */ | |
91 | static List doQuery(final Connection connection, final AbstractDBIndexPersistence persistence, | |
92 | final String queryString, final Object[] queryArgs, final DataType[] columnTypes) | |
93 | throws IndexPersistenceException { | |
94 | 188 | DatabaseUtils.checkArgs(connection, persistence, queryString, queryArgs); |
95 | 179 | if (columnTypes == null) { |
96 | 1 | throw new IllegalArgumentException("The parameter named [columnTypes] was null."); |
97 | } | |
98 | 475 | for (int i = 0; i < columnTypes.length; i++) { |
99 | 298 | if (columnTypes[i] == null) { |
100 | 1 | throw new IllegalArgumentException("The given parameter named [columnTypes] contained a null value."); |
101 | } | |
102 | } | |
103 | ||
104 | try { | |
105 | 177 | final PreparedStatement preparedStatement = connection.prepareStatement(queryString); |
106 | try { | |
107 | 349 | for (int i = 0; i < queryArgs.length; i++) { |
108 | 174 | preparedStatement.setObject(i + 1, queryArgs[i]); |
109 | } | |
110 | 175 | final ResultSet resultSet = preparedStatement.executeQuery(); |
111 | try { | |
112 | 174 | final List ret = new ArrayList(); |
113 | 174 | final ResultSetMetaData metaData = resultSet.getMetaData(); |
114 | 174 | final int columnCount = metaData.getColumnCount(); |
115 | 174 | if (columnTypes.length != columnCount) { |
116 | 1 | throw new IllegalArgumentException("The column types length [" + columnTypes.length |
117 | + "] does not match the result set column count[" + columnCount + "]."); | |
118 | } | |
119 | 1370 | while (resultSet.next()) { |
120 | 1197 | final Object[] rowData = new Object[columnCount]; |
121 | 3546 | for (int i = 0; i < rowData.length; i++) { |
122 | 2349 | rowData[i] = columnTypes[i].getValue(resultSet, i + 1); |
123 | } | |
124 | 1197 | ret.add(rowData); |
125 | } | |
126 | 173 | return ret; |
127 | } finally { | |
128 | 174 | DatabaseUtils.closeResultSetSilently(resultSet); |
129 | } | |
130 | } finally { | |
131 | 175 | DatabaseUtils.closeStatementSilently(preparedStatement); |
132 | } | |
133 | ||
134 | 3 | } catch (SQLException e) { |
135 | // this is the catch clause for exceptions that can occur during execution of the statement, | |
136 | // Upon exception we rollback and close the connection and throw the wrapped SQLException | |
137 | 3 | persistence.rollbackTransaction(connection); |
138 | 2 | throw new IndexPersistenceException( |
139 | "Error while executing query [" + queryString + "] using the query arguments [" + Arrays.asList( | |
140 | queryArgs).toString() + "].", e); | |
141 | } | |
142 | } | |
143 | ||
144 | /** | |
145 | * This method performs the given retrieval (i.e. non-DML) query on the given connection using the given query | |
146 | * arguments. | |
147 | * <p/> | |
148 | * The {@link java.sql.ResultSet} returned from the query is expected to contain ONE row containing ONE value, which | |
149 | * is then returned. | |
150 | * <p/> | |
151 | * This approach assured that all resources (the {@link java.sql.PreparedStatement} and the {@link | |
152 | * java.sql.ResultSet}) allocated in this method are also de-allocated in this method. | |
153 | * <p/> | |
154 | * <b>Note:</b> The given connection is not closed or committed in this method, but is rolled back upon any error | |
155 | * | |
156 | * @param connection the connection to perform the query on | |
157 | * @param persistence the AbstractDBIndexPersistence instance that can be used to perform rollback operations on the | |
158 | * given connection in case an error is encountered | |
159 | * @param queryString the query to be performed (a {@link java.sql.PreparedStatement} is created from it) | |
160 | * @param queryArgs the arguments to be used in the query (i.e. to be set to the created {@link | |
161 | * PreparedStatement}) | |
162 | * @param columnType the type as which to return the value, use one of the values {@link #STRING_TYPE}, {@link | |
163 | * #BYTE_ARRAY_TYPE} or {@link #INTEGER_TYPE} here | |
164 | * | |
165 | * @return the value returned by the query as value of the type represented by the given columnType or <tt>null</tt> | |
166 | * if the {@link java.sql.ResultSet} value was <tt>null</tt> | |
167 | * | |
168 | * @throws IndexPersistenceException in case the query fails | |
169 | * @throws IllegalArgumentException in case any arg is <tt>null</tt> or the given query String was an empty | |
170 | * (trim'd) string or the given query did return multiple rows or columns | |
171 | * @see DatabaseUtils#doDMLQuery(java.sql.Connection, AbstractDBIndexPersistence, String, Object[]) | |
172 | * @see DatabaseUtils#doSingleValueQuery(java.sql.Connection, AbstractDBIndexPersistence, String, Object[], | |
173 | * DatabaseUtils.DataType) | |
174 | */ | |
175 | static Object doSingleValueQuery(final Connection connection, final AbstractDBIndexPersistence persistence, | |
176 | final String queryString, final Object[] queryArgs, | |
177 | final DataType columnType) | |
178 | throws IndexPersistenceException { | |
179 | 239 | DatabaseUtils.checkArgs(connection, persistence, queryString, queryArgs); |
180 | 234 | if (columnType == null) { |
181 | 1 | throw new IllegalArgumentException("The parameter named [columnType] was null."); |
182 | } | |
183 | ||
184 | try { | |
185 | 233 | final PreparedStatement preparedStatement = connection.prepareStatement(queryString); |
186 | try { | |
187 | 459 | for (int i = 0; i < queryArgs.length; i++) { |
188 | 229 | preparedStatement.setObject(i + 1, queryArgs[i]); |
189 | } | |
190 | 230 | final ResultSet resultSet = preparedStatement.executeQuery(); |
191 | try { | |
192 | 230 | final ResultSetMetaData metaData = resultSet.getMetaData(); |
193 | 230 | final int columnCount = metaData.getColumnCount(); |
194 | 230 | if (columnCount == 1 && resultSet.next()) { |
195 | 229 | return columnType.getValue(resultSet, 1); |
196 | } else { | |
197 | 1 | throw new IllegalArgumentException( |
198 | "The given query [" + queryString + "] did not return ONE result row containing " | |
199 | + "ONE value using the query arguments [" + Arrays.asList(queryArgs).toString() + "]."); | |
200 | } | |
201 | } finally { | |
202 | 230 | DatabaseUtils.closeResultSetSilently(resultSet); |
203 | } | |
204 | } finally { | |
205 | 231 | DatabaseUtils.closeStatementSilently(preparedStatement); |
206 | } | |
207 | ||
208 | 3 | } catch (SQLException e) { |
209 | // this is the catch clause for exceptions that can occur during execution of the statement, | |
210 | // Upon exception we rollback and close the connection and throw the wrapped SQLException | |
211 | // | |
212 | // The rollback is done even as this is no DML query, | |
213 | // as previous queries on this connection could have been DMLs | |
214 | 3 | persistence.rollbackTransaction(connection); |
215 | 2 | throw new IndexPersistenceException( |
216 | "Error while executing query [" + queryString + "] using the query arguments [" + Arrays.asList( | |
217 | queryArgs).toString() + "].", e); | |
218 | } | |
219 | } | |
220 | ||
221 | /** | |
222 | * This method performs the given retrieval (i.e. non-DML) query on the given connection using the given query | |
223 | * arguments. | |
224 | * <p/> | |
225 | * The {@link java.sql.ResultSet} returned from the query is expected to contain any number of rows but exactly ONE | |
226 | * column, Sot hat the returned list contains the result values. In comparison to {@link | |
227 | * #doQuery(java.sql.Connection, AbstractDBIndexPersistence, String, Object[], DatabaseUtils.DataType[])} this | |
228 | * method does return a list that directly contains the values and does not wrap every value in an Object[] | |
229 | * containing only the value. | |
230 | * <p/> | |
231 | * This approach assured that all resources (the {@link java.sql.PreparedStatement} and the {@link | |
232 | * java.sql.ResultSet}) allocated in this method are also de-allocated in this method. | |
233 | * <p/> | |
234 | * <b>Note:</b> The given connection is not closed or committed in this method, but is rolled back upon any error | |
235 | * | |
236 | * @param connection the connection to perform the query on | |
237 | * @param persistence the AbstractDBIndexPersistence instance that can be used to perform rollback operations on the | |
238 | * given connection in case an error is encountered | |
239 | * @param queryString the query to be performed (a {@link java.sql.PreparedStatement} is created from it) | |
240 | * @param queryArgs the arguments to be used in the query (i.e. to be set to the created {@link | |
241 | * PreparedStatement}) | |
242 | * @param columnType the type as which to return the value, use one of the values {@link #STRING_TYPE}, {@link | |
243 | * #BYTE_ARRAY_TYPE} or {@link #INTEGER_TYPE} here | |
244 | * | |
245 | * @return the values returned by the query as List of values of the type represented by the given columnType | |
246 | * | |
247 | * @throws IndexPersistenceException in case the query fails | |
248 | * @throws IllegalArgumentException in case any arg is <tt>null</tt> or the given query String was an empty | |
249 | * (trim'd) string or the given query did return multiple rows or columns | |
250 | * @see DatabaseUtils#doDMLQuery(java.sql.Connection, AbstractDBIndexPersistence, String, Object[]) | |
251 | * @see DatabaseUtils#doSingleValueQuery(java.sql.Connection, AbstractDBIndexPersistence, String, Object[], | |
252 | * DatabaseUtils.DataType) | |
253 | */ | |
254 | static List doSingleColumnQuery(final Connection connection, final AbstractDBIndexPersistence persistence, | |
255 | final String queryString, final Object[] queryArgs, | |
256 | final DataType columnType) | |
257 | throws IndexPersistenceException { | |
258 | 1153 | DatabaseUtils.checkArgs(connection, persistence, queryString, queryArgs); |
259 | 1148 | if (columnType == null) { |
260 | 1 | throw new IllegalArgumentException("The parameter named [columnType] was null."); |
261 | } | |
262 | ||
263 | try { | |
264 | 1147 | final PreparedStatement preparedStatement = connection.prepareStatement(queryString); |
265 | try { | |
266 | 3337 | for (int i = 0; i < queryArgs.length; i++) { |
267 | 2193 | preparedStatement.setObject(i + 1, queryArgs[i]); |
268 | } | |
269 | 1144 | final ResultSet resultSet = preparedStatement.executeQuery(); |
270 | try { | |
271 | 1144 | final ResultSetMetaData metaData = resultSet.getMetaData(); |
272 | 1144 | final int columnCount = metaData.getColumnCount(); |
273 | 1144 | if (columnCount == 1) { |
274 | 1143 | final List ret = new ArrayList(); |
275 | 3506 | while (resultSet.next()) { |
276 | 2363 | ret.add(columnType.getValue(resultSet, 1)); |
277 | } | |
278 | 1143 | return ret; |
279 | } else { | |
280 | 1 | throw new IllegalArgumentException( |
281 | "The given query [" + queryString + "] did not return " | |
282 | + "ONE column using the query arguments [" + Arrays.asList(queryArgs).toString() | |
283 | + "]."); | |
284 | } | |
285 | } finally { | |
286 | 1144 | DatabaseUtils.closeResultSetSilently(resultSet); |
287 | } | |
288 | } finally { | |
289 | 1145 | DatabaseUtils.closeStatementSilently(preparedStatement); |
290 | } | |
291 | ||
292 | 3 | } catch (SQLException e) { |
293 | // this is the catch clause for exceptions that can occur during execution of the statement, | |
294 | // Upon exception we rollback and close the connection and throw the wrapped SQLException | |
295 | // | |
296 | // The rollback is done even as this is no DML query, | |
297 | // as previous queries on this connection could have been DMLs | |
298 | 3 | persistence.rollbackTransaction(connection); |
299 | 2 | throw new IndexPersistenceException( |
300 | "Error while executing query [" + queryString + "] using the query arguments [" + Arrays.asList( | |
301 | queryArgs).toString() + "].", e); | |
302 | } | |
303 | } | |
304 | ||
305 | /** | |
306 | * This method performs the given DML (query on the given connection using the given query arguments. | |
307 | * <p/> | |
308 | * The update count returned from the query is then returned. | |
309 | * <p/> | |
310 | * This approach assured that all resources (the {@link java.sql.PreparedStatement}) allocated in this method are | |
311 | * also de-allocated in this method. | |
312 | * <p/> | |
313 | * <b>Note:</b> The given connection is not closed or committed in this method, but is rolled back upon any error | |
314 | * | |
315 | * @param connection the connection to perform the query on | |
316 | * @param persistence the AbstractDBIndexPersistence instance that can be used to perform rollback operations on the | |
317 | * given connection in case an error is encountered | |
318 | * @param queryString the query to be performed (a {@link java.sql.PreparedStatement} is created from it) | |
319 | * @param queryArgs the arguments to be used in the query (i.e. to be set to the created {@link | |
320 | * PreparedStatement}) | |
321 | * | |
322 | * @return the number of database rows affected by the query | |
323 | * | |
324 | * @throws IndexPersistenceException in case the query fails | |
325 | * @throws IllegalArgumentException in case any arg is <tt>null</tt> or the given query String was an empty | |
326 | * (trim'd) string | |
327 | * @see DatabaseUtils#doQuery(java.sql.Connection, AbstractDBIndexPersistence, String, Object[], | |
328 | * DatabaseUtils.DataType[]) | |
329 | * @see DatabaseUtils#doSingleValueQuery(java.sql.Connection, AbstractDBIndexPersistence, String, Object[], | |
330 | * DatabaseUtils.DataType) | |
331 | */ | |
332 | static int doDMLQuery(final Connection connection, final AbstractDBIndexPersistence persistence, | |
333 | final String queryString, final Object[] queryArgs) throws IndexPersistenceException { | |
334 | 5813 | DatabaseUtils.checkArgs(connection, persistence, queryString, queryArgs); |
335 | try { | |
336 | 5808 | final PreparedStatement preparedStatement = connection.prepareStatement(queryString); |
337 | try { | |
338 | 16950 | for (int i = 0; i < queryArgs.length; i++) { |
339 | 11145 | preparedStatement.setObject(i + 1, queryArgs[i]); |
340 | } | |
341 | 5805 | preparedStatement.execute(); |
342 | 5805 | return preparedStatement.getUpdateCount(); |
343 | } finally { | |
344 | 5805 | DatabaseUtils.closeStatementSilently(preparedStatement); |
345 | } | |
346 | 3 | } catch (SQLException e) { |
347 | // this is the catch clause for exceptions that can occur during execution of the statement, | |
348 | // Upon exception we rollback and close the connection and throw the wrapped SQLException | |
349 | 3 | persistence.rollbackTransaction(connection); |
350 | 2 | throw new IndexPersistenceException( |
351 | "Error while executing query [" + queryString + "] using the query arguments [" + Arrays.asList( | |
352 | queryArgs).toString() + "].", e); | |
353 | } | |
354 | } | |
355 | ||
356 | /** | |
357 | * This is a utility arg-checking method for the given args. | |
358 | * | |
359 | * @param connection checked to be non-<tt>null</tt> | |
360 | * @param persistence checked to be non-<tt>null</tt> | |
361 | * @param queryString checked to be non-<tt>null</tt> and non-empty(trim'd) | |
362 | * @param queryArgs checked to be non-<tt>null</tt> | |
363 | * | |
364 | * @throws IllegalArgumentException in case any arg is <tt>null</tt> or the given query String was an empty (trim'd) | |
365 | * string | |
366 | */ | |
367 | private static void checkArgs(final Connection connection, final AbstractDBIndexPersistence persistence, | |
368 | final String queryString, final Object[] queryArgs) { | |
369 | 7393 | if (connection == null) { |
370 | 6 | throw new IllegalArgumentException("The parameter named [connection] was null."); |
371 | } | |
372 | 7387 | if (persistence == null) { |
373 | 6 | throw new IllegalArgumentException("The parameter named [persistence] was null."); |
374 | } | |
375 | 7381 | if (queryString == null) { |
376 | 4 | throw new IllegalArgumentException("The parameter named [queryString] was null."); |
377 | } | |
378 | 7377 | if (queryString.trim().length() == 0) { |
379 | 4 | throw new IllegalArgumentException("The parameter named [queryString] was an empty String."); |
380 | } | |
381 | 7373 | if (queryArgs == null) { |
382 | 4 | throw new IllegalArgumentException("The parameter named [queryArgs] was null."); |
383 | } | |
384 | 7369 | } |
385 | ||
386 | /** | |
387 | * This method silently closes the given connection. | |
388 | * <p/> | |
389 | * Silently means that any exceptions thrown during close of the connection are caught and logged but not | |
390 | * re-thrown. | |
391 | * | |
392 | * @param connection the connection to be closed | |
393 | * | |
394 | * @throws IllegalArgumentException in case the given connection is <tt>null</tt> | |
395 | */ | |
396 | static void closeSilently(final Connection connection) { | |
397 | 730 | if (connection == null) { |
398 | 1 | throw new IllegalArgumentException("The parameter named [connection] was null."); |
399 | } | |
400 | ||
401 | try { | |
402 | 729 | connection.close(); |
403 | 0 | } catch (SQLException e) { |
404 | // as we do not want this exception to mask an | |
405 | // exception that might have occurred during execution, we | |
406 | // cannot throw this exception here. | |
407 | // Furthermore as this is already a cleanup action which | |
408 | // is performed after the operation has finished (either | |
409 | // successfully, then the expected result exists or | |
410 | // unsuccessfully then already an SQLException exists) | |
411 | // there is no reason to throw an exception from this point. | |
412 | 729 | } |
413 | 729 | } |
414 | ||
415 | /** | |
416 | * This method closes the given result set silently, i.e. any exception occurring during close is not re-thrown but | |
417 | * only logged. | |
418 | * | |
419 | * @param resultSet the resultSet to be closed | |
420 | * | |
421 | * @throws IllegalArgumentException in case the given arg is <tt>null</tt> | |
422 | */ | |
423 | private static void closeResultSetSilently(final ResultSet resultSet) { | |
424 | 1548 | if (resultSet == null) { |
425 | 0 | throw new IllegalArgumentException("The parameter named [resultSet] was null."); |
426 | } | |
427 | ||
428 | try { | |
429 | // safely close the result set | |
430 | // according to http://jdj.sys-con.com/read/46653.htm | |
431 | // a robust application should not rely on implicit | |
432 | // closing of result sets | |
433 | 1548 | resultSet.close(); |
434 | 0 | } catch (SQLException e) { |
435 | // as we do not want this exception to mask an | |
436 | // exception that might have occurred during execution, we | |
437 | // cannot throw this exception here. | |
438 | // Furthermore as this is already a cleanup action which | |
439 | // is performed after the operation has finished (either | |
440 | // successfully, then the expected result exists or | |
441 | // unsuccessfully then already an SQLException exists) | |
442 | // there is no reason to throw an exception from this point. | |
443 | 1548 | } |
444 | 1548 | } |
445 | ||
446 | /** | |
447 | * This method closes the given Statement silently, i.e. any exception that occurs during close is not, re.thrown | |
448 | * but only logged. | |
449 | * | |
450 | * @param preparedStatement the statement to be closed | |
451 | * | |
452 | * @throws IllegalArgumentException in case the given arg is <tt>null</tt> | |
453 | */ | |
454 | private static void closeStatementSilently(final PreparedStatement preparedStatement) { | |
455 | 7356 | if (preparedStatement == null) { |
456 | 0 | throw new IllegalArgumentException("The parameter named [preparedStatement] was null."); |
457 | } | |
458 | ||
459 | try { | |
460 | // safely close the statement | |
461 | // according to http://jdj.sys-con.com/read/46653.htm | |
462 | // a robust application should not rely on implicit | |
463 | // closing of statements | |
464 | 7356 | preparedStatement.close(); |
465 | 0 | } catch (SQLException e) { |
466 | // as we do not want this exception to mask an | |
467 | // exception that might have occurred during execution, we | |
468 | // cannot throw this exception here. | |
469 | // Furthermore as this is already a cleanup action which | |
470 | // is performed after the operation has finished (either | |
471 | // successfully, then the expected result exists or | |
472 | // unsuccessfully then already an SQLException exists) | |
473 | // there is no reason to throw an exception from this point. | |
474 | 7356 | } |
475 | 7356 | } |
476 | ||
477 | /** | |
478 | * This class is a wrapper for type safe retrieval of values from a {@link java.sql.ResultSet}. Instances of this | |
479 | * class can be used as arguments to {@link DatabaseUtils#doQuery(java.sql.Connection, AbstractDBIndexPersistence, | |
480 | * String, Object[], DatabaseUtils.DataType[])} and {@link DatabaseUtils#doSingleValueQuery(java.sql.Connection, | |
481 | * AbstractDBIndexPersistence, String, Object[], DatabaseUtils.DataType)}to specify the type as which to return the | |
482 | * value of a ResultSet column. | |
483 | * <p/> | |
484 | * This class has been introduced to generify the behaviors of different databases and JDBC drivers so that always | |
485 | * the expected type is returned ({@link java.sql.ResultSet#getObject(int)} does not sufficiently do this job as the | |
486 | * type of the value is highly database-dependant (e.g. for a BLOB column the MySQL driver returns a <tt>byte[]</tt> | |
487 | * and the Oracle driver returns a {@link java.sql.Blob})). | |
488 | * <p/> | |
489 | * This class contains a private constructor to make sure all implementations of this class are declared inside | |
490 | * {@link DatabaseUtils}. Instances are provided to users via constants declared in {@link DatabaseUtils} - so this | |
491 | * class defines some kind of 'pseudo-enum' which cannot be instantiated externally. | |
492 | * | |
493 | * @author TCSDEVELOPER | |
494 | * @version 1.0 | |
495 | */ | |
496 | abstract static class DataType { | |
497 | /** | |
498 | * Empty private constructor. By using this concept, it is assured that only {@link DatabaseUtils} can contain | |
499 | * subclasses of this class and the implementation classes cannot be instantiated externally. | |
500 | */ | |
501 | private DataType() { | |
502 | ||
503 | } | |
504 | ||
505 | /** | |
506 | * This method retrieves the value at the given index from the given resultSet as instance of the | |
507 | * subclass-dependant type. | |
508 | * <p/> | |
509 | * | |
510 | * @param resultSet the result set from which to retrieve the value | |
511 | * @param index the index at which to retrieve the value | |
512 | * | |
513 | * @return the retrieved value | |
514 | * | |
515 | * @throws IllegalArgumentException in case given resultSet or columnType is <tt>null</tt> | |
516 | * @throws java.sql.SQLException in case an exception occurs while working with the given ResultSet or the | |
517 | * index does not exist in the result set | |
518 | */ | |
519 | protected abstract Object getValue(ResultSet resultSet, int index) throws SQLException; | |
520 | ||
521 | } | |
522 | ||
523 | /** | |
524 | * This class is a wrapper for type safe retrieval of values from a {@link java.sql.ResultSet}. The values retrieved | |
525 | * by the {@link #getValue(java.sql.ResultSet, int)} implementation of this {@link DataType} are assured to be of | |
526 | * type {@link String} or to be <tt>null</tt> in case the {@link java.sql.ResultSet} value was <tt>null</tt>. | |
527 | * <p/> | |
528 | * <p/> | |
529 | * The only instance of this class is available as value of the constant {@link DatabaseUtils#STRING_TYPE}. | |
530 | * | |
531 | * @author TCSDEVELOPER | |
532 | * @version 1.0 | |
533 | */ | |
534 | private static class StringType extends DataType { | |
535 | /** | |
536 | * This method retrieves the value at the given index from the given resultSet as instance of the | |
537 | * subclass-dependant type. | |
538 | * <p/> | |
539 | * | |
540 | * @param resultSet the result set from which to retrieve the value | |
541 | * @param index the index at which to retrieve the value | |
542 | * | |
543 | * @return the retrieved value as {@link String} or <tt>null</tt> if the value in the {@link java.sql.ResultSet} | |
544 | * was <tt>null</tt>. | |
545 | * | |
546 | * @throws IllegalArgumentException in case given resultSet or columnType is <tt>null</tt> | |
547 | * @throws java.sql.SQLException in case an exception occurs while working with the given ResultSet or the | |
548 | * index does not exist in the result set | |
549 | */ | |
550 | protected Object getValue(final ResultSet resultSet, final int index) throws SQLException { | |
551 | final String string = resultSet.getString(index); | |
552 | if (resultSet.wasNull()) { | |
553 | throw new SQLException("Assertion failed: result set value was expected to be non-null, " | |
554 | + "but was null."); | |
555 | } else { | |
556 | return string; | |
557 | } | |
558 | } | |
559 | } | |
560 | ||
561 | /** | |
562 | * This class is a wrapper for type safe retrieval of values from a {@link java.sql.ResultSet}. The values retrieved | |
563 | * by the {@link #getValue(java.sql.ResultSet, int)} implementation of this {@link DataType} are assured to be of | |
564 | * type <tt>byte[]</tt> or to be <tt>null</tt> in case the {@link java.sql.ResultSet} value was <tt>null</tt>. | |
565 | * <p/> | |
566 | * <p/> | |
567 | * The only instance of this class is available as value of the constant {@link DatabaseUtils#BYTE_ARRAY_TYPE}. | |
568 | * | |
569 | * @author TCSDEVELOPER | |
570 | * @version 1.0 | |
571 | */ | |
572 | private static class ByteArrayType extends DataType { | |
573 | /** | |
574 | * This method retrieves the value at the given index from the given resultSet as instance of the | |
575 | * subclass-dependant type. | |
576 | * <p/> | |
577 | * | |
578 | * @param resultSet the result set from which to retrieve the value | |
579 | * @param index the index at which to retrieve the value | |
580 | * | |
581 | * @return the retrieved value as <tt>byte[]</tt> or <tt>null</tt> if the value in the {@link | |
582 | * java.sql.ResultSet} was <tt>null</tt>. | |
583 | * | |
584 | * @throws IllegalArgumentException in case given resultSet or columnType is <tt>null</tt> | |
585 | * @throws java.sql.SQLException in case an exception occurs while working with the given ResultSet or the | |
586 | * index does not exist in the result set | |
587 | */ | |
588 | protected Object getValue(final ResultSet resultSet, final int index) throws SQLException { | |
589 | final Blob blob = resultSet.getBlob(index); | |
590 | if (resultSet.wasNull()) { | |
591 | throw new SQLException("Assertion failed: result set value was expected to be non-null, " | |
592 | + "but was null."); | |
593 | } else { | |
594 | return blob.getBytes(1, (int) blob.length()); | |
595 | } | |
596 | } | |
597 | } | |
598 | ||
599 | /** | |
600 | * This class is a wrapper for type safe retrieval of values from a {@link ResultSet}. The values retrieved by the | |
601 | * {@link #getValue(java.sql.ResultSet, int)} implementation of this {@link DataType} are assured to be of type | |
602 | * {@link Integer} or to be <tt>null</tt> in case the {@link ResultSet} value was <tt>null</tt>. | |
603 | * <p/> | |
604 | * <p/> | |
605 | * The only instance of this class is available as value of the constant {@link DatabaseUtils#INTEGER_TYPE}. | |
606 | * | |
607 | * @author TCSDEVELOPER | |
608 | * @version 1.0 | |
609 | */ | |
610 | private static class IntegerType extends DataType { | |
611 | /** | |
612 | * This method retrieves the value at the given index from the given resultSet as instance of the | |
613 | * subclass-dependant type. | |
614 | * <p/> | |
615 | * | |
616 | * @param resultSet the result set from which to retrieve the value | |
617 | * @param index the index at which to retrieve the value | |
618 | * | |
619 | * @return the retrieved value as {@link Integer} or <tt>null</tt> if the value in the {@link ResultSet} was | |
620 | * <tt>null</tt>. | |
621 | * | |
622 | * @throws IllegalArgumentException in case given resultSet or columnType is <tt>null</tt> | |
623 | * @throws SQLException in case an exception occurs while working with the given ResultSet or the | |
624 | * index does not exist in the result set | |
625 | */ | |
626 | protected Object getValue(final ResultSet resultSet, final int index) throws SQLException { | |
627 | final int aInteger = resultSet.getInt(index); | |
628 | if (resultSet.wasNull()) { | |
629 | throw new SQLException("Assertion failed: result set value was expected to be non-null, " | |
630 | + "but was null."); | |
631 | } else { | |
632 | return new Integer(aInteger); | |
633 | } | |
634 | } | |
635 | } | |
636 | } |
this report was generated by version 1.0.5 of jcoverage. |
copyright © 2003, jcoverage ltd. all rights reserved. |