org.dbunit.database.DatabaseTableMetaData Maven / Gradle / Ivy
The newest version!
/*
*
* The DbUnit Database Testing Framework
* Copyright (C)2002-2004, DbUnit.org
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package org.dbunit.database;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.dbunit.dataset.AbstractTableMetaData;
import org.dbunit.dataset.Column;
import org.dbunit.dataset.Columns;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.ITableMetaData;
import org.dbunit.dataset.NoSuchTableException;
import org.dbunit.dataset.datatype.IDataTypeFactory;
import org.dbunit.dataset.filter.IColumnFilter;
import org.dbunit.util.QualifiedTableName;
import org.dbunit.util.SQLHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Container for the metadata for one database table. The metadata is initialized
* using a {@link IDatabaseConnection}.
*
* @author Manuel Laflamme
* @author Last changed by: $Author$
* @version $Revision$ $Date$
* @since Mar 8, 2002
* @see ITableMetaData
*/
public class DatabaseTableMetaData extends AbstractTableMetaData
{
/**
* Logger for this class
*/
private static final Logger logger = LoggerFactory.getLogger(DatabaseTableMetaData.class);
/**
* Table name, potentially qualified
*/
private final QualifiedTableName _qualifiedTableNameSupport;
private final String _originalTableName;
private final IDatabaseConnection _connection;
private Column[] _columns;
private Column[] _primaryKeys;
private boolean _caseSensitiveMetaData;
//added by hzhan032
private IColumnFilter lastKeyFilter;
DatabaseTableMetaData(String tableName, IDatabaseConnection connection) throws DataSetException
{
this(tableName, connection, true);
}
/**
* Creates a new database table metadata
* @param tableName The name of the table - can be fully qualified
* @param connection The database connection
* @param validate Whether or not to validate the given input data. It is not recommended to
* set the validation to false
because it is then possible to create an instance
* of this object for a db table that does not exist.
* @throws DataSetException
*/
DatabaseTableMetaData(String tableName, IDatabaseConnection connection, boolean validate) throws DataSetException
{
this(tableName, connection, validate, false);
}
/**
* Creates a new database table metadata
* @param tableName The name of the table - can be fully qualified
* @param connection The database connection
* @param validate Whether or not to validate the given input data. It is not recommended to
* set the validation to false
because it is then possible to create an instance
* of this object for a db table that does not exist.
* @param caseSensitiveMetaData Whether or not the metadata looked up in a case sensitive way
* @throws DataSetException
* @since 2.4.1
*/
DatabaseTableMetaData(final String tableName, IDatabaseConnection connection, boolean validate, boolean caseSensitiveMetaData) throws DataSetException
{
if (tableName == null) {
throw new NullPointerException("The parameter 'tableName' must not be null");
}
if (connection == null) {
throw new NullPointerException("The parameter 'connection' must not be null");
}
_connection = connection;
_caseSensitiveMetaData = caseSensitiveMetaData;
try
{
Connection jdbcConnection = connection.getConnection();
if(!caseSensitiveMetaData)
{
_originalTableName = SQLHelper.correctCase(tableName, jdbcConnection);
SQLHelper.logDebugIfValueChanged(tableName, _originalTableName, "Corrected table name:", DatabaseTableMetaData.class);
}
else
{
_originalTableName = tableName;
}
// qualified names support - table name and schema is stored here
_qualifiedTableNameSupport = new QualifiedTableName(_originalTableName, _connection.getSchema());
if(validate)
{
String schemaName = _qualifiedTableNameSupport.getSchema();
String plainTableName = _qualifiedTableNameSupport.getTable();
logger.debug("Validating if table '{}' exists in schema '{}' ...", plainTableName, schemaName);
try {
DatabaseConfig config = connection.getConfig();
IMetadataHandler metadataHandler = (IMetadataHandler) config.getProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER);
DatabaseMetaData databaseMetaData = jdbcConnection.getMetaData();
if(!metadataHandler.tableExists(databaseMetaData, schemaName, plainTableName))
{
throw new NoSuchTableException("Did not find table '" + plainTableName + "' in schema '" + schemaName + "'");
}
}
catch (SQLException e)
{
throw new DataSetException("Exception while validation existence of table '" + plainTableName + "'", e);
}
}
else
{
logger.debug("Validation switched off. Will not check if table exists.");
}
}
catch (SQLException e)
{
throw new DataSetException("Exception while retrieving JDBC connection from dbunit connection '" + connection + "'", e);
}
}
/**
* @param tableName
* @param resultSet
* @param dataTypeFactory
* @return The table metadata created for the given parameters
* @throws DataSetException
* @throws SQLException
* @deprecated since 2.3.0. use {@link ResultSetTableMetaData#ResultSetTableMetaData(String, ResultSet, IDataTypeFactory, boolean)}
*/
public static ITableMetaData createMetaData(String tableName,
ResultSet resultSet, IDataTypeFactory dataTypeFactory)
throws DataSetException, SQLException
{
if (logger.isDebugEnabled())
{
logger.debug("createMetaData(tableName={}, resultSet={}, dataTypeFactory={}) - start",
new Object[]{ tableName, resultSet, dataTypeFactory });
}
return new ResultSetTableMetaData(tableName, resultSet, dataTypeFactory, false);
}
/**
* @param tableName
* @param resultSet
* @param connection
* @return The table metadata created for the given parameters
* @throws SQLException
* @throws DataSetException
* @deprecated since 2.3.0. use {@link org.dbunit.database.ResultSetTableMetaData#ResultSetTableMetaData(String, ResultSet, IDatabaseConnection, boolean)}
*/
public static ITableMetaData createMetaData(String tableName,
ResultSet resultSet, IDatabaseConnection connection)
throws SQLException, DataSetException
{
if (logger.isDebugEnabled())
{
logger.debug("createMetaData(tableName={}, resultSet={}, connection={}) - start",
new Object[] { tableName, resultSet, connection });
}
return new ResultSetTableMetaData(tableName,resultSet,connection, false);
}
private String[] getPrimaryKeyNames() throws SQLException
{
logger.debug("getPrimaryKeyNames() - start");
String schemaName = _qualifiedTableNameSupport.getSchema();
String tableName = _qualifiedTableNameSupport.getTable();
Connection connection = _connection.getConnection();
DatabaseMetaData databaseMetaData = connection.getMetaData();
DatabaseConfig config = _connection.getConfig();
IMetadataHandler metadataHandler = (IMetadataHandler) config.getProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER);
ResultSet resultSet = metadataHandler.getPrimaryKeys(databaseMetaData, schemaName, tableName);
List list = new ArrayList();
try
{
while (resultSet.next())
{
String name = resultSet.getString(4);
int sequence = resultSet.getInt(5);
list.add(new PrimaryKeyData(name, sequence));
}
}
finally
{
resultSet.close();
}
Collections.sort(list);
String[] keys = new String[list.size()];
for (int i = 0; i < keys.length; i++)
{
PrimaryKeyData data = (PrimaryKeyData)list.get(i);
keys[i] = data.getName();
}
return keys;
}
private class PrimaryKeyData implements Comparable
{
private final String _name;
private final int _index;
public PrimaryKeyData(String name, int index)
{
_name = name;
_index = index;
}
public String getName()
{
logger.debug("getName() - start");
return _name;
}
public int getIndex()
{
return _index;
}
////////////////////////////////////////////////////////////////////////
// Comparable interface
public int compareTo(Object o)
{
PrimaryKeyData data = (PrimaryKeyData)o;
return getIndex() - data.getIndex();
}
}
////////////////////////////////////////////////////////////////////////////
// ITableMetaData interface
public String getTableName()
{
// Ensure that the same table name is returned as specified in the input.
// This is necessary to support fully qualified XML dataset imports.
//""
//""
//""
//" ";
return this._originalTableName;
}
public Column[] getColumns() throws DataSetException
{
logger.debug("getColumns() - start");
if (_columns == null)
{
try
{
// qualified names support
String schemaName = _qualifiedTableNameSupport.getSchema();
String tableName = _qualifiedTableNameSupport.getTable();
Connection jdbcConnection = _connection.getConnection();
DatabaseMetaData databaseMetaData = jdbcConnection.getMetaData();
DatabaseConfig config = _connection.getConfig();
IMetadataHandler metadataHandler = (IMetadataHandler)config.getProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER);
ResultSet resultSet = metadataHandler.getColumns(databaseMetaData, schemaName, tableName);
try
{
IDataTypeFactory dataTypeFactory = super.getDataTypeFactory(_connection);
boolean datatypeWarning = config.getFeature(
DatabaseConfig.FEATURE_DATATYPE_WARNING);
List columnList = new ArrayList();
while (resultSet.next())
{
// Check for exact table/schema name match because
// databaseMetaData.getColumns() uses patterns for the lookup
boolean match = metadataHandler.matches(resultSet, schemaName, tableName, _caseSensitiveMetaData);
if(match)
{
Column column = SQLHelper.createColumn(resultSet, dataTypeFactory, datatypeWarning);
if(column != null)
{
columnList.add(column);
}
}
else
{
logger.debug("Skipping '" + resultSet.getString(2) + "." +
resultSet.getString(3) + "' because names do not exactly match.");
}
}
if (columnList.size() == 0)
{
logger.warn("No columns found for table '"+ tableName +"' that are supported by dbunit. " +
"Will return an empty column list");
}
_columns = (Column[])columnList.toArray(new Column[0]);
}
finally
{
resultSet.close();
}
}
catch (SQLException e)
{
throw new DataSetException(e);
}
}
return _columns;
}
private boolean primaryKeyFilterChanged(IColumnFilter keyFilter)
{
return (keyFilter != lastKeyFilter);
}
public Column[] getPrimaryKeys() throws DataSetException
{
logger.debug("getPrimaryKeys() - start");
DatabaseConfig config = _connection.getConfig();
IColumnFilter primaryKeysFilter = (IColumnFilter) config.getProperty(
DatabaseConfig.PROPERTY_PRIMARY_KEY_FILTER);
if (_primaryKeys == null || primaryKeyFilterChanged(primaryKeysFilter)) {
try {
lastKeyFilter = primaryKeysFilter;
if (primaryKeysFilter != null) {
_primaryKeys = Columns.getColumns(getTableName(), getColumns(),
primaryKeysFilter);
} else {
String[] pkNames = getPrimaryKeyNames();
_primaryKeys = Columns.getColumns(pkNames, getColumns());
}
}
catch (SQLException e)
{
throw new DataSetException(e);
}
}
return _primaryKeys;
}
////////////////////////////////////////////////////////////////////////////
// Object class
public String toString()
{
try
{
String tableName = getTableName();
String columns = Arrays.asList(getColumns()).toString();
String primaryKeys = Arrays.asList(getPrimaryKeys()).toString();
return "table=" + tableName + ", cols=" + columns + ", pk=" + primaryKeys + "";
}
catch (DataSetException e)
{
return super.toString();
}
}
}