added support to SimpleJdbcInsert for including synonyms when table metadata is retrieved; this only applies to Oracle (SPR-4782)

This commit is contained in:
Thomas Risberg 2009-06-11 20:54:09 +00:00
parent 1d6a3e5360
commit f70d14e2c2
7 changed files with 178 additions and 15 deletions

View File

@ -361,7 +361,7 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
}
}
catch (SQLException se) {
logger.warn("Error while retreiving metadata for procedure columns: " + se.getMessage());
logger.warn("Error while retreiving metadata for table columns: " + se.getMessage());
}
finally {
try {
@ -369,7 +369,7 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
tableColumns.close();
}
catch (SQLException se) {
logger.warn("Problem closing resultset for procedure column metadata " + se.getMessage());
logger.warn("Problem closing resultset for table column metadata " + se.getMessage());
}
}

View File

@ -0,0 +1,104 @@
/*
* Copyright 2002-2007 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.jdbc.core.metadata;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.sql.Connection;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
/**
* The Oracle specific implementation of the {@link org.springframework.jdbc.core.metadata.TableMetaDataProvider}.
* Supports a feature for including synonyms in the metadata lookup.
*
* @author Thomas Risberg
* @since 3.0
*/
public class OracleTableMetaDataProvider extends GenericTableMetaDataProvider {
private boolean includeSynonyms;
public OracleTableMetaDataProvider(DatabaseMetaData databaseMetaData) throws SQLException {
this(databaseMetaData, false);
}
public OracleTableMetaDataProvider(DatabaseMetaData databaseMetaData, boolean includeSynonyms) throws SQLException {
super(databaseMetaData);
this.includeSynonyms = includeSynonyms;
}
@Override
public void initializeWithTableColumnMetaData(DatabaseMetaData databaseMetaData,
String catalogName, String schemaName, String tableName) throws SQLException {
Connection con = databaseMetaData.getConnection();
Method methodToInvoke = null;
Boolean origValueForIncludeSynonyms = null;
if (includeSynonyms) {
if (con.getClass().getName().startsWith("oracle")) {
if (logger.isDebugEnabled()) {
logger.debug("Including synonyms in table metadata lookup.");
}
}
else {
logger.warn("Unable to include synonyms in table metadata lookup. Connection used for " +
"DatabaseMetaData is not recognized as an Oracle connection; " +
"class is " + con.getClass().getName());
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Defaulting to no synonyms in table metadata lookup.");
}
}
if (includeSynonyms && con.getClass().getName().startsWith("oracle")) {
try {
methodToInvoke = con.getClass().getMethod("getIncludeSynonyms", (Class[]) null);
methodToInvoke.setAccessible(true);
origValueForIncludeSynonyms = (Boolean)methodToInvoke.invoke(con);
methodToInvoke = con.getClass().getMethod("setIncludeSynonyms", new Class[] {boolean.class});
methodToInvoke.setAccessible(true);
methodToInvoke.invoke(con, Boolean.TRUE);
}
catch (Exception ex) {
throw new InvalidDataAccessApiUsageException(
"Couldn't initialize Oracle Connection.", ex);
}
}
super.initializeWithTableColumnMetaData(databaseMetaData, catalogName, schemaName, tableName);
if (includeSynonyms && con.getClass().getName().startsWith("oracle")) {
try {
methodToInvoke = con.getClass().getMethod("setIncludeSynonyms", new Class[] {boolean.class});
methodToInvoke.setAccessible(true);
methodToInvoke.invoke(con, origValueForIncludeSynonyms);
}
catch (Exception ex) {
throw new InvalidDataAccessApiUsageException(
"Couldn't restore Oracle Connection.", ex);
}
}
}
}

View File

