|
|
|
@ -1,5 +1,5 @@ |
|
|
|
/* |
|
|
|
/* |
|
|
|
* Copyright 2002-2016 the original author or authors. |
|
|
|
* Copyright 2002-2017 the original author or authors. |
|
|
|
* |
|
|
|
* |
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
|
* you may not use this file except in compliance with the License. |
|
|
|
* you may not use this file except in compliance with the License. |
|
|
|
@ -30,6 +30,7 @@ import org.apache.commons.logging.Log; |
|
|
|
import org.apache.commons.logging.LogFactory; |
|
|
|
import org.apache.commons.logging.LogFactory; |
|
|
|
|
|
|
|
|
|
|
|
import org.springframework.dao.DataAccessResourceFailureException; |
|
|
|
import org.springframework.dao.DataAccessResourceFailureException; |
|
|
|
|
|
|
|
import org.springframework.jdbc.support.JdbcUtils; |
|
|
|
import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor; |
|
|
|
import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -37,6 +38,7 @@ import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor; |
|
|
|
* enough features for all supported databases. |
|
|
|
* enough features for all supported databases. |
|
|
|
* |
|
|
|
* |
|
|
|
* @author Thomas Risberg |
|
|
|
* @author Thomas Risberg |
|
|
|
|
|
|
|
* @author Juergen Hoeller |
|
|
|
* @since 2.5 |
|
|
|
* @since 2.5 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public class GenericTableMetaDataProvider implements TableMetaDataProvider { |
|
|
|
public class GenericTableMetaDataProvider implements TableMetaDataProvider { |
|
|
|
@ -163,17 +165,23 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
catch (SQLException ex) { |
|
|
|
catch (SQLException ex) { |
|
|
|
logger.warn("Error retrieving 'DatabaseMetaData.getGeneratedKeys' - " + ex.getMessage()); |
|
|
|
if (logger.isWarnEnabled()) { |
|
|
|
|
|
|
|
logger.warn("Error retrieving 'DatabaseMetaData.getGeneratedKeys': " + ex.getMessage()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
try { |
|
|
|
try { |
|
|
|
String databaseProductName = databaseMetaData.getDatabaseProductName(); |
|
|
|
String databaseProductName = databaseMetaData.getDatabaseProductName(); |
|
|
|
if (this.productsNotSupportingGeneratedKeysColumnNameArray.contains(databaseProductName)) { |
|
|
|
if (this.productsNotSupportingGeneratedKeysColumnNameArray.contains(databaseProductName)) { |
|
|
|
logger.debug("GeneratedKeysColumnNameArray is not supported for " + databaseProductName); |
|
|
|
if (logger.isDebugEnabled()) { |
|
|
|
|
|
|
|
logger.debug("GeneratedKeysColumnNameArray is not supported for " + databaseProductName); |
|
|
|
|
|
|
|
} |
|
|
|
setGeneratedKeysColumnNameArraySupported(false); |
|
|
|
setGeneratedKeysColumnNameArraySupported(false); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
if (isGetGeneratedKeysSupported()) { |
|
|
|
if (isGetGeneratedKeysSupported()) { |
|
|
|
logger.debug("GeneratedKeysColumnNameArray is supported for " + databaseProductName); |
|
|
|
if (logger.isDebugEnabled()) { |
|
|
|
|
|
|
|
logger.debug("GeneratedKeysColumnNameArray is supported for " + databaseProductName); |
|
|
|
|
|
|
|
} |
|
|
|
setGeneratedKeysColumnNameArraySupported(true); |
|
|
|
setGeneratedKeysColumnNameArraySupported(true); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
@ -182,25 +190,36 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
catch (SQLException ex) { |
|
|
|
catch (SQLException ex) { |
|
|
|
logger.warn("Error retrieving 'DatabaseMetaData.getDatabaseProductName' - " + ex.getMessage()); |
|
|
|
if (logger.isWarnEnabled()) { |
|
|
|
|
|
|
|
logger.warn("Error retrieving 'DatabaseMetaData.getDatabaseProductName': " + ex.getMessage()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
this.databaseVersion = databaseMetaData.getDatabaseProductVersion(); |
|
|
|
this.databaseVersion = databaseMetaData.getDatabaseProductVersion(); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (SQLException ex) { |
|
|
|
catch (SQLException ex) { |
|
|
|
logger.warn("Error retrieving 'DatabaseMetaData.getDatabaseProductVersion' - " + ex.getMessage()); |
|
|
|
if (logger.isWarnEnabled()) { |
|
|
|
|
|
|
|
logger.warn("Error retrieving 'DatabaseMetaData.getDatabaseProductVersion': " + ex.getMessage()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
setStoresUpperCaseIdentifiers(databaseMetaData.storesUpperCaseIdentifiers()); |
|
|
|
setStoresUpperCaseIdentifiers(databaseMetaData.storesUpperCaseIdentifiers()); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (SQLException ex) { |
|
|
|
catch (SQLException ex) { |
|
|
|
logger.warn("Error retrieving 'DatabaseMetaData.storesUpperCaseIdentifiers' - " + ex.getMessage()); |
|
|
|
if (logger.isWarnEnabled()) { |
|
|
|
|
|
|
|
logger.warn("Error retrieving 'DatabaseMetaData.storesUpperCaseIdentifiers': " + ex.getMessage()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
setStoresLowerCaseIdentifiers(databaseMetaData.storesLowerCaseIdentifiers()); |
|
|
|
setStoresLowerCaseIdentifiers(databaseMetaData.storesLowerCaseIdentifiers()); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (SQLException ex) { |
|
|
|
catch (SQLException ex) { |
|
|
|
logger.warn("Error retrieving 'DatabaseMetaData.storesLowerCaseIdentifiers' - " + ex.getMessage()); |
|
|
|
if (logger.isWarnEnabled()) { |
|
|
|
|
|
|
|
logger.warn("Error retrieving 'DatabaseMetaData.storesLowerCaseIdentifiers': " + ex.getMessage()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
@ -278,7 +297,7 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider { |
|
|
|
* Provide access to default schema for subclasses. |
|
|
|
* Provide access to default schema for subclasses. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
protected String getDefaultSchema() { |
|
|
|
protected String getDefaultSchema() { |
|
|
|
return userName; |
|
|
|
return this.userName; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -291,17 +310,14 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider { |
|
|
|
/** |
|
|
|
/** |
|
|
|
* Method supporting the metedata processing for a table. |
|
|
|
* Method supporting the metedata processing for a table. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private void locateTableAndProcessMetaData(DatabaseMetaData databaseMetaData, String catalogName, |
|
|
|
private void locateTableAndProcessMetaData( |
|
|
|
String schemaName, String tableName) { |
|
|
|
DatabaseMetaData databaseMetaData, String catalogName, String schemaName, String tableName) { |
|
|
|
|
|
|
|
|
|
|
|
Map<String, TableMetaData> tableMeta = new HashMap<>(); |
|
|
|
Map<String, TableMetaData> tableMeta = new HashMap<>(); |
|
|
|
ResultSet tables = null; |
|
|
|
ResultSet tables = null; |
|
|
|
try { |
|
|
|
try { |
|
|
|
tables = databaseMetaData.getTables( |
|
|
|
tables = databaseMetaData.getTables( |
|
|
|
catalogNameToUse(catalogName), |
|
|
|
catalogNameToUse(catalogName), schemaNameToUse(schemaName), tableNameToUse(tableName), null); |
|
|
|
schemaNameToUse(schemaName), |
|
|
|
|
|
|
|
tableNameToUse(tableName), |
|
|
|
|
|
|
|
null); |
|
|
|
|
|
|
|
while (tables != null && tables.next()) { |
|
|
|
while (tables != null && tables.next()) { |
|
|
|
TableMetaData tmd = new TableMetaData(); |
|
|
|
TableMetaData tmd = new TableMetaData(); |
|
|
|
tmd.setCatalogName(tables.getString("TABLE_CAT")); |
|
|
|
tmd.setCatalogName(tables.getString("TABLE_CAT")); |
|
|
|
@ -316,49 +332,52 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
catch (SQLException ex) { |
|
|
|
catch (SQLException ex) { |
|
|
|
logger.warn("Error while accessing table meta data results" + ex.getMessage()); |
|
|
|
if (logger.isWarnEnabled()) { |
|
|
|
|
|
|
|
logger.warn("Error while accessing table meta data results: " + ex.getMessage()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
finally { |
|
|
|
finally { |
|
|
|
if (tables != null) { |
|
|
|
JdbcUtils.closeResultSet(tables); |
|
|
|
try { |
|
|
|
} |
|
|
|
tables.close(); |
|
|
|
|
|
|
|
} |
|
|
|
if (tableMeta.isEmpty()) { |
|
|
|
catch (SQLException ex) { |
|
|
|
if (logger.isWarnEnabled()) { |
|
|
|
logger.warn("Error while closing table meta data results" + ex.getMessage()); |
|
|
|
logger.warn("Unable to locate table meta data for '" + tableName + "': column names must be provided"); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
processTableColumns(databaseMetaData, findTableMetaData(schemaName, tableName, tableMeta)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (tableMeta.size() < 1) { |
|
|
|
private TableMetaData findTableMetaData(String schemaName, String tableName, Map<String, TableMetaData> tableMeta) { |
|
|
|
logger.warn("Unable to locate table meta data for '" + tableName +"' -- column names must be provided"); |
|
|
|
if (schemaName != null) { |
|
|
|
|
|
|
|
TableMetaData tmd = tableMeta.get(schemaName.toUpperCase()); |
|
|
|
|
|
|
|
if (tmd == null) { |
|
|
|
|
|
|
|
throw new DataAccessResourceFailureException("Unable to locate table meta data for '" + |
|
|
|
|
|
|
|
tableName + "' in the '" + schemaName + "' schema"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return tmd; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else if (tableMeta.size() == 1) { |
|
|
|
|
|
|
|
return tableMeta.values().iterator().next(); |
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
else { |
|
|
|
TableMetaData tmd; |
|
|
|
TableMetaData tmd = tableMeta.get(getDefaultSchema()); |
|
|
|
if (schemaName == null) { |
|
|
|
if (tmd == null) { |
|
|
|
tmd = tableMeta.get(getDefaultSchema()); |
|
|
|
tmd = tableMeta.get(this.userName != null ? this.userName.toUpperCase() : ""); |
|
|
|
if (tmd == null) { |
|
|
|
|
|
|
|
tmd = tableMeta.get(userName != null ? userName.toUpperCase() : ""); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (tmd == null) { |
|
|
|
|
|
|
|
tmd = tableMeta.get("PUBLIC"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (tmd == null) { |
|
|
|
|
|
|
|
tmd = tableMeta.get("DBO"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (tmd == null) { |
|
|
|
|
|
|
|
throw new DataAccessResourceFailureException("Unable to locate table meta data for '" + |
|
|
|
|
|
|
|
tableName + "' in the default schema"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
else { |
|
|
|
if (tmd == null) { |
|
|
|
tmd = tableMeta.get(schemaName.toUpperCase()); |
|
|
|
tmd = tableMeta.get("PUBLIC"); |
|
|
|
if (tmd == null) { |
|
|
|
|
|
|
|
throw new DataAccessResourceFailureException("Unable to locate table meta data for '" + |
|
|
|
|
|
|
|
tableName + "' in the '" + schemaName + "' schema"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (tmd == null) { |
|
|
|
processTableColumns(databaseMetaData, tmd); |
|
|
|
tmd = tableMeta.get("DBO"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (tmd == null) { |
|
|
|
|
|
|
|
throw new DataAccessResourceFailureException( |
|
|
|
|
|
|
|
"Unable to locate table meta data for '" + tableName + "' in the default schema"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return tmd; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -389,10 +408,7 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider { |
|
|
|
if ("NUMBER".equals(typeName) && decimalDigits == 0) { |
|
|
|
if ("NUMBER".equals(typeName) && decimalDigits == 0) { |
|
|
|
dataType = Types.NUMERIC; |
|
|
|
dataType = Types.NUMERIC; |
|
|
|
if (logger.isDebugEnabled()) { |
|
|
|
if (logger.isDebugEnabled()) { |
|
|
|
logger.debug("Overriding metadata: " |
|
|
|
logger.debug("Overriding metadata: " + columnName + " now NUMERIC instead of DECIMAL"); |
|
|
|
+ columnName + |
|
|
|
|
|
|
|
" now using NUMERIC instead of DECIMAL" |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -400,24 +416,19 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider { |
|
|
|
TableParameterMetaData meta = new TableParameterMetaData(columnName, dataType, nullable); |
|
|
|
TableParameterMetaData meta = new TableParameterMetaData(columnName, dataType, nullable); |
|
|
|
this.tableParameterMetaData.add(meta); |
|
|
|
this.tableParameterMetaData.add(meta); |
|
|
|
if (logger.isDebugEnabled()) { |
|
|
|
if (logger.isDebugEnabled()) { |
|
|
|
logger.debug("Retrieved metadata: " + meta.getParameterName() + |
|
|
|
logger.debug("Retrieved metadata: " + meta.getParameterName() + " " + |
|
|
|
" " + meta.getSqlType() + " " + meta.isNullable()); |
|
|
|
meta.getSqlType() + " " + meta.isNullable()); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
catch (SQLException ex) { |
|
|
|
catch (SQLException ex) { |
|
|
|
logger.warn("Error while retrieving metadata for table columns: " + ex.getMessage()); |
|
|
|
if (logger.isWarnEnabled()) { |
|
|
|
|
|
|
|
logger.warn("Error while retrieving metadata for table columns: " + ex.getMessage()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
finally { |
|
|
|
finally { |
|
|
|
try { |
|
|
|
JdbcUtils.closeResultSet(tableColumns); |
|
|
|
if (tableColumns != null) |
|
|
|
|
|
|
|
tableColumns.close(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (SQLException ex) { |
|
|
|
|
|
|
|
logger.warn("Problem closing ResultSet for table column metadata " + ex.getMessage()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|