1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.jdbc.support;
18
19 import java.lang.reflect.InvocationTargetException;
20 import java.lang.reflect.Method;
21 import java.math.BigDecimal;
22 import java.sql.Blob;
23 import java.sql.Clob;
24 import java.sql.Connection;
25 import java.sql.DatabaseMetaData;
26 import java.sql.ResultSet;
27 import java.sql.ResultSetMetaData;
28 import java.sql.SQLException;
29 import java.sql.SQLFeatureNotSupportedException;
30 import java.sql.Statement;
31 import java.sql.Types;
32 import javax.sql.DataSource;
33
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36
37 import org.springframework.jdbc.CannotGetJdbcConnectionException;
38 import org.springframework.jdbc.datasource.DataSourceUtils;
39 import org.springframework.lang.UsesJava7;
40 import org.springframework.util.ClassUtils;
41
42
43
44
45
46
47
48
49 public abstract class JdbcUtils {
50
51
52
53
54
55 public static final int TYPE_UNKNOWN = Integer.MIN_VALUE;
56
57
58
59 private static final boolean getObjectWithTypeAvailable =
60 ClassUtils.hasMethod(ResultSet.class, "getObject", int.class, Class.class);
61
62 private static final Log logger = LogFactory.getLog(JdbcUtils.class);
63
64
65
66
67
68
69
70 public static void closeConnection(Connection con) {
71 if (con != null) {
72 try {
73 con.close();
74 }
75 catch (SQLException ex) {
76 logger.debug("Could not close JDBC Connection", ex);
77 }
78 catch (Throwable ex) {
79
80 logger.debug("Unexpected exception on closing JDBC Connection", ex);
81 }
82 }
83 }
84
85
86
87
88
89
90 public static void closeStatement(Statement stmt) {
91 if (stmt != null) {
92 try {
93 stmt.close();
94 }
95 catch (SQLException ex) {
96 logger.trace("Could not close JDBC Statement", ex);
97 }
98 catch (Throwable ex) {
99
100 logger.trace("Unexpected exception on closing JDBC Statement", ex);
101 }
102 }
103 }
104
105
106
107
108
109
110 public static void closeResultSet(ResultSet rs) {
111 if (rs != null) {
112 try {
113 rs.close();
114 }
115 catch (SQLException ex) {
116 logger.trace("Could not close JDBC ResultSet", ex);
117 }
118 catch (Throwable ex) {
119
120 logger.trace("Unexpected exception on closing JDBC ResultSet", ex);
121 }
122 }
123 }
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138 @UsesJava7
139 public static Object getResultSetValue(ResultSet rs, int index, Class<?> requiredType) throws SQLException {
140 if (requiredType == null) {
141 return getResultSetValue(rs, index);
142 }
143
144 Object value;
145
146
147 if (String.class.equals(requiredType)) {
148 return rs.getString(index);
149 }
150 else if (boolean.class.equals(requiredType) || Boolean.class.equals(requiredType)) {
151 value = rs.getBoolean(index);
152 }
153 else if (byte.class.equals(requiredType) || Byte.class.equals(requiredType)) {
154 value = rs.getByte(index);
155 }
156 else if (short.class.equals(requiredType) || Short.class.equals(requiredType)) {
157 value = rs.getShort(index);
158 }
159 else if (int.class.equals(requiredType) || Integer.class.equals(requiredType)) {
160 value = rs.getInt(index);
161 }
162 else if (long.class.equals(requiredType) || Long.class.equals(requiredType)) {
163 value = rs.getLong(index);
164 }
165 else if (float.class.equals(requiredType) || Float.class.equals(requiredType)) {
166 value = rs.getFloat(index);
167 }
168 else if (double.class.equals(requiredType) || Double.class.equals(requiredType) ||
169 Number.class.equals(requiredType)) {
170 value = rs.getDouble(index);
171 }
172 else if (BigDecimal.class.equals(requiredType)) {
173 return rs.getBigDecimal(index);
174 }
175 else if (java.sql.Date.class.equals(requiredType)) {
176 return rs.getDate(index);
177 }
178 else if (java.sql.Time.class.equals(requiredType)) {
179 return rs.getTime(index);
180 }
181 else if (java.sql.Timestamp.class.equals(requiredType) || java.util.Date.class.equals(requiredType)) {
182 return rs.getTimestamp(index);
183 }
184 else if (byte[].class.equals(requiredType)) {
185 return rs.getBytes(index);
186 }
187 else if (Blob.class.equals(requiredType)) {
188 return rs.getBlob(index);
189 }
190 else if (Clob.class.equals(requiredType)) {
191 return rs.getClob(index);
192 }
193 else {
194
195 if (getObjectWithTypeAvailable) {
196 try {
197 return rs.getObject(index, requiredType);
198 }
199 catch (AbstractMethodError err) {
200 logger.debug("JDBC driver does not implement JDBC 4.1 'getObject(int, Class)' method", err);
201 }
202 catch (SQLFeatureNotSupportedException ex) {
203 logger.debug("JDBC driver does not support JDBC 4.1 'getObject(int, Class)' method", ex);
204 }
205 catch (SQLException ex) {
206 logger.debug("JDBC driver has limited support for JDBC 4.1 'getObject(int, Class)' method", ex);
207 }
208 }
209
210 return getResultSetValue(rs, index);
211 }
212
213
214 return (rs.wasNull() ? null : value);
215 }
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235 public static Object getResultSetValue(ResultSet rs, int index) throws SQLException {
236 Object obj = rs.getObject(index);
237 String className = null;
238 if (obj != null) {
239 className = obj.getClass().getName();
240 }
241 if (obj instanceof Blob) {
242 Blob blob = (Blob) obj;
243 obj = blob.getBytes(1, (int) blob.length());
244 }
245 else if (obj instanceof Clob) {
246 Clob clob = (Clob) obj;
247 obj = clob.getSubString(1, (int) clob.length());
248 }
249 else if ("oracle.sql.TIMESTAMP".equals(className) || "oracle.sql.TIMESTAMPTZ".equals(className)) {
250 obj = rs.getTimestamp(index);
251 }
252 else if (className != null && className.startsWith("oracle.sql.DATE")) {
253 String metaDataClassName = rs.getMetaData().getColumnClassName(index);
254 if ("java.sql.Timestamp".equals(metaDataClassName) || "oracle.sql.TIMESTAMP".equals(metaDataClassName)) {
255 obj = rs.getTimestamp(index);
256 }
257 else {
258 obj = rs.getDate(index);
259 }
260 }
261 else if (obj != null && obj instanceof java.sql.Date) {
262 if ("java.sql.Timestamp".equals(rs.getMetaData().getColumnClassName(index))) {
263 obj = rs.getTimestamp(index);
264 }
265 }
266 return obj;
267 }
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284 public static Object extractDatabaseMetaData(DataSource dataSource, DatabaseMetaDataCallback action)
285 throws MetaDataAccessException {
286
287 Connection con = null;
288 try {
289 con = DataSourceUtils.getConnection(dataSource);
290 if (con == null) {
291
292 throw new MetaDataAccessException("Connection returned by DataSource [" + dataSource + "] was null");
293 }
294 DatabaseMetaData metaData = con.getMetaData();
295 if (metaData == null) {
296
297 throw new MetaDataAccessException("DatabaseMetaData returned by Connection [" + con + "] was null");
298 }
299 return action.processMetaData(metaData);
300 }
301 catch (CannotGetJdbcConnectionException ex) {
302 throw new MetaDataAccessException("Could not get Connection for extracting meta data", ex);
303 }
304 catch (SQLException ex) {
305 throw new MetaDataAccessException("Error while extracting DatabaseMetaData", ex);
306 }
307 catch (AbstractMethodError err) {
308 throw new MetaDataAccessException(
309 "JDBC DatabaseMetaData method not implemented by JDBC driver - upgrade your driver", err);
310 }
311 finally {
312 DataSourceUtils.releaseConnection(con, dataSource);
313 }
314 }
315
316
317
318
319
320
321
322
323
324
325
326 public static Object extractDatabaseMetaData(DataSource dataSource, final String metaDataMethodName)
327 throws MetaDataAccessException {
328
329 return extractDatabaseMetaData(dataSource,
330 new DatabaseMetaDataCallback() {
331 @Override
332 public Object processMetaData(DatabaseMetaData dbmd) throws SQLException, MetaDataAccessException {
333 try {
334 Method method = DatabaseMetaData.class.getMethod(metaDataMethodName, (Class[]) null);
335 return method.invoke(dbmd, (Object[]) null);
336 }
337 catch (NoSuchMethodException ex) {
338 throw new MetaDataAccessException("No method named '" + metaDataMethodName +
339 "' found on DatabaseMetaData instance [" + dbmd + "]", ex);
340 }
341 catch (IllegalAccessException ex) {
342 throw new MetaDataAccessException(
343 "Could not access DatabaseMetaData method '" + metaDataMethodName + "'", ex);
344 }
345 catch (InvocationTargetException ex) {
346 if (ex.getTargetException() instanceof SQLException) {
347 throw (SQLException) ex.getTargetException();
348 }
349 throw new MetaDataAccessException(
350 "Invocation of DatabaseMetaData method '" + metaDataMethodName + "' failed", ex);
351 }
352 }
353 });
354 }
355
356
357
358
359
360
361
362
363
364
365
366
367 public static boolean supportsBatchUpdates(Connection con) {
368 try {
369 DatabaseMetaData dbmd = con.getMetaData();
370 if (dbmd != null) {
371 if (dbmd.supportsBatchUpdates()) {
372 logger.debug("JDBC driver supports batch updates");
373 return true;
374 }
375 else {
376 logger.debug("JDBC driver does not support batch updates");
377 }
378 }
379 }
380 catch (SQLException ex) {
381 logger.debug("JDBC driver 'supportsBatchUpdates' method threw exception", ex);
382 }
383 return false;
384 }
385
386
387
388
389
390
391 public static String commonDatabaseName(String source) {
392 String name = source;
393 if (source != null && source.startsWith("DB2")) {
394 name = "DB2";
395 }
396 else if ("Sybase SQL Server".equals(source) ||
397 "Adaptive Server Enterprise".equals(source) ||
398 "ASE".equals(source) ||
399 "sql server".equalsIgnoreCase(source) ) {
400 name = "Sybase";
401 }
402 return name;
403 }
404
405
406
407
408
409
410 public static boolean isNumeric(int sqlType) {
411 return Types.BIT == sqlType || Types.BIGINT == sqlType || Types.DECIMAL == sqlType ||
412 Types.DOUBLE == sqlType || Types.FLOAT == sqlType || Types.INTEGER == sqlType ||
413 Types.NUMERIC == sqlType || Types.REAL == sqlType || Types.SMALLINT == sqlType ||
414 Types.TINYINT == sqlType;
415 }
416
417
418
419
420
421
422
423
424
425
426
427
428
429 public static String lookupColumnName(ResultSetMetaData resultSetMetaData, int columnIndex) throws SQLException {
430 String name = resultSetMetaData.getColumnLabel(columnIndex);
431 if (name == null || name.length() < 1) {
432 name = resultSetMetaData.getColumnName(columnIndex);
433 }
434 return name;
435 }
436
437
438
439
440
441
442
443 public static String convertUnderscoreNameToPropertyName(String name) {
444 StringBuilder result = new StringBuilder();
445 boolean nextIsUpper = false;
446 if (name != null && name.length() > 0) {
447 if (name.length() > 1 && name.substring(1,2).equals("_")) {
448 result.append(name.substring(0, 1).toUpperCase());
449 }
450 else {
451 result.append(name.substring(0, 1).toLowerCase());
452 }
453 for (int i = 1; i < name.length(); i++) {
454 String s = name.substring(i, i + 1);
455 if (s.equals("_")) {
456 nextIsUpper = true;
457 }
458 else {
459 if (nextIsUpper) {
460 result.append(s.toUpperCase());
461 nextIsUpper = false;
462 }
463 else {
464 result.append(s.toLowerCase());
465 }
466 }
467 }
468 }
469 return result.toString();
470 }
471
472 }