Raise JDBC driver feature baseline to JDBC 4.0+
Issue: SPR-13826
This commit is contained in:
parent
d96a66ae8f
commit
5ac7a32c8a
|
|
@ -25,16 +25,12 @@ import java.sql.Clob;
|
|||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.sql.Types;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
|
@ -79,10 +75,7 @@ public abstract class StatementCreatorUtils {
|
|||
public static final String IGNORE_GETPARAMETERTYPE_PROPERTY_NAME = "spring.jdbc.getParameterType.ignore";
|
||||
|
||||
|
||||
static final boolean shouldIgnoreGetParameterType = SpringProperties.getFlag(IGNORE_GETPARAMETERTYPE_PROPERTY_NAME);
|
||||
|
||||
static final Set<String> driversWithNoSupportForGetParameterType =
|
||||
Collections.newSetFromMap(new ConcurrentHashMap<>(1));
|
||||
static boolean shouldIgnoreGetParameterType = SpringProperties.getFlag(IGNORE_GETPARAMETERTYPE_PROPERTY_NAME);
|
||||
|
||||
private static final Log logger = LogFactory.getLog(StatementCreatorUtils.class);
|
||||
|
||||
|
|
@ -244,61 +237,25 @@ public abstract class StatementCreatorUtils {
|
|||
if (sqlType == SqlTypeValue.TYPE_UNKNOWN || sqlType == Types.OTHER) {
|
||||
boolean useSetObject = false;
|
||||
Integer sqlTypeToUse = null;
|
||||
DatabaseMetaData dbmd = null;
|
||||
String jdbcDriverName = null;
|
||||
boolean checkGetParameterType = !shouldIgnoreGetParameterType;
|
||||
if (checkGetParameterType && !driversWithNoSupportForGetParameterType.isEmpty()) {
|
||||
try {
|
||||
dbmd = ps.getConnection().getMetaData();
|
||||
jdbcDriverName = dbmd.getDriverName();
|
||||
checkGetParameterType = !driversWithNoSupportForGetParameterType.contains(jdbcDriverName);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.debug("Could not check connection metadata", ex);
|
||||
}
|
||||
}
|
||||
if (checkGetParameterType) {
|
||||
try {
|
||||
sqlTypeToUse = ps.getParameterMetaData().getParameterType(paramIndex);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("JDBC 3.0 getParameterType call not supported - using fallback method instead: " + ex);
|
||||
}
|
||||
}
|
||||
if (!shouldIgnoreGetParameterType) {
|
||||
sqlTypeToUse = ps.getParameterMetaData().getParameterType(paramIndex);
|
||||
}
|
||||
if (sqlTypeToUse == null) {
|
||||
// JDBC driver not compliant with JDBC 3.0 -> proceed with database-specific checks
|
||||
// Proceed with database-specific checks
|
||||
sqlTypeToUse = Types.NULL;
|
||||
try {
|
||||
if (dbmd == null) {
|
||||
dbmd = ps.getConnection().getMetaData();
|
||||
}
|
||||
if (jdbcDriverName == null) {
|
||||
jdbcDriverName = dbmd.getDriverName();
|
||||
}
|
||||
if (checkGetParameterType &&
|
||||
!(jdbcDriverName.startsWith("Oracle") && dbmd.getDriverMajorVersion() >= 12)) {
|
||||
// Register JDBC driver with no support for getParameterType, except for the
|
||||
// Oracle 12c driver where getParameterType fails for specific statements only
|
||||
// (so an exception thrown above does not indicate general lack of support).
|
||||
driversWithNoSupportForGetParameterType.add(jdbcDriverName);
|
||||
}
|
||||
String databaseProductName = dbmd.getDatabaseProductName();
|
||||
if (databaseProductName.startsWith("Informix") ||
|
||||
(jdbcDriverName.startsWith("Microsoft") && jdbcDriverName.contains("SQL Server"))) {
|
||||
// "Microsoft SQL Server JDBC Driver 3.0" versus "Microsoft JDBC Driver 4.0 for SQL Server"
|
||||
useSetObject = true;
|
||||
}
|
||||
else if (databaseProductName.startsWith("DB2") ||
|
||||
jdbcDriverName.startsWith("jConnect") ||
|
||||
jdbcDriverName.startsWith("SQLServer")||
|
||||
jdbcDriverName.startsWith("Apache Derby")) {
|
||||
sqlTypeToUse = Types.VARCHAR;
|
||||
}
|
||||
DatabaseMetaData dbmd = ps.getConnection().getMetaData();
|
||||
String jdbcDriverName = dbmd.getDriverName();
|
||||
String databaseProductName = dbmd.getDatabaseProductName();
|
||||
if (databaseProductName.startsWith("Informix") ||
|
||||
(jdbcDriverName.startsWith("Microsoft") && jdbcDriverName.contains("SQL Server"))) {
|
||||
// "Microsoft SQL Server JDBC Driver 3.0" versus "Microsoft JDBC Driver 4.0 for SQL Server"
|
||||
useSetObject = true;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
logger.debug("Could not check connection metadata", ex);
|
||||
else if (databaseProductName.startsWith("DB2") ||
|
||||
jdbcDriverName.startsWith("jConnect") ||
|
||||
jdbcDriverName.startsWith("SQLServer")||
|
||||
jdbcDriverName.startsWith("Apache Derby")) {
|
||||
sqlTypeToUse = Types.VARCHAR;
|
||||
}
|
||||
}
|
||||
if (useSetObject) {
|
||||
|
|
@ -334,21 +291,13 @@ public abstract class StatementCreatorUtils {
|
|||
if (strVal.length() > 4000) {
|
||||
// Necessary for older Oracle drivers, in particular when running against an Oracle 10 database.
|
||||
// Should also work fine against other drivers/databases since it uses standard JDBC 4.0 API.
|
||||
try {
|
||||
if (sqlType == Types.NCLOB) {
|
||||
ps.setNClob(paramIndex, new StringReader(strVal), strVal.length());
|
||||
}
|
||||
else {
|
||||
ps.setClob(paramIndex, new StringReader(strVal), strVal.length());
|
||||
}
|
||||
return;
|
||||
if (sqlType == Types.NCLOB) {
|
||||
ps.setNClob(paramIndex, new StringReader(strVal), strVal.length());
|
||||
}
|
||||
catch (AbstractMethodError err) {
|
||||
logger.debug("JDBC driver does not implement JDBC 4.0 'setClob(int, Reader, long)' method", err);
|
||||
}
|
||||
catch (SQLFeatureNotSupportedException ex) {
|
||||
logger.debug("JDBC driver does not support JDBC 4.0 'setClob(int, Reader, long)' method", ex);
|
||||
else {
|
||||
ps.setClob(paramIndex, new StringReader(strVal), strVal.length());
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Fallback: regular setString binding
|
||||
ps.setString(paramIndex, strVal);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -27,7 +27,6 @@ import java.util.GregorianCalendar;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.BDDMockito.*;
|
||||
|
||||
/**
|
||||
|
|
@ -59,13 +58,21 @@ public class StatementCreatorUtilsTests {
|
|||
|
||||
@Test
|
||||
public void testSetParameterValueWithNullAndUnknownType() throws SQLException {
|
||||
StatementCreatorUtils.shouldIgnoreGetParameterType = true;
|
||||
Connection con = mock(Connection.class);
|
||||
DatabaseMetaData dbmd = mock(DatabaseMetaData.class);
|
||||
given(preparedStatement.getConnection()).willReturn(con);
|
||||
given(dbmd.getDatabaseProductName()).willReturn("Oracle");
|
||||
given(dbmd.getDriverName()).willReturn("Oracle Driver");
|
||||
given(con.getMetaData()).willReturn(dbmd);
|
||||
StatementCreatorUtils.setParameterValue(preparedStatement, 1, SqlTypeValue.TYPE_UNKNOWN, null, null);
|
||||
verify(preparedStatement).setNull(1, Types.NULL);
|
||||
StatementCreatorUtils.shouldIgnoreGetParameterType = false;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetParameterValueWithNullAndUnknownTypeOnInformix() throws SQLException {
|
||||
StatementCreatorUtils.driversWithNoSupportForGetParameterType.clear();
|
||||
StatementCreatorUtils.shouldIgnoreGetParameterType = true;
|
||||
Connection con = mock(Connection.class);
|
||||
DatabaseMetaData dbmd = mock(DatabaseMetaData.class);
|
||||
given(preparedStatement.getConnection()).willReturn(con);
|
||||
|
|
@ -76,12 +83,12 @@ public class StatementCreatorUtilsTests {
|
|||
verify(dbmd).getDatabaseProductName();
|
||||
verify(dbmd).getDriverName();
|
||||
verify(preparedStatement).setObject(1, null);
|
||||
assertEquals(1, StatementCreatorUtils.driversWithNoSupportForGetParameterType.size());
|
||||
StatementCreatorUtils.shouldIgnoreGetParameterType = false;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetParameterValueWithNullAndUnknownTypeOnDerbyEmbedded() throws SQLException {
|
||||
StatementCreatorUtils.driversWithNoSupportForGetParameterType.clear();
|
||||
StatementCreatorUtils.shouldIgnoreGetParameterType = true;
|
||||
Connection con = mock(Connection.class);
|
||||
DatabaseMetaData dbmd = mock(DatabaseMetaData.class);
|
||||
given(preparedStatement.getConnection()).willReturn(con);
|
||||
|
|
@ -92,12 +99,11 @@ public class StatementCreatorUtilsTests {
|
|||
verify(dbmd).getDatabaseProductName();
|
||||
verify(dbmd).getDriverName();
|
||||
verify(preparedStatement).setNull(1, Types.VARCHAR);
|
||||
assertEquals(1, StatementCreatorUtils.driversWithNoSupportForGetParameterType.size());
|
||||
StatementCreatorUtils.shouldIgnoreGetParameterType = false;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetParameterValueWithNullAndGetParameterTypeWorking() throws SQLException {
|
||||
StatementCreatorUtils.driversWithNoSupportForGetParameterType.clear();
|
||||
ParameterMetaData pmd = mock(ParameterMetaData.class);
|
||||
given(preparedStatement.getParameterMetaData()).willReturn(pmd);
|
||||
given(pmd.getParameterType(1)).willReturn(Types.SMALLINT);
|
||||
|
|
@ -105,69 +111,6 @@ public class StatementCreatorUtilsTests {
|
|||
verify(pmd).getParameterType(1);
|
||||
verify(preparedStatement, never()).getConnection();
|
||||
verify(preparedStatement).setNull(1, Types.SMALLINT);
|
||||
assertTrue(StatementCreatorUtils.driversWithNoSupportForGetParameterType.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetParameterValueWithNullAndGetParameterTypeWorkingButNotForOtherDriver() throws SQLException {
|
||||
StatementCreatorUtils.driversWithNoSupportForGetParameterType.clear();
|
||||
StatementCreatorUtils.driversWithNoSupportForGetParameterType.add("Oracle JDBC Driver");
|
||||
Connection con = mock(Connection.class);
|
||||
DatabaseMetaData dbmd = mock(DatabaseMetaData.class);
|
||||
ParameterMetaData pmd = mock(ParameterMetaData.class);
|
||||
given(preparedStatement.getConnection()).willReturn(con);
|
||||
given(con.getMetaData()).willReturn(dbmd);
|
||||
given(dbmd.getDriverName()).willReturn("Apache Derby Embedded Driver");
|
||||
given(preparedStatement.getParameterMetaData()).willReturn(pmd);
|
||||
given(pmd.getParameterType(1)).willReturn(Types.SMALLINT);
|
||||
StatementCreatorUtils.setParameterValue(preparedStatement, 1, SqlTypeValue.TYPE_UNKNOWN, null, null);
|
||||
verify(dbmd).getDriverName();
|
||||
verify(pmd).getParameterType(1);
|
||||
verify(preparedStatement).setNull(1, Types.SMALLINT);
|
||||
assertEquals(1, StatementCreatorUtils.driversWithNoSupportForGetParameterType.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetParameterValueWithNullAndUnknownTypeAndGetParameterTypeNotWorking() throws SQLException {
|
||||
StatementCreatorUtils.driversWithNoSupportForGetParameterType.clear();
|
||||
Connection con = mock(Connection.class);
|
||||
DatabaseMetaData dbmd = mock(DatabaseMetaData.class);
|
||||
given(preparedStatement.getConnection()).willReturn(con);
|
||||
given(con.getMetaData()).willReturn(dbmd);
|
||||
given(dbmd.getDatabaseProductName()).willReturn("Apache Derby");
|
||||
given(dbmd.getDriverName()).willReturn("Apache Derby Embedded Driver");
|
||||
StatementCreatorUtils.setParameterValue(preparedStatement, 1, SqlTypeValue.TYPE_UNKNOWN, null, null);
|
||||
verify(dbmd).getDatabaseProductName();
|
||||
verify(dbmd).getDriverName();
|
||||
verify(preparedStatement).setNull(1, Types.VARCHAR);
|
||||
assertEquals(1, StatementCreatorUtils.driversWithNoSupportForGetParameterType.size());
|
||||
|
||||
reset(preparedStatement, con, dbmd);
|
||||
ParameterMetaData pmd = mock(ParameterMetaData.class);
|
||||
given(preparedStatement.getConnection()).willReturn(con);
|
||||
given(con.getMetaData()).willReturn(dbmd);
|
||||
given(preparedStatement.getParameterMetaData()).willReturn(pmd);
|
||||
given(pmd.getParameterType(1)).willThrow(new SQLException("unsupported"));
|
||||
given(dbmd.getDatabaseProductName()).willReturn("Informix Dynamic Server");
|
||||
given(dbmd.getDriverName()).willReturn("Informix Driver");
|
||||
StatementCreatorUtils.setParameterValue(preparedStatement, 1, SqlTypeValue.TYPE_UNKNOWN, null, null);
|
||||
verify(pmd).getParameterType(1);
|
||||
verify(dbmd).getDatabaseProductName();
|
||||
verify(dbmd).getDriverName();
|
||||
verify(preparedStatement).setObject(1, null);
|
||||
assertEquals(2, StatementCreatorUtils.driversWithNoSupportForGetParameterType.size());
|
||||
|
||||
reset(preparedStatement, con, dbmd, pmd);
|
||||
given(preparedStatement.getConnection()).willReturn(con);
|
||||
given(con.getMetaData()).willReturn(dbmd);
|
||||
given(dbmd.getDatabaseProductName()).willReturn("Informix Dynamic Server");
|
||||
given(dbmd.getDriverName()).willReturn("Informix Driver");
|
||||
StatementCreatorUtils.setParameterValue(preparedStatement, 1, SqlTypeValue.TYPE_UNKNOWN, null, null);
|
||||
verify(preparedStatement, never()).getParameterMetaData();
|
||||
verify(dbmd).getDatabaseProductName();
|
||||
verify(dbmd).getDriverName();
|
||||
verify(preparedStatement).setObject(1, null);
|
||||
assertEquals(2, StatementCreatorUtils.driversWithNoSupportForGetParameterType.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -277,8 +220,16 @@ public class StatementCreatorUtilsTests {
|
|||
|
||||
@Test // SPR-8571
|
||||
public void testSetParameterValueWithNullAndVendorSpecificType() throws SQLException {
|
||||
StatementCreatorUtils.shouldIgnoreGetParameterType = true;
|
||||
Connection con = mock(Connection.class);
|
||||
DatabaseMetaData dbmd = mock(DatabaseMetaData.class);
|
||||
given(preparedStatement.getConnection()).willReturn(con);
|
||||
given(dbmd.getDatabaseProductName()).willReturn("Oracle");
|
||||
given(dbmd.getDriverName()).willReturn("Oracle Driver");
|
||||
given(con.getMetaData()).willReturn(dbmd);
|
||||
StatementCreatorUtils.setParameterValue(preparedStatement, 1, Types.OTHER, null, null);
|
||||
verify(preparedStatement).setNull(1, Types.NULL);
|
||||
StatementCreatorUtils.shouldIgnoreGetParameterType = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue