All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dbunit.database.ResultSetTableMetaData Maven / Gradle / Ivy

Go to download

dbUnit is a JUnit extension (also usable from Ant and Maven) targeted for database-driven projects that, among other things, puts your database into a known state between test runs. This is an excellent way to avoid the myriad of problems that can occur when one test case corrupts the database and causes subsequent tests to fail or exacerbate the damage.

There is a newer version: 2.8.0
Show newest version
/*
 *
 * The DbUnit Database Testing Framework
 * Copyright (C)2002-2008, 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.ResultSetMetaData;
import java.sql.SQLException;

import org.dbunit.dataset.AbstractTableMetaData;
import org.dbunit.dataset.Column;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.DefaultTableMetaData;
import org.dbunit.dataset.datatype.DataType;
import org.dbunit.dataset.datatype.DataTypeException;
import org.dbunit.dataset.datatype.IDataTypeFactory;
import org.dbunit.util.SQLHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * {@link ResultSet} based {@link org.dbunit.dataset.ITableMetaData} implementation.
 * 

* The lookup for the information needed to create the {@link Column} objects is retrieved * in two phases: *

    *
  1. Try to find the information from the given {@link ResultSet} via a {@link DatabaseMetaData} * object. Therefore the {@link ResultSetMetaData} is used to get the catalog/schema/table/column * names which in turn are used to get column information via * {@link DatabaseMetaData#getColumns(String, String, String, String)}. The reason for this is * that the {@link DatabaseMetaData} is more precise and contains more information about columns * than the {@link ResultSetMetaData} does. Another reason is that some JDBC drivers (currently known * from MYSQL driver) provide an inconsistent implementation of those two MetaData objects * and the {@link DatabaseMetaData} is hence considered to be the master by dbunit. *
  2. *
  3. * Since some JDBC drivers (one of them being Oracle) cannot (or just do not) provide the * catalog/schema/table/column values on a {@link ResultSetMetaData} instance the second * step will create the dbunit {@link Column} using the {@link ResultSetMetaData} methods * directly (for example {@link ResultSetMetaData#getColumnType(int)}. (This is also the way * dbunit worked until the 2.4 release) *
  4. *
*

* * @author gommma (gommma AT users.sourceforge.net) * @author Last changed by: $Author: gommma $ * @version $Revision: 1026 $ $Date: 2009-08-17 21:58:24 +0200 (lun, 17 ago 2009) $ * @since 2.3.0 */ public class ResultSetTableMetaData extends AbstractTableMetaData { /** * Logger for this class */ private static final Logger logger = LoggerFactory.getLogger(DatabaseTableMetaData.class); /** * The actual table metadata */ private DefaultTableMetaData wrappedTableMetaData; private boolean _caseSensitiveMetaData; /** * @param tableName The name of the database table * @param resultSet The JDBC result set that is used to retrieve the columns * @param connection The connection which is needed to retrieve some configuration values * @param caseSensitiveMetaData Whether or not the metadata is case sensitive * @throws DataSetException * @throws SQLException */ public ResultSetTableMetaData(String tableName, ResultSet resultSet, IDatabaseConnection connection, boolean caseSensitiveMetaData) throws DataSetException, SQLException { super(); _caseSensitiveMetaData = caseSensitiveMetaData; this.wrappedTableMetaData = createMetaData(tableName, resultSet, connection); } /** * @param tableName The name of the database table * @param resultSet The JDBC result set that is used to retrieve the columns * @param dataTypeFactory * @param caseSensitiveMetaData Whether or not the metadata is case sensitive * @throws DataSetException * @throws SQLException * @deprecated since 2.4.4. use {@link ResultSetTableMetaData#ResultSetTableMetaData(String, ResultSet, IDatabaseConnection, boolean)} */ public ResultSetTableMetaData(String tableName, ResultSet resultSet, IDataTypeFactory dataTypeFactory, boolean caseSensitiveMetaData) throws DataSetException, SQLException { super(); _caseSensitiveMetaData = caseSensitiveMetaData; this.wrappedTableMetaData = createMetaData(tableName, resultSet, dataTypeFactory, new DefaultMetadataHandler()); } private DefaultTableMetaData createMetaData(String tableName, ResultSet resultSet, IDatabaseConnection connection) throws SQLException, DataSetException { if (logger.isTraceEnabled()) logger.trace("createMetaData(tableName={}, resultSet={}, connection={}) - start", new Object[] { tableName, resultSet, connection }); DatabaseConfig dbConfig = connection.getConfig(); IMetadataHandler columnFactory = (IMetadataHandler)dbConfig.getProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER); IDataTypeFactory typeFactory = super.getDataTypeFactory(connection); return createMetaData(tableName, resultSet, typeFactory, columnFactory); } private DefaultTableMetaData createMetaData(String tableName, ResultSet resultSet, IDataTypeFactory dataTypeFactory, IMetadataHandler columnFactory) throws DataSetException, SQLException { if (logger.isTraceEnabled()) logger.trace("createMetaData(tableName={}, resultSet={}, dataTypeFactory={}, columnFactory={}) - start", new Object[]{ tableName, resultSet, dataTypeFactory, columnFactory }); Connection connection = resultSet.getStatement().getConnection(); DatabaseMetaData databaseMetaData = connection.getMetaData(); ResultSetMetaData metaData = resultSet.getMetaData(); Column[] columns = new Column[metaData.getColumnCount()]; for (int i = 0; i < columns.length; i++) { int rsIndex = i+1; // 1. try to create the column from the DatabaseMetaData object. The DatabaseMetaData // provides more information and is more precise so that it should always be used in // preference to the ResultSetMetaData object. columns[i] = createColumnFromDbMetaData(metaData, rsIndex, databaseMetaData, dataTypeFactory, columnFactory); // 2. If we could not create the Column from a DatabaseMetaData object, try to create it // from the ResultSetMetaData object directly if(columns[i] == null) { columns[i] = createColumnFromRsMetaData(metaData, rsIndex, tableName, dataTypeFactory); } } return new DefaultTableMetaData(tableName, columns); } private Column createColumnFromRsMetaData(ResultSetMetaData rsMetaData, int rsIndex, String tableName, IDataTypeFactory dataTypeFactory) throws SQLException, DataTypeException { if(logger.isTraceEnabled()){ logger.trace("createColumnFromRsMetaData(rsMetaData={}, rsIndex={}," + " tableName={}, dataTypeFactory={}) - start", new Object[]{rsMetaData, String.valueOf(rsIndex), tableName, dataTypeFactory}); } int columnType = rsMetaData.getColumnType(rsIndex); String columnTypeName = rsMetaData.getColumnTypeName(rsIndex); String columnName = rsMetaData.getColumnName(rsIndex); int isNullable = rsMetaData.isNullable(rsIndex); DataType dataType = dataTypeFactory.createDataType( columnType, columnTypeName, tableName, columnName); Column column = new Column( columnName, dataType, columnTypeName, Column.nullableValue(isNullable)); return column; } /** * Try to create the Column using information from the given {@link ResultSetMetaData} * to search the column via the given {@link DatabaseMetaData}. If the * {@link ResultSetMetaData} does not provide the required information * (one of catalog/schema/table is "") * the search for the Column via {@link DatabaseMetaData} is not executed and null * is returned immediately. * @param rsMetaData The {@link ResultSetMetaData} from which to retrieve the {@link DatabaseMetaData} * @param rsIndex The current index in the {@link ResultSetMetaData} * @param databaseMetaData The {@link DatabaseMetaData} which is used to lookup detailed * information about the column if possible * @param dataTypeFactory dbunit {@link IDataTypeFactory} needed to create the Column * @param metadataHandler the handler to be used for {@link DatabaseMetaData} handling * @return The column or null if it can be not created using a * {@link DatabaseMetaData} object because of missing information in the * {@link ResultSetMetaData} object * @throws SQLException * @throws DataTypeException */ private Column createColumnFromDbMetaData(ResultSetMetaData rsMetaData, int rsIndex, DatabaseMetaData databaseMetaData, IDataTypeFactory dataTypeFactory, IMetadataHandler metadataHandler) throws SQLException, DataTypeException { if(logger.isTraceEnabled()){ logger.trace("createColumnFromMetaData(rsMetaData={}, rsIndex={}," + " databaseMetaData={}, dataTypeFactory={}, columnFactory={}) - start", new Object[]{rsMetaData, String.valueOf(rsIndex), databaseMetaData, dataTypeFactory, metadataHandler}); } // use DatabaseMetaData to retrieve the actual column definition String catalogName = rsMetaData.getCatalogName(rsIndex); String schemaName = rsMetaData.getSchemaName(rsIndex); String tableName = rsMetaData.getTableName(rsIndex); String columnName = rsMetaData.getColumnName(rsIndex); // Due to a bug in the DB2 JDBC driver we have to trim the names catalogName = trim(catalogName); schemaName = trim(schemaName); tableName = trim(tableName); columnName = trim(columnName); // Check if at least one of catalog/schema/table attributes is // not applicable (i.e. "" is returned). If so do not try // to get the column metadata from the DatabaseMetaData object. // This is the case for all oracle JDBC drivers if(catalogName != null && catalogName.equals("")) { // Catalog name is not required catalogName = null; } if(schemaName != null && schemaName.equals("")) { logger.debug("The 'schemaName' from the ResultSetMetaData is empty-string and not applicable hence. " + "Will not try to lookup column properties via DatabaseMetaData.getColumns."); return null; } if(tableName != null && tableName.equals("")) { logger.debug("The 'tableName' from the ResultSetMetaData is empty-string and not applicable hence. " + "Will not try to lookup column properties via DatabaseMetaData.getColumns."); return null; } if(logger.isDebugEnabled()) logger.debug("All attributes from the ResultSetMetaData are valid, " + "trying to lookup values in DatabaseMetaData. catalog={}, schema={}, table={}, column={}", new Object[]{catalogName, schemaName, tableName, columnName} ); // All of the retrieved attributes are valid, // so lookup the column via DatabaseMetaData ResultSet columnsResultSet = metadataHandler.getColumns(databaseMetaData, schemaName, tableName); try { // Scroll resultset forward - must have one result which exactly matches the required parameters scrollTo(columnsResultSet, metadataHandler, catalogName, schemaName, tableName, columnName); Column column = SQLHelper.createColumn(columnsResultSet, dataTypeFactory, true); return column; } catch(IllegalStateException e) { logger.warn("Cannot find column from ResultSetMetaData info via DatabaseMetaData. Returning null." + " Even if this is expected to never happen it probably happened due to a JDBC driver bug." + " To get around this you may want to configure a user defined " + IMetadataHandler.class, e); return null; } finally { SQLHelper.close(columnsResultSet); } } /** * Trims the given string in a null-safe way * @param value * @return * @since 2.4.6 */ private String trim(String value) { return (value==null ? null : value.trim()); } private void scrollTo(ResultSet columnsResultSet, IMetadataHandler metadataHandler, String catalog, String schema, String table, String column) throws SQLException { while(columnsResultSet.next()) { boolean match = metadataHandler.matches(columnsResultSet, catalog, schema, table, column, _caseSensitiveMetaData); if(match) { // All right. Return immediately because the resultSet is positioned on the correct row return; } } // If we get here the column could not be found String msg = "Did not find column '" + column + "' for '" + schema + "." + table + "' in catalog '" + catalog + "' because names do not exactly match."; throw new IllegalStateException(msg); } public Column[] getColumns() throws DataSetException { return this.wrappedTableMetaData.getColumns(); } public Column[] getPrimaryKeys() throws DataSetException { return this.wrappedTableMetaData.getPrimaryKeys(); } public String getTableName() { return this.wrappedTableMetaData.getTableName(); } public String toString() { StringBuffer sb = new StringBuffer(); sb.append(getClass().getName()).append("["); sb.append("wrappedTableMetaData=").append(this.wrappedTableMetaData); sb.append("]"); return sb.toString(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy