revised OracleTableMetaDataProvider for reliable Oracle Connection detection; autodetect JdbcTemplate's NativeJdbcExtractor (SPR-7611)
This commit is contained in:
parent
1f1577e33e
commit
0f924820e8
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2010 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.
|
||||
|
@ -33,8 +33,8 @@ import org.springframework.dao.DataAccessResourceFailureException;
|
|||
import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor;
|
||||
|
||||
/**
|
||||
* A generic implementation of the {@link TableMetaDataProvider} that should provide enough features for all supported
|
||||
* databases.
|
||||
* A generic implementation of the {@link TableMetaDataProvider} that should provide
|
||||
* enough features for all supported databases.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.5
|
||||
|
@ -67,30 +67,23 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
|||
|
||||
/** database products we know not supporting the use of a String[] for generated keys */
|
||||
private List productsNotSupportingGeneratedKeysColumnNameArray =
|
||||
Arrays.asList(new String[] {"Apache Derby", "HSQL Database Engine"});
|
||||
Arrays.asList("Apache Derby", "HSQL Database Engine");
|
||||
|
||||
/** Collection of TableParameterMetaData objects */
|
||||
private List<TableParameterMetaData> insertParameterMetaData = new ArrayList<TableParameterMetaData>();
|
||||
|
||||
/** NativeJdbcExtractor that can be used to retrieve the native connection */
|
||||
protected NativeJdbcExtractor nativeJdbcExtractor = null;
|
||||
private NativeJdbcExtractor nativeJdbcExtractor;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor used to initialize with provided database meta data.
|
||||
* @param databaseMetaData meta data to be used
|
||||
* @throws SQLException
|
||||
*/
|
||||
protected GenericTableMetaDataProvider(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
userName = databaseMetaData.getUserName();
|
||||
this.userName = databaseMetaData.getUserName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether identifiers use upper case
|
||||
*/
|
||||
public boolean isStoresUpperCaseIdentifiers() {
|
||||
return storesUpperCaseIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether identifiers use upper case
|
||||
|
@ -100,29 +93,36 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get whether identifiers use lower case
|
||||
* Get whether identifiers use upper case
|
||||
*/
|
||||
public boolean isStoresLowerCaseIdentifiers() {
|
||||
return storesLowerCaseIdentifiers;
|
||||
public boolean isStoresUpperCaseIdentifiers() {
|
||||
return this.storesUpperCaseIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether identifiers use lower case
|
||||
* Specify whether identifiers use lower case.
|
||||
*/
|
||||
public void setStoresLowerCaseIdentifiers(boolean storesLowerCaseIdentifiers) {
|
||||
this.storesLowerCaseIdentifiers = storesLowerCaseIdentifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether identifiers use lower case
|
||||
*/
|
||||
public boolean isStoresLowerCaseIdentifiers() {
|
||||
return this.storesLowerCaseIdentifiers;
|
||||
}
|
||||
|
||||
public boolean isTableColumnMetaDataUsed() {
|
||||
return tableColumnMetaDataUsed;
|
||||
return this.tableColumnMetaDataUsed;
|
||||
}
|
||||
|
||||
public List<TableParameterMetaData> getTableParameterMetaData() {
|
||||
return insertParameterMetaData;
|
||||
return this.insertParameterMetaData;
|
||||
}
|
||||
|
||||
public boolean isGetGeneratedKeysSupported() {
|
||||
return getGeneratedKeysSupported;
|
||||
return this.getGeneratedKeysSupported;
|
||||
}
|
||||
|
||||
public boolean isGetGeneratedKeysSimulated(){
|
||||
|
@ -140,10 +140,6 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
|||
this.getGeneratedKeysSupported = getGeneratedKeysSupported;
|
||||
}
|
||||
|
||||
public boolean isGeneratedKeysColumnNameArraySupported() {
|
||||
return generatedKeysColumnNameArraySupported;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether a column name array is supported for generated keys
|
||||
*/
|
||||
|
@ -151,12 +147,20 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
|||
this.generatedKeysColumnNameArraySupported = generatedKeysColumnNameArraySupported;
|
||||
}
|
||||
|
||||
public boolean isGeneratedKeysColumnNameArraySupported() {
|
||||
return this.generatedKeysColumnNameArraySupported;
|
||||
}
|
||||
|
||||
public void setNativeJdbcExtractor(NativeJdbcExtractor nativeJdbcExtractor) {
|
||||
this.nativeJdbcExtractor = nativeJdbcExtractor;
|
||||
}
|
||||
|
||||
public void initializeWithMetaData(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
protected NativeJdbcExtractor getNativeJdbcExtractor() {
|
||||
return this.nativeJdbcExtractor;
|
||||
}
|
||||
|
||||
|
||||
public void initializeWithMetaData(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
try {
|
||||
if (databaseMetaData.supportsGetGeneratedKeys()) {
|
||||
logger.debug("GetGeneratedKeys is supported");
|
||||
|
@ -172,7 +176,7 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
|||
}
|
||||
try {
|
||||
String databaseProductName = databaseMetaData.getDatabaseProductName();
|
||||
if (productsNotSupportingGeneratedKeysColumnNameArray.contains(databaseProductName)) {
|
||||
if (this.productsNotSupportingGeneratedKeysColumnNameArray.contains(databaseProductName)) {
|
||||
logger.debug("GeneratedKeysColumnNameArray is not supported for " + databaseProductName);
|
||||
setGeneratedKeysColumnNameArraySupported(false);
|
||||
}
|
||||
|
@ -185,7 +189,7 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
|||
logger.warn("Error retrieving 'DatabaseMetaData.getDatabaseProductName' - " + se.getMessage());
|
||||
}
|
||||
try {
|
||||
databaseVersion = databaseMetaData.getDatabaseProductVersion();
|
||||
this.databaseVersion = databaseMetaData.getDatabaseProductVersion();
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.warn("Error retrieving 'DatabaseMetaData.getDatabaseProductVersion' - " + se.getMessage());
|
||||
|
@ -205,47 +209,56 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
|||
|
||||
}
|
||||
|
||||
public void initializeWithTableColumnMetaData(DatabaseMetaData databaseMetaData, String catalogName, String schemaName, String tableName)
|
||||
throws SQLException {
|
||||
|
||||
tableColumnMetaDataUsed = true;
|
||||
public void initializeWithTableColumnMetaData(DatabaseMetaData databaseMetaData, String catalogName,
|
||||
String schemaName, String tableName) throws SQLException {
|
||||
|
||||
this.tableColumnMetaDataUsed = true;
|
||||
locateTableAndProcessMetaData(databaseMetaData, catalogName, schemaName, tableName);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public String tableNameToUse(String tableName) {
|
||||
if (tableName == null)
|
||||
if (tableName == null) {
|
||||
return null;
|
||||
else if (isStoresUpperCaseIdentifiers())
|
||||
}
|
||||
else if (isStoresUpperCaseIdentifiers()) {
|
||||
return tableName.toUpperCase();
|
||||
else if(isStoresLowerCaseIdentifiers())
|
||||
}
|
||||
else if(isStoresLowerCaseIdentifiers()) {
|
||||
return tableName.toLowerCase();
|
||||
else
|
||||
}
|
||||
else {
|
||||
return tableName;
|
||||
}
|
||||
}
|
||||
|
||||
public String catalogNameToUse(String catalogName) {
|
||||
if (catalogName == null)
|
||||
if (catalogName == null) {
|
||||
return null;
|
||||
else if (isStoresUpperCaseIdentifiers())
|
||||
}
|
||||
else if (isStoresUpperCaseIdentifiers()) {
|
||||
return catalogName.toUpperCase();
|
||||
else if(isStoresLowerCaseIdentifiers())
|
||||
}
|
||||
else if(isStoresLowerCaseIdentifiers()) {
|
||||
return catalogName.toLowerCase();
|
||||
else
|
||||
return catalogName;
|
||||
}
|
||||
else {
|
||||
return catalogName;
|
||||
}
|
||||
}
|
||||
|
||||
public String schemaNameToUse(String schemaName) {
|
||||
if (schemaName == null)
|
||||
if (schemaName == null) {
|
||||
return null;
|
||||
else if (isStoresUpperCaseIdentifiers())
|
||||
}
|
||||
else if (isStoresUpperCaseIdentifiers()) {
|
||||
return schemaName.toUpperCase();
|
||||
else if(isStoresLowerCaseIdentifiers())
|
||||
}
|
||||
else if(isStoresLowerCaseIdentifiers()) {
|
||||
return schemaName.toLowerCase();
|
||||
else
|
||||
return schemaName;
|
||||
}
|
||||
else {
|
||||
return schemaName;
|
||||
}
|
||||
}
|
||||
|
||||
public String metaDataCatalogNameToUse(String catalogName) {
|
||||
|
@ -261,19 +274,20 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
|||
|
||||
|
||||
/**
|
||||
* Provide access to version info for subclasses
|
||||
* Provide access to version info for subclasses.
|
||||
*/
|
||||
protected String getDatabaseVersion() {
|
||||
return databaseVersion;
|
||||
return this.databaseVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method supporting the metedata processing for a table
|
||||
* Method supporting the metedata processing for a table.
|
||||
*/
|
||||
private void locateTableAndProcessMetaData(DatabaseMetaData databaseMetaData, String catalogName, String schemaName, String tableName) {
|
||||
private void locateTableAndProcessMetaData(DatabaseMetaData databaseMetaData, String catalogName,
|
||||
String schemaName, String tableName) {
|
||||
|
||||
Map<String, TableMetaData> tableMeta = new HashMap<String, TableMetaData>();
|
||||
ResultSet tables = null;
|
||||
|
||||
try {
|
||||
tables = databaseMetaData.getTables(
|
||||
catalogNameToUse(catalogName),
|
||||
|
@ -311,7 +325,7 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
|||
logger.warn("Unable to locate table meta data for '" + tableName +"' -- column names must be provided");
|
||||
}
|
||||
else {
|
||||
TableMetaData tmd = null;
|
||||
TableMetaData tmd;
|
||||
if (schemaName == null) {
|
||||
tmd = tableMeta.get(userName.toUpperCase());
|
||||
if (tmd == null) {
|
||||
|
@ -320,14 +334,16 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
|||
tmd = tableMeta.get("DBO");
|
||||
}
|
||||
if (tmd == null) {
|
||||
throw new DataAccessResourceFailureException("Unable to locate table meta data for '" + tableName + "' in the default schema");
|
||||
throw new DataAccessResourceFailureException("Unable to locate table meta data for '" +
|
||||
tableName + "' in the default schema");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
tmd = tableMeta.get(schemaName.toUpperCase());
|
||||
if (tmd == null) {
|
||||
throw new DataAccessResourceFailureException("Unable to locate table meta data for '" + tableName + "' in the '" + schemaName + "' schema");
|
||||
throw new DataAccessResourceFailureException("Unable to locate table meta data for '" +
|
||||
tableName + "' in the '" + schemaName + "' schema");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,7 +394,7 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
|||
dataType,
|
||||
nullable
|
||||
);
|
||||
insertParameterMetaData.add(meta);
|
||||
this.insertParameterMetaData.add(meta);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Retrieved metadata: "
|
||||
+ meta.getParameterName() +
|
||||
|
@ -389,7 +405,7 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
|||
}
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.warn("Error while retreiving metadata for table columns: " + se.getMessage());
|
||||
logger.warn("Error while retrieving metadata for table columns: " + se.getMessage());
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
|
@ -397,7 +413,7 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
|||
tableColumns.close();
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.warn("Problem closing resultset for table column metadata " + se.getMessage());
|
||||
logger.warn("Problem closing ResultSet for table column metadata " + se.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -405,45 +421,49 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
|||
|
||||
|
||||
/**
|
||||
* Class representing table meta data
|
||||
* Inner class representing table meta data.
|
||||
*/
|
||||
private class TableMetaData {
|
||||
private static class TableMetaData {
|
||||
|
||||
private String catalogName;
|
||||
|
||||
private String schemaName;
|
||||
|
||||
private String tableName;
|
||||
|
||||
private String type;
|
||||
|
||||
|
||||
public String getCatalogName() {
|
||||
return catalogName;
|
||||
}
|
||||
|
||||
public void setCatalogName(String catalogName) {
|
||||
this.catalogName = catalogName;
|
||||
}
|
||||
|
||||
public String getSchemaName() {
|
||||
return schemaName;
|
||||
public String getCatalogName() {
|
||||
return this.catalogName;
|
||||
}
|
||||
|
||||
public void setSchemaName(String schemaName) {
|
||||
this.schemaName = schemaName;
|
||||
}
|
||||
|
||||
public String getTableName() {
|
||||
return tableName;
|
||||
public String getSchemaName() {
|
||||
return this.schemaName;
|
||||
}
|
||||
|
||||
public void setTableName(String tableName) {
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
public String getTableName() {
|
||||
return this.tableName;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return this.type;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2010 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,17 +22,20 @@ import java.sql.DatabaseMetaData;
|
|||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* The Oracle specific implementation of the {@link org.springframework.jdbc.core.metadata.TableMetaDataProvider}.
|
||||
* 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
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
*/
|
||||
public class OracleTableMetaDataProvider extends GenericTableMetaDataProvider {
|
||||
|
||||
private boolean includeSynonyms;
|
||||
private final boolean includeSynonyms;
|
||||
|
||||
|
||||
public OracleTableMetaDataProvider(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
|
@ -49,67 +52,61 @@ public class OracleTableMetaDataProvider extends GenericTableMetaDataProvider {
|
|||
public void initializeWithTableColumnMetaData(DatabaseMetaData databaseMetaData,
|
||||
String catalogName, String schemaName, String tableName) throws SQLException {
|
||||
|
||||
Connection con = null;
|
||||
if (nativeJdbcExtractor == null) {
|
||||
con = databaseMetaData.getConnection();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using meta data JDBC connection: " + con.getClass().getName());
|
||||
}
|
||||
}
|
||||
else {
|
||||
con = nativeJdbcExtractor.getNativeConnection(databaseMetaData.getConnection());
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using native JDBC connection: " + con.getClass().getName());
|
||||
}
|
||||
}
|
||||
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 (!this.includeSynonyms) {
|
||||
logger.debug("Defaulting to no synonyms in table metadata lookup");
|
||||
super.initializeWithTableColumnMetaData(databaseMetaData, catalogName, schemaName, tableName);
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Connection con = databaseMetaData.getConnection();
|
||||
NativeJdbcExtractor nativeJdbcExtractor = getNativeJdbcExtractor();
|
||||
if (nativeJdbcExtractor != null) {
|
||||
con = nativeJdbcExtractor.getNativeConnection(con);
|
||||
}
|
||||
boolean isOracleCon;
|
||||
try {
|
||||
Class oracleConClass = getClass().getClassLoader().loadClass("oracle.jdbc.OracleConnection");
|
||||
isOracleCon = oracleConClass.isInstance(con);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Couldn't find Oracle JDBC API: " + ex);
|
||||
}
|
||||
isOracleCon = false;
|
||||
}
|
||||
|
||||
if (!isOracleCon) {
|
||||
logger.warn("Unable to include synonyms in table metadata lookup. Connection used for " +
|
||||
"DatabaseMetaData is not recognized as an Oracle connection: " + con);
|
||||
super.initializeWithTableColumnMetaData(databaseMetaData, catalogName, schemaName, tableName);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug("Including synonyms in table metadata lookup");
|
||||
Method setIncludeSynonyms;
|
||||
Boolean originalValueForIncludeSynonyms;
|
||||
|
||||
try {
|
||||
Method getIncludeSynonyms = con.getClass().getMethod("getIncludeSynonyms", (Class[]) null);
|
||||
ReflectionUtils.makeAccessible(getIncludeSynonyms);
|
||||
originalValueForIncludeSynonyms = (Boolean) getIncludeSynonyms.invoke(con);
|
||||
|
||||
setIncludeSynonyms = con.getClass().getMethod("setIncludeSynonyms", new Class[] {boolean.class});
|
||||
ReflectionUtils.makeAccessible(setIncludeSynonyms);
|
||||
setIncludeSynonyms.invoke(con, Boolean.TRUE);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new InvalidDataAccessApiUsageException("Couldn't prepare 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);
|
||||
}
|
||||
|
||||
try {
|
||||
setIncludeSynonyms.invoke(con, originalValueForIncludeSynonyms);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new InvalidDataAccessApiUsageException("Couldn't reset Oracle Connection", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -72,7 +72,8 @@ public class TableMetaDataContext {
|
|||
private boolean generatedKeyColumnsUsed = false;
|
||||
|
||||
/** NativeJdbcExtractor to be used to retrieve the native connection */
|
||||
NativeJdbcExtractor nativeJdbcExtractor = null;
|
||||
NativeJdbcExtractor nativeJdbcExtractor;
|
||||
|
||||
|
||||
/**
|
||||
* Set the name of the table for this context.
|
||||
|
@ -162,7 +163,7 @@ public class TableMetaDataContext {
|
|||
|
||||
/**
|
||||
* Does this database support simple query to retrieve generated keys
|
||||
* when the JDBC 3.0 feature is not supported
|
||||
* when the JDBC 3.0 feature is not supported.
|
||||
* {@link java.sql.DatabaseMetaData#supportsGetGeneratedKeys()}?
|
||||
*/
|
||||
public boolean isGetGeneratedKeysSimulated() {
|
||||
|
@ -171,7 +172,7 @@ public class TableMetaDataContext {
|
|||
|
||||
/**
|
||||
* Does this database support simple query to retrieve generated keys
|
||||
* when the JDBC 3.0 feature is not supported
|
||||
* when the JDBC 3.0 feature is not supported.
|
||||
* {@link java.sql.DatabaseMetaData#supportsGetGeneratedKeys()}?
|
||||
*/
|
||||
public String getSimulationQueryForGetGeneratedKey(String tableName, String keyColumnName) {
|
||||
|
@ -179,7 +180,7 @@ public class TableMetaDataContext {
|
|||
}
|
||||
|
||||
/**
|
||||
* Is a column name String array for retrieving generated keys supported
|
||||
* Is a column name String array for retrieving generated keys supported?
|
||||
* {@link java.sql.Connection#createStruct(String, Object[])}?
|
||||
*/
|
||||
public boolean isGeneratedKeysColumnNameArraySupported() {
|
||||
|
@ -187,7 +188,7 @@ public class TableMetaDataContext {
|
|||
}
|
||||
|
||||
/**
|
||||
* Set {@link NativeJdbcExtractor} to be used to retrieve the native connection
|
||||
* Set {@link NativeJdbcExtractor} to be used to retrieve the native connection.
|
||||
*/
|
||||
public void setNativeJdbcExtractor(NativeJdbcExtractor nativeJdbcExtractor) {
|
||||
this.nativeJdbcExtractor = nativeJdbcExtractor;
|
||||
|
@ -195,7 +196,7 @@ public class TableMetaDataContext {
|
|||
|
||||
|
||||
/**
|
||||
* Process the current meta data with the provided configuration options
|
||||
* Process the current meta data with the provided configuration options.
|
||||
* @param dataSource the DataSource being used
|
||||
* @param declaredColumns any columns that are declared
|
||||
* @param generatedKeyNames name of generated keys
|
||||
|
@ -212,7 +213,7 @@ public class TableMetaDataContext {
|
|||
*/
|
||||
protected List<String> reconcileColumnsToUse(List<String> declaredColumns, String[] generatedKeyNames) {
|
||||
if (generatedKeyNames.length > 0) {
|
||||
generatedKeyColumnsUsed = true;
|
||||
this.generatedKeyColumnsUsed = true;
|
||||
}
|
||||
if (declaredColumns.size() > 0) {
|
||||
return new ArrayList<String>(declaredColumns);
|
||||
|
@ -240,7 +241,7 @@ public class TableMetaDataContext {
|
|||
// database metadata is not necessarily providing case sensitive column names
|
||||
Map caseInsensitiveParameterNames =
|
||||
SqlParameterSourceUtils.extractCaseInsensitiveParameterNames(parameterSource);
|
||||
for (String column : tableColumns) {
|
||||
for (String column : this.tableColumns) {
|
||||
if (parameterSource.hasValue(column)) {
|
||||
values.add(SqlParameterSourceUtils.getTypedValue(parameterSource, column));
|
||||
}
|
||||
|
@ -280,7 +281,7 @@ public class TableMetaDataContext {
|
|||
for (String key : inParameters.keySet()) {
|
||||
source.put(key.toLowerCase(), inParameters.get(key));
|
||||
}
|
||||
for (String column : tableColumns) {
|
||||
for (String column : this.tableColumns) {
|
||||
values.add(source.get(column.toLowerCase()));
|
||||
}
|
||||
return values;
|
||||
|
@ -316,7 +317,7 @@ public class TableMetaDataContext {
|
|||
}
|
||||
insertStatement.append(") VALUES(");
|
||||
if (columnCount < 1) {
|
||||
if (generatedKeyColumnsUsed) {
|
||||
if (this.generatedKeyColumnsUsed) {
|
||||
logger.info("Unable to locate non-key columns for table '" +
|
||||
this.getTableName() + "' so an empty insert statement is generated");
|
||||
}
|
||||
|
@ -340,15 +341,12 @@ public class TableMetaDataContext {
|
|||
* @return the array of types to be used
|
||||
*/
|
||||
public int[] createInsertTypes() {
|
||||
|
||||
int[] types = new int[this.getTableColumns().size()];
|
||||
|
||||
List<TableParameterMetaData> parameters = this.metaDataProvider.getTableParameterMetaData();
|
||||
Map<String, TableParameterMetaData> parameterMap = new HashMap<String, TableParameterMetaData>(parameters.size());
|
||||
for (TableParameterMetaData tpmd : parameters) {
|
||||
parameterMap.put(tpmd.getParameterName().toUpperCase(), tpmd);
|
||||
}
|
||||
|
||||
int typeIndx = 0;
|
||||
for (String column : this.getTableColumns()) {
|
||||
if (column == null) {
|
||||
|
@ -365,7 +363,6 @@ public class TableMetaDataContext {
|
|||
}
|
||||
typeIndx++;
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2010 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.
|
||||
|
@ -18,7 +18,6 @@ package org.springframework.jdbc.core.metadata;
|
|||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
@ -38,74 +37,70 @@ import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor;
|
|||
*/
|
||||
public class TableMetaDataProviderFactory {
|
||||
|
||||
/** Logger */
|
||||
private static final Log logger = LogFactory.getLog(TableMetaDataProviderFactory.class);
|
||||
|
||||
|
||||
/**
|
||||
* Create a TableMetaDataProvider based on the database metedata
|
||||
* @param dataSource used to retrieve metedata
|
||||
* @param context the class that holds configuration and metedata
|
||||
* @return instance of the TableMetaDataProvider implementation to be used
|
||||
*/
|
||||
static public TableMetaDataProvider createMetaDataProvider(DataSource dataSource,
|
||||
final TableMetaDataContext context) {
|
||||
public static TableMetaDataProvider createMetaDataProvider(DataSource dataSource, TableMetaDataContext context) {
|
||||
return createMetaDataProvider(dataSource, context, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a TableMetaDataProvider based on the database metedata
|
||||
* @param dataSource used to retrieve metedata
|
||||
* @param context the class that holds configuration and metedata
|
||||
* @param nativeJdbcExtractor @{link NativeJdbcExtractor} to be used
|
||||
* @param nativeJdbcExtractor the NativeJdbcExtractor to be used
|
||||
* @return instance of the TableMetaDataProvider implementation to be used
|
||||
*/
|
||||
static public TableMetaDataProvider createMetaDataProvider(DataSource dataSource,
|
||||
final TableMetaDataContext context,
|
||||
final NativeJdbcExtractor nativeJdbcExtractor) {
|
||||
public static TableMetaDataProvider createMetaDataProvider(DataSource dataSource,
|
||||
final TableMetaDataContext context, final NativeJdbcExtractor nativeJdbcExtractor) {
|
||||
try {
|
||||
return (TableMetaDataProvider) JdbcUtils.extractDatabaseMetaData(
|
||||
dataSource, new DatabaseMetaDataCallback() {
|
||||
|
||||
public Object processMetaData(DatabaseMetaData databaseMetaData)
|
||||
throws SQLException, MetaDataAccessException {
|
||||
String databaseProductName =
|
||||
JdbcUtils.commonDatabaseName(databaseMetaData.getDatabaseProductName());
|
||||
boolean accessTableColumnMetaData = context.isAccessTableColumnMetaData();
|
||||
TableMetaDataProvider provider;
|
||||
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)) {
|
||||
provider = new PostgresTableMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
else if ("Apache Derby".equals(databaseProductName)) {
|
||||
provider = new DerbyTableMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
else {
|
||||
provider = new GenericTableMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
if (nativeJdbcExtractor != null) {
|
||||
provider.setNativeJdbcExtractor(nativeJdbcExtractor);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using " + provider.getClass().getName());
|
||||
}
|
||||
provider.initializeWithMetaData(databaseMetaData);
|
||||
if (accessTableColumnMetaData) {
|
||||
provider.initializeWithTableColumnMetaData(databaseMetaData, context.getCatalogName(),
|
||||
context.getSchemaName(), context.getTableName());
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
});
|
||||
} catch (MetaDataAccessException e) {
|
||||
throw new DataAccessResourceFailureException("Error retreiving database metadata", e);
|
||||
return (TableMetaDataProvider) JdbcUtils.extractDatabaseMetaData(dataSource,
|
||||
new DatabaseMetaDataCallback() {
|
||||
public Object processMetaData(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
String databaseProductName =
|
||||
JdbcUtils.commonDatabaseName(databaseMetaData.getDatabaseProductName());
|
||||
boolean accessTableColumnMetaData = context.isAccessTableColumnMetaData();
|
||||
TableMetaDataProvider provider;
|
||||
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)) {
|
||||
provider = new PostgresTableMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
else if ("Apache Derby".equals(databaseProductName)) {
|
||||
provider = new DerbyTableMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
else {
|
||||
provider = new GenericTableMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
if (nativeJdbcExtractor != null) {
|
||||
provider.setNativeJdbcExtractor(nativeJdbcExtractor);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using " + provider.getClass().getSimpleName());
|
||||
}
|
||||
provider.initializeWithMetaData(databaseMetaData);
|
||||
if (accessTableColumnMetaData) {
|
||||
provider.initializeWithTableColumnMetaData(databaseMetaData, context.getCatalogName(),
|
||||
context.getSchemaName(), context.getTableName());
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (MetaDataAccessException ex) {
|
||||
throw new DataAccessResourceFailureException("Error retrieving database metadata", ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2010 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.
|
||||
|
@ -18,25 +18,24 @@ package org.springframework.jdbc.core.simple;
|
|||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.sql.ResultSet;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.ConnectionCallback;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
@ -57,6 +56,7 @@ import org.springframework.util.Assert;
|
|||
* This class provides the base SPI for {@link SimpleJdbcInsert}.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5
|
||||
*/
|
||||
public abstract class AbstractJdbcInsert {
|
||||
|
@ -65,10 +65,13 @@ public abstract class AbstractJdbcInsert {
|
|||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
/** Lower-level class used to execute SQL */
|
||||
private JdbcTemplate jdbcTemplate = new JdbcTemplate();
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
/** Context used to retrieve and manage database metadata */
|
||||
private final TableMetaDataContext tableMetaDataContext = new TableMetaDataContext();
|
||||
|
||||
/** List of columns objects to be used in insert statement */
|
||||
private List<String> declaredColumns = new ArrayList<String>();
|
||||
private final List<String> declaredColumns = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Has this operation been compiled? Compilation means at
|
||||
|
@ -77,31 +80,30 @@ public abstract class AbstractJdbcInsert {
|
|||
*/
|
||||
private boolean compiled = false;
|
||||
|
||||
/** the generated string used for insert statement */
|
||||
/** The generated string used for insert statement */
|
||||
private String insertString;
|
||||
|
||||
/** the SQL Type information for the insert columns */
|
||||
/** The SQL type information for the insert columns */
|
||||
private int[] insertTypes;
|
||||
|
||||
/** the names of the columns holding the generated key */
|
||||
private String[] generatedKeyNames = new String[] {};
|
||||
|
||||
/** context used to retrieve and manage database metadata */
|
||||
private TableMetaDataContext tableMetaDataContext = new TableMetaDataContext();
|
||||
/** The names of the columns holding the generated key */
|
||||
private String[] generatedKeyNames = new String[0];
|
||||
|
||||
|
||||
/**
|
||||
* Constructor for sublasses to delegate to for setting the DataSource.
|
||||
*/
|
||||
protected AbstractJdbcInsert(DataSource dataSource) {
|
||||
jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for sublasses to delegate to for setting the JdbcTemplate.
|
||||
*/
|
||||
protected AbstractJdbcInsert(JdbcTemplate jdbcTemplate) {
|
||||
Assert.notNull(jdbcTemplate, "JdbcTemplate must not be null");
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
setNativeJdbcExtractor(jdbcTemplate.getNativeJdbcExtractor());
|
||||
}
|
||||
|
||||
|
||||
|
@ -109,26 +111,19 @@ public abstract class AbstractJdbcInsert {
|
|||
// Methods dealing with configuaration properties
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Get the name of the table for this insert
|
||||
*/
|
||||
public String getTableName() {
|
||||
return tableMetaDataContext.getTableName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the table for this insert
|
||||
*/
|
||||
public void setTableName(String tableName) {
|
||||
checkIfConfigurationModificationIsAllowed();
|
||||
tableMetaDataContext.setTableName(tableName);
|
||||
this.tableMetaDataContext.setTableName(tableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the schema for this insert
|
||||
* Get the name of the table for this insert
|
||||
*/
|
||||
public String getSchemaName() {
|
||||
return tableMetaDataContext.getSchemaName();
|
||||
public String getTableName() {
|
||||
return this.tableMetaDataContext.getTableName();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -136,14 +131,14 @@ public abstract class AbstractJdbcInsert {
|
|||
*/
|
||||
public void setSchemaName(String schemaName) {
|
||||
checkIfConfigurationModificationIsAllowed();
|
||||
tableMetaDataContext.setSchemaName(schemaName);
|
||||
this.tableMetaDataContext.setSchemaName(schemaName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the catalog for this insert
|
||||
* Get the name of the schema for this insert
|
||||
*/
|
||||
public String getCatalogName() {
|
||||
return tableMetaDataContext.getCatalogName();
|
||||
public String getSchemaName() {
|
||||
return this.tableMetaDataContext.getSchemaName();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -151,7 +146,14 @@ public abstract class AbstractJdbcInsert {
|
|||
*/
|
||||
public void setCatalogName(String catalogName) {
|
||||
checkIfConfigurationModificationIsAllowed();
|
||||
tableMetaDataContext.setCatalogName(catalogName);
|
||||
this.tableMetaDataContext.setCatalogName(catalogName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the catalog for this insert
|
||||
*/
|
||||
public String getCatalogName() {
|
||||
return this.tableMetaDataContext.getCatalogName();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -159,22 +161,22 @@ public abstract class AbstractJdbcInsert {
|
|||
*/
|
||||
public void setColumnNames(List<String> columnNames) {
|
||||
checkIfConfigurationModificationIsAllowed();
|
||||
declaredColumns.clear();
|
||||
declaredColumns.addAll(columnNames);
|
||||
this.declaredColumns.clear();
|
||||
this.declaredColumns.addAll(columnNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the names of the columns used
|
||||
*/
|
||||
public List<String> getColumnNames() {
|
||||
return Collections.unmodifiableList(declaredColumns);
|
||||
return Collections.unmodifiableList(this.declaredColumns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the names of any generated keys
|
||||
*/
|
||||
public String[] getGeneratedKeyNames() {
|
||||
return generatedKeyNames;
|
||||
return this.generatedKeyNames;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -207,32 +209,32 @@ public abstract class AbstractJdbcInsert {
|
|||
this.tableMetaDataContext.setOverrideIncludeSynonymsDefault(override);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link NativeJdbcExtractor} to use to retrieve the native connection if necessary
|
||||
*/
|
||||
public void setNativeJdbcExtractor(NativeJdbcExtractor nativeJdbcExtractor) {
|
||||
this.tableMetaDataContext.setNativeJdbcExtractor(nativeJdbcExtractor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the insert string to be used
|
||||
*/
|
||||
public String getInsertString() {
|
||||
return insertString;
|
||||
return this.insertString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array of {@link java.sql.Types} to be used for insert
|
||||
*/
|
||||
public int[] getInsertTypes() {
|
||||
return insertTypes;
|
||||
return this.insertTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link JdbcTemplate} that is configured to be used
|
||||
*/
|
||||
protected JdbcTemplate getJdbcTemplate() {
|
||||
return jdbcTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link NativeJdbcExtractor} to use to retrieve the native connection if necessary
|
||||
*/
|
||||
public void setNativeJdbcExtractor(NativeJdbcExtractor nativeJdbcExtractor) {
|
||||
this.tableMetaDataContext.setNativeJdbcExtractor(nativeJdbcExtractor);
|
||||
return this.jdbcTemplate;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue