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

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

/*
 *
 * 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$ * @version $Revision$ $Date$ * @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.getColumnLabel(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.getColumnLabel(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