Skip to content

Commit 5ac7a32

Browse files
committed
Raise JDBC driver feature baseline to JDBC 4.0+
Issue: SPR-13826
1 parent d96a66a commit 5ac7a32

File tree

2 files changed

+42
-142
lines changed

2 files changed

+42
-142
lines changed

spring-jdbc/src/main/java/org/springframework/jdbc/core/StatementCreatorUtils.java

Lines changed: 21 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,12 @@
2525
import java.sql.DatabaseMetaData;
2626
import java.sql.PreparedStatement;
2727
import java.sql.SQLException;
28-
import java.sql.SQLFeatureNotSupportedException;
2928
import java.sql.Types;
3029
import java.util.Arrays;
3130
import java.util.Calendar;
3231
import java.util.Collection;
33-
import java.util.Collections;
3432
import java.util.HashMap;
3533
import java.util.Map;
36-
import java.util.Set;
37-
import java.util.concurrent.ConcurrentHashMap;
3834

3935
import org.apache.commons.logging.Log;
4036
import org.apache.commons.logging.LogFactory;
@@ -79,10 +75,7 @@ public abstract class StatementCreatorUtils {
7975
public static final String IGNORE_GETPARAMETERTYPE_PROPERTY_NAME = "spring.jdbc.getParameterType.ignore";
8076

8177

82-
static final boolean shouldIgnoreGetParameterType = SpringProperties.getFlag(IGNORE_GETPARAMETERTYPE_PROPERTY_NAME);
83-
84-
static final Set<String> driversWithNoSupportForGetParameterType =
85-
Collections.newSetFromMap(new ConcurrentHashMap<>(1));
78+
static boolean shouldIgnoreGetParameterType = SpringProperties.getFlag(IGNORE_GETPARAMETERTYPE_PROPERTY_NAME);
8679

8780
private static final Log logger = LogFactory.getLog(StatementCreatorUtils.class);
8881

@@ -244,61 +237,25 @@ private static void setNull(PreparedStatement ps, int paramIndex, int sqlType, S
244237
if (sqlType == SqlTypeValue.TYPE_UNKNOWN || sqlType == Types.OTHER) {
245238
boolean useSetObject = false;
246239
Integer sqlTypeToUse = null;
247-
DatabaseMetaData dbmd = null;
248-
String jdbcDriverName = null;
249-
boolean checkGetParameterType = !shouldIgnoreGetParameterType;
250-
if (checkGetParameterType && !driversWithNoSupportForGetParameterType.isEmpty()) {
251-
try {
252-
dbmd = ps.getConnection().getMetaData();
253-
jdbcDriverName = dbmd.getDriverName();
254-
checkGetParameterType = !driversWithNoSupportForGetParameterType.contains(jdbcDriverName);
255-
}
256-
catch (Throwable ex) {
257-
logger.debug("Could not check connection metadata", ex);
258-
}
259-
}
260-
if (checkGetParameterType) {
261-
try {
262-
sqlTypeToUse = ps.getParameterMetaData().getParameterType(paramIndex);
263-
}
264-
catch (Throwable ex) {
265-
if (logger.isDebugEnabled()) {
266-
logger.debug("JDBC 3.0 getParameterType call not supported - using fallback method instead: " + ex);
267-
}
268-
}
240+
if (!shouldIgnoreGetParameterType) {
241+
sqlTypeToUse = ps.getParameterMetaData().getParameterType(paramIndex);
269242
}
270243
if (sqlTypeToUse == null) {
271-
// JDBC driver not compliant with JDBC 3.0 -> proceed with database-specific checks
244+
// Proceed with database-specific checks
272245
sqlTypeToUse = Types.NULL;
273-
try {
274-
if (dbmd == null) {
275-
dbmd = ps.getConnection().getMetaData();
276-
}
277-
if (jdbcDriverName == null) {
278-
jdbcDriverName = dbmd.getDriverName();
279-
}
280-
if (checkGetParameterType &&
281-
!(jdbcDriverName.startsWith("Oracle") && dbmd.getDriverMajorVersion() >= 12)) {
282-
// Register JDBC driver with no support for getParameterType, except for the
283-
// Oracle 12c driver where getParameterType fails for specific statements only
284-
// (so an exception thrown above does not indicate general lack of support).
285-
driversWithNoSupportForGetParameterType.add(jdbcDriverName);
286-
}
287-
String databaseProductName = dbmd.getDatabaseProductName();
288-
if (databaseProductName.startsWith("Informix") ||
289-
(jdbcDriverName.startsWith("Microsoft") && jdbcDriverName.contains("SQL Server"))) {
290-
// "Microsoft SQL Server JDBC Driver 3.0" versus "Microsoft JDBC Driver 4.0 for SQL Server"
291-
useSetObject = true;
292-
}
293-
else if (databaseProductName.startsWith("DB2") ||
294-
jdbcDriverName.startsWith("jConnect") ||
295-
jdbcDriverName.startsWith("SQLServer")||
296-
jdbcDriverName.startsWith("Apache Derby")) {
297-
sqlTypeToUse = Types.VARCHAR;
298-
}
246+
DatabaseMetaData dbmd = ps.getConnection().getMetaData();
247+
String jdbcDriverName = dbmd.getDriverName();
248+
String databaseProductName = dbmd.getDatabaseProductName();
249+
if (databaseProductName.startsWith("Informix") ||
250+
(jdbcDriverName.startsWith("Microsoft") && jdbcDriverName.contains("SQL Server"))) {
251+
// "Microsoft SQL Server JDBC Driver 3.0" versus "Microsoft JDBC Driver 4.0 for SQL Server"
252+
useSetObject = true;
299253
}
300-
catch (Throwable ex) {
301-
logger.debug("Could not check connection metadata", ex);
254+
else if (databaseProductName.startsWith("DB2") ||
255+
jdbcDriverName.startsWith("jConnect") ||
256+
jdbcDriverName.startsWith("SQLServer")||
257+
jdbcDriverName.startsWith("Apache Derby")) {
258+
sqlTypeToUse = Types.VARCHAR;
302259
}
303260
}
304261
if (useSetObject) {
@@ -334,21 +291,13 @@ else if ((sqlType == Types.CLOB || sqlType == Types.NCLOB) && isStringValue(inVa
334291
if (strVal.length() > 4000) {
335292
// Necessary for older Oracle drivers, in particular when running against an Oracle 10 database.
336293
// Should also work fine against other drivers/databases since it uses standard JDBC 4.0 API.
337-
try {
338-
if (sqlType == Types.NCLOB) {
339-
ps.setNClob(paramIndex, new StringReader(strVal), strVal.length());
340-
}
341-
else {
342-
ps.setClob(paramIndex, new StringReader(strVal), strVal.length());
343-
}
344-
return;
294+
if (sqlType == Types.NCLOB) {
295+
ps.setNClob(paramIndex, new StringReader(strVal), strVal.length());
345296
}
346-
catch (AbstractMethodError err) {
347-
logger.debug("JDBC driver does not implement JDBC 4.0 'setClob(int, Reader, long)' method", err);
348-
}
349-
catch (SQLFeatureNotSupportedException ex) {
350-
logger.debug("JDBC driver does not support JDBC 4.0 'setClob(int, Reader, long)' method", ex);
297+
else {
298+
ps.setClob(paramIndex, new StringReader(strVal), strVal.length());
351299
}
300+
return;
352301
}
353302
// Fallback: regular setString binding
354303
ps.setString(paramIndex, strVal);

spring-jdbc/src/test/java/org/springframework/jdbc/core/StatementCreatorUtilsTests.java

Lines changed: 21 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -27,7 +27,6 @@
2727
import org.junit.Before;
2828
import org.junit.Test;
2929

30-
import static org.junit.Assert.*;
3130
import static org.mockito.BDDMockito.*;
3231

3332
/**
@@ -59,13 +58,21 @@ public void testSetParameterValueWithNullAndTypeName() throws SQLException {
5958

6059
@Test
6160
public void testSetParameterValueWithNullAndUnknownType() throws SQLException {
61+
StatementCreatorUtils.shouldIgnoreGetParameterType = true;
62+
Connection con = mock(Connection.class);
63+
DatabaseMetaData dbmd = mock(DatabaseMetaData.class);
64+
given(preparedStatement.getConnection()).willReturn(con);
65+
given(dbmd.getDatabaseProductName()).willReturn("Oracle");
66+
given(dbmd.getDriverName()).willReturn("Oracle Driver");
67+
given(con.getMetaData()).willReturn(dbmd);
6268
StatementCreatorUtils.setParameterValue(preparedStatement, 1, SqlTypeValue.TYPE_UNKNOWN, null, null);
6369
verify(preparedStatement).setNull(1, Types.NULL);
70+
StatementCreatorUtils.shouldIgnoreGetParameterType = false;
6471
}
6572

6673
@Test
6774
public void testSetParameterValueWithNullAndUnknownTypeOnInformix() throws SQLException {
68-
StatementCreatorUtils.driversWithNoSupportForGetParameterType.clear();
75+
StatementCreatorUtils.shouldIgnoreGetParameterType = true;
6976
Connection con = mock(Connection.class);
7077
DatabaseMetaData dbmd = mock(DatabaseMetaData.class);
7178
given(preparedStatement.getConnection()).willReturn(con);
@@ -76,12 +83,12 @@ public void testSetParameterValueWithNullAndUnknownTypeOnInformix() throws SQLEx
7683
verify(dbmd).getDatabaseProductName();
7784
verify(dbmd).getDriverName();
7885
verify(preparedStatement).setObject(1, null);
79-
assertEquals(1, StatementCreatorUtils.driversWithNoSupportForGetParameterType.size());
86+
StatementCreatorUtils.shouldIgnoreGetParameterType = false;
8087
}
8188

8289
@Test
8390
public void testSetParameterValueWithNullAndUnknownTypeOnDerbyEmbedded() throws SQLException {
84-
StatementCreatorUtils.driversWithNoSupportForGetParameterType.clear();
91+
StatementCreatorUtils.shouldIgnoreGetParameterType = true;
8592
Connection con = mock(Connection.class);
8693
DatabaseMetaData dbmd = mock(DatabaseMetaData.class);
8794
given(preparedStatement.getConnection()).willReturn(con);
@@ -92,82 +99,18 @@ public void testSetParameterValueWithNullAndUnknownTypeOnDerbyEmbedded() throws
9299
verify(dbmd).getDatabaseProductName();
93100
verify(dbmd).getDriverName();
94101
verify(preparedStatement).setNull(1, Types.VARCHAR);
95-
assertEquals(1, StatementCreatorUtils.driversWithNoSupportForGetParameterType.size());
102+
StatementCreatorUtils.shouldIgnoreGetParameterType = false;
96103
}
97104

98105
@Test
99106
public void testSetParameterValueWithNullAndGetParameterTypeWorking() throws SQLException {
100-
StatementCreatorUtils.driversWithNoSupportForGetParameterType.clear();
101107
ParameterMetaData pmd = mock(ParameterMetaData.class);
102108
given(preparedStatement.getParameterMetaData()).willReturn(pmd);
103109
given(pmd.getParameterType(1)).willReturn(Types.SMALLINT);
104110
StatementCreatorUtils.setParameterValue(preparedStatement, 1, SqlTypeValue.TYPE_UNKNOWN, null, null);
105111
verify(pmd).getParameterType(1);
106112
verify(preparedStatement, never()).getConnection();
107113
verify(preparedStatement).setNull(1, Types.SMALLINT);
108-
assertTrue(StatementCreatorUtils.driversWithNoSupportForGetParameterType.isEmpty());
109-
}
110-
111-
@Test
112-
public void testSetParameterValueWithNullAndGetParameterTypeWorkingButNotForOtherDriver() throws SQLException {
113-
StatementCreatorUtils.driversWithNoSupportForGetParameterType.clear();
114-
StatementCreatorUtils.driversWithNoSupportForGetParameterType.add("Oracle JDBC Driver");
115-
Connection con = mock(Connection.class);
116-
DatabaseMetaData dbmd = mock(DatabaseMetaData.class);
117-
ParameterMetaData pmd = mock(ParameterMetaData.class);
118-
given(preparedStatement.getConnection()).willReturn(con);
119-
given(con.getMetaData()).willReturn(dbmd);
120-
given(dbmd.getDriverName()).willReturn("Apache Derby Embedded Driver");
121-
given(preparedStatement.getParameterMetaData()).willReturn(pmd);
122-
given(pmd.getParameterType(1)).willReturn(Types.SMALLINT);
123-
StatementCreatorUtils.setParameterValue(preparedStatement, 1, SqlTypeValue.TYPE_UNKNOWN, null, null);
124-
verify(dbmd).getDriverName();
125-
verify(pmd).getParameterType(1);
126-
verify(preparedStatement).setNull(1, Types.SMALLINT);
127-
assertEquals(1, StatementCreatorUtils.driversWithNoSupportForGetParameterType.size());
128-
}
129-
130-
@Test
131-
public void testSetParameterValueWithNullAndUnknownTypeAndGetParameterTypeNotWorking() throws SQLException {
132-
StatementCreatorUtils.driversWithNoSupportForGetParameterType.clear();
133-
Connection con = mock(Connection.class);
134-
DatabaseMetaData dbmd = mock(DatabaseMetaData.class);
135-
given(preparedStatement.getConnection()).willReturn(con);
136-
given(con.getMetaData()).willReturn(dbmd);
137-
given(dbmd.getDatabaseProductName()).willReturn("Apache Derby");
138-
given(dbmd.getDriverName()).willReturn("Apache Derby Embedded Driver");
139-
StatementCreatorUtils.setParameterValue(preparedStatement, 1, SqlTypeValue.TYPE_UNKNOWN, null, null);
140-
verify(dbmd).getDatabaseProductName();
141-
verify(dbmd).getDriverName();
142-
verify(preparedStatement).setNull(1, Types.VARCHAR);
143-
assertEquals(1, StatementCreatorUtils.driversWithNoSupportForGetParameterType.size());
144-
145-
reset(preparedStatement, con, dbmd);
146-
ParameterMetaData pmd = mock(ParameterMetaData.class);
147-
given(preparedStatement.getConnection()).willReturn(con);
148-
given(con.getMetaData()).willReturn(dbmd);
149-
given(preparedStatement.getParameterMetaData()).willReturn(pmd);
150-
given(pmd.getParameterType(1)).willThrow(new SQLException("unsupported"));
151-
given(dbmd.getDatabaseProductName()).willReturn("Informix Dynamic Server");
152-
given(dbmd.getDriverName()).willReturn("Informix Driver");
153-
StatementCreatorUtils.setParameterValue(preparedStatement, 1, SqlTypeValue.TYPE_UNKNOWN, null, null);
154-
verify(pmd).getParameterType(1);
155-
verify(dbmd).getDatabaseProductName();
156-
verify(dbmd).getDriverName();
157-
verify(preparedStatement).setObject(1, null);
158-
assertEquals(2, StatementCreatorUtils.driversWithNoSupportForGetParameterType.size());
159-
160-
reset(preparedStatement, con, dbmd, pmd);
161-
given(preparedStatement.getConnection()).willReturn(con);
162-
given(con.getMetaData()).willReturn(dbmd);
163-
given(dbmd.getDatabaseProductName()).willReturn("Informix Dynamic Server");
164-
given(dbmd.getDriverName()).willReturn("Informix Driver");
165-
StatementCreatorUtils.setParameterValue(preparedStatement, 1, SqlTypeValue.TYPE_UNKNOWN, null, null);
166-
verify(preparedStatement, never()).getParameterMetaData();
167-
verify(dbmd).getDatabaseProductName();
168-
verify(dbmd).getDriverName();
169-
verify(preparedStatement).setObject(1, null);
170-
assertEquals(2, StatementCreatorUtils.driversWithNoSupportForGetParameterType.size());
171114
}
172115

173116
@Test
@@ -277,8 +220,16 @@ public void testSetParameterValueWithStringAndVendorSpecificType() throws SQLExc
277220

278221
@Test // SPR-8571
279222
public void testSetParameterValueWithNullAndVendorSpecificType() throws SQLException {
223+
StatementCreatorUtils.shouldIgnoreGetParameterType = true;
224+
Connection con = mock(Connection.class);
225+
DatabaseMetaData dbmd = mock(DatabaseMetaData.class);
226+
given(preparedStatement.getConnection()).willReturn(con);
227+
given(dbmd.getDatabaseProductName()).willReturn("Oracle");
228+
given(dbmd.getDriverName()).willReturn("Oracle Driver");
229+
given(con.getMetaData()).willReturn(dbmd);
280230
StatementCreatorUtils.setParameterValue(preparedStatement, 1, Types.OTHER, null, null);
281231
verify(preparedStatement).setNull(1, Types.NULL);
232+
StatementCreatorUtils.shouldIgnoreGetParameterType = false;
282233
}
283234

284235
}

0 commit comments

Comments
 (0)