@ -30,8 +30,6 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.jdbc.core.SqlTypeValue;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils;
import org.springframework.jdbc.support.JdbcUtils;
@ -61,15 +59,17 @@ public class TableMetaDataContext {
private List<String> tableColumns = new ArrayList<String>();
/** should we access insert parameter meta data info or not */
private boolean accessTableParameterMetaData = true;
private boolean accessTableColumnMetaData = true;
/** the provider of call meta data */
/** should we override default for including synonyms for meta data lookups */
private boolean overrideIncludeSynonymsDefault = false;
/** the provider of table meta data */
private TableMetaDataProvider metaDataProvider;
/** are we using generated key columns */
private boolean generatedKeyColumnsUsed = false;
/**
* Set the name of the table for this context.
*/
@ -115,18 +115,32 @@ public class TableMetaDataContext {
/**
* Specify whether we should access table column meta data.
*/
public void setAccessTableParameterMetaData(boolean accessTableParameterMetaData) {
this.accessTableParameterMetaData = accessTableParameterMetaData;
public void setAccessTableColumnMetaData(boolean accessTableColumnMetaData) {
this.accessTableColumnMetaData = accessTableColumnMetaData;
}
/**
* Are we accessing table meta data?
*/
public boolean isAccessTableParameterMetaData() {
return this.accessTableParameterMetaData;
public boolean isAccessTableColumnMetaData() {
return this.accessTableColumnMetaData;
}
/**
* Specify whether we should override default for accessing synonyms.
*/
public void setOverrideIncludeSynonymsDefault(boolean override) {
this.overrideIncludeSynonymsDefault = override;
}
/**
* Are we overrding include synonyms default?
*/
public boolean isOverrideIncludeSynonymsDefault() {
return this.overrideIncludeSynonymsDefault;
}
/**
* Get a List of the table column names.
*/

View File

@ -54,10 +54,15 @@ public class TableMetaDataProviderFactory {
public Object processMetaData(DatabaseMetaData databaseMetaData)
throws SQLException, MetaDataAccessException {
String databaseProductName = JdbcUtils.commonDatabaseName(databaseMetaData.getDatabaseProductName());
boolean accessTableColumnMetaData = context.isAccessTableParameterMetaData();
String databaseProductName =
JdbcUtils.commonDatabaseName(databaseMetaData.getDatabaseProductName());
boolean accessTableColumnMetaData = context.isAccessTableColumnMetaData();
TableMetaDataProvider provider;
if ("HSQL Database Engine".equals(databaseProductName)) {
if ("Oracle".equals(databaseProductName)) {
provider = new OracleTableMetaDataProvider(databaseMetaData,
context.isOverrideIncludeSynonymsDefault());
}
else if ("HSQL Database Engine".equals(databaseProductName)) {
provider = new HsqlTableMetaDataProvider(databaseMetaData);
}
else if ("PostgreSQL".equals(databaseProductName)) {
@ -74,7 +79,8 @@ public class TableMetaDataProviderFactory {
}
provider.initializeWithMetaData(databaseMetaData);
if (accessTableColumnMetaData) {
provider.initializeWithTableColumnMetaData(databaseMetaData, context.getCatalogName(), context.getSchemaName(), context.getTableName());
provider.initializeWithTableColumnMetaData(databaseMetaData, context.getCatalogName(),
context.getSchemaName(), context.getTableName());
}
return provider;
}

View File

@ -192,6 +192,20 @@ public abstract class AbstractJdbcInsert {
this.generatedKeyNames = new String[] {generatedKeyName};
}
/**
* Specify whether the parameter metadata for the call should be used. The default is true.
*/
public void setAccessTableColumnMetaData(boolean accessTableColumnMetaData) {
this.tableMetaDataContext.setAccessTableColumnMetaData(accessTableColumnMetaData);
}
/**
* Specify whether the default for including synonyms should be changed. The default is false.
*/
public void setOverrideIncludeSynonymsDefault(boolean override) {
this.tableMetaDataContext.setOverrideIncludeSynonymsDefault(override);
}
/**
* Get the insert string to be used
*/

View File

@ -94,6 +94,16 @@ public class SimpleJdbcInsert extends AbstractJdbcInsert implements SimpleJdbcIn
return this;
}
public SimpleJdbcInsertOperations withoutTableColumnMetaDataAccess() {
setAccessTableColumnMetaData(false);
return this;
}
public SimpleJdbcInsertOperations includeSynonymsForTableColumnMetaData() {
setOverrideIncludeSynonymsDefault(true);
return this;
}
public int execute(Map<String, Object> args) {
return doExecute(args);
}

View File

@ -66,6 +66,21 @@ public interface SimpleJdbcInsertOperations {
*/
SimpleJdbcInsertOperations usingGeneratedKeyColumns(String... columnNames);
/**
* Turn off any processing of column meta data information obtained via JDBC.
* @return the instance of this SimpleJdbcInsert
*/
SimpleJdbcInsertOperations withoutTableColumnMetaDataAccess();
/**
* Include synonyms for the column meta data lookups via JDBC.
* Note: this is only necessary to include for Oracle since other
* databases supporting synonyms seems to include the synonyms
* automatically.
* @return the instance of this SimpleJdbcInsert
*/
SimpleJdbcInsertOperations includeSynonymsForTableColumnMetaData();
/**
* Execute the insert using the values passed in.