From f0a1ff2d762d0cc4aac176e1be55d8758f85db0e Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Fri, 11 Jan 2013 21:55:57 +0100 Subject: [PATCH] JDBC parameter binding uses JDBC 3.0 ParameterMetaData (if available) for type determination Forward-ported from 3.1.2, with minor modifications for defensiveness against the JDBC driver. Issue: SPR-10084 --- .../core/PreparedStatementCreatorFactory.java | 14 +++---- .../jdbc/core/StatementCreatorUtils.java | 40 +++++++++++++------ 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/PreparedStatementCreatorFactory.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/PreparedStatementCreatorFactory.java index 7efe962c64..6ba84b72b8 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/PreparedStatementCreatorFactory.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/PreparedStatementCreatorFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -146,7 +146,7 @@ public class PreparedStatementCreatorFactory { * Return a new PreparedStatementSetter for the given parameters. * @param params list of parameters (may be {@code null}) */ - public PreparedStatementSetter newPreparedStatementSetter(List params) { + public PreparedStatementSetter newPreparedStatementSetter(List params) { return new PreparedStatementCreatorImpl(params != null ? params : Collections.emptyList()); } @@ -225,7 +225,7 @@ public class PreparedStatementCreatorFactory { } public PreparedStatement createPreparedStatement(Connection con) throws SQLException { - PreparedStatement ps = null; + PreparedStatement ps; if (generatedKeysColumnNames != null || returnGeneratedKeys) { try { if (generatedKeysColumnNames != null) { @@ -235,10 +235,10 @@ public class PreparedStatementCreatorFactory { ps = con.prepareStatement(this.actualSql, PreparedStatement.RETURN_GENERATED_KEYS); } } - catch (AbstractMethodError ex) { + catch (AbstractMethodError err) { throw new InvalidDataAccessResourceUsageException( - "The JDBC driver is not compliant to JDBC 3.0 and thus " + - "does not support retrieval of auto-generated keys", ex); + "Your JDBC driver is not compliant with JDBC 3.0 - " + + "it does not support retrieval of auto-generated keys", err); } } else if (resultSetType == ResultSet.TYPE_FORWARD_ONLY && !updatableResults) { @@ -263,7 +263,7 @@ public class PreparedStatementCreatorFactory { int sqlColIndx = 1; for (int i = 0; i < this.parameters.size(); i++) { Object in = this.parameters.get(i); - SqlParameter declaredParameter = null; + SqlParameter declaredParameter; // SqlParameterValue overrides declared parameter metadata, in particular for // independence from the declared parameter position in case of named parameters. if (in instanceof SqlParameterValue) { diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/StatementCreatorUtils.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/StatementCreatorUtils.java index 1e6a263ca4..ea8e74501e 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/StatementCreatorUtils.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/StatementCreatorUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2013 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. @@ -22,6 +22,7 @@ import java.math.BigInteger; import java.sql.Blob; import java.sql.Clob; import java.sql.DatabaseMetaData; +import java.sql.ParameterMetaData; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Types; @@ -189,7 +190,7 @@ public abstract class StatementCreatorUtils { if (inValue instanceof SqlParameterValue) { SqlParameterValue parameterValue = (SqlParameterValue) inValue; if (logger.isDebugEnabled()) { - logger.debug("Overriding typeinfo with runtime info from SqlParameterValue: column index " + paramIndex + + logger.debug("Overriding type info with runtime info from SqlParameterValue: column index " + paramIndex + ", SQL type " + parameterValue.getSqlType() + ", Type name " + parameterValue.getTypeName()); } @@ -228,18 +229,31 @@ public abstract class StatementCreatorUtils { boolean useSetObject = false; sqlType = Types.NULL; try { - DatabaseMetaData dbmd = ps.getConnection().getMetaData(); - String databaseProductName = dbmd.getDatabaseProductName(); - String jdbcDriverName = dbmd.getDriverName(); - if (databaseProductName.startsWith("Informix") || - jdbcDriverName.startsWith("Microsoft SQL Server")) { - useSetObject = true; + ParameterMetaData pmd = null; + try { + pmd = ps.getParameterMetaData(); } - else if (databaseProductName.startsWith("DB2") || - jdbcDriverName.startsWith("jConnect") || - jdbcDriverName.startsWith("SQLServer")|| - jdbcDriverName.startsWith("Apache Derby")) { - sqlType = Types.VARCHAR; + catch (Throwable ex) { + // JDBC driver not compliant with JDBC 3.0 + // -> proceed with database-specific checks + } + if (pmd != null) { + sqlType = pmd.getParameterType(paramIndex); + } + else { + DatabaseMetaData dbmd = ps.getConnection().getMetaData(); + String databaseProductName = dbmd.getDatabaseProductName(); + String jdbcDriverName = dbmd.getDriverName(); + if (databaseProductName.startsWith("Informix") || + jdbcDriverName.startsWith("Microsoft SQL Server")) { + useSetObject = true; + } + else if (databaseProductName.startsWith("DB2") || + jdbcDriverName.startsWith("jConnect") || + jdbcDriverName.startsWith("SQLServer")|| + jdbcDriverName.startsWith("Apache Derby")) { + sqlType = Types.VARCHAR; + } } } catch (Throwable ex) {