/* XXL: The eXtensible and fleXible Library for data processing Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger Head of the Database Research Group Department of Mathematics and Computer Science University of Marburg Germany 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 3 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, see <http://www.gnu.org/licenses/>. http://code.google.com/p/xxl/ */ package xxl.core.relational.metaData; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Types; import xxl.core.util.metaData.MetaDataException; /** * This class provides an extended decorator for metadata of the type * <code>ResultSetMetaData</code>. Calls to the methods of this class * (<code>getXXX(int column)</code>) are redirected to the wrapped instance * (<code>getXXX(<b>originalColumnIndex(column)</b>)</code>). Note, that the * given column index of the original method call is substituded by a mapped * column index. This mapping, performed by the * <code>originalColumnIndex</code> method, can be easily used to create * relational metadata for projection operators. (In this case, the * <code>getColumnCount</code> method must also be overwritten to return the * correct number of projected columns.) */ public class WrappedResultSetMetaData implements ResultSetMetaData { /** * The wrapped relational metadata calls to this class' methods are * redirected to. */ protected ResultSetMetaData metaData; /** * Constructs a new relational metadata that wraps the given object of type * <code>ResultSetMetaData</code>. * * @param resultSetMetaData the relational metadata to be wrapped. */ public WrappedResultSetMetaData(ResultSetMetaData resultSetMetaData) { metaData = resultSetMetaData; } /** * Returns the column number of the original relational metadata that has * been mapped to the column number value that is passed to the call. * * @param column column number of the mapped relational metadata. * @return column number of the original relational metadata. * @throws SQLException if a database access error occurs. Can be used to * perform column checks. */ @SuppressWarnings("unused") // SQLException is used by subclasses protected int originalColumnIndex(int column) throws SQLException { return column; } // ************************************************************************ // * methods of interface WrappedResultSetMetaData * // ************************************************************************ /** * Returns the number of columns in this <code>ResultSet</code> object. * * @return the number of columns. * @throws SQLException if a database access error occurs. */ public int getColumnCount() throws SQLException { return metaData.getColumnCount(); } /** * Indicates whether the designated column is automatically numbered, thus * read-only. * * @param column the first column is 1, the second is 2, ... * @return <code>true</code> if so; <code>false</code> otherwise. * @throws SQLException if a database access error occurs. */ public boolean isAutoIncrement(int column) throws SQLException { return metaData.isAutoIncrement(originalColumnIndex(column)); } /** * Indicates whether a column's case matters. * * @param column the first column is 1, the second is 2, ... * @return <code>true</code> if so; <code>false</code> otherwise. * @throws SQLException if a database access error occurs. */ public boolean isCaseSensitive(int column) throws SQLException { return metaData.isCaseSensitive(originalColumnIndex(column)); } /** * Indicates whether the designated column can be used in a where clause. * * @param column the first column is 1, the second is 2, ... * @return <code>true</code> if so; <code>false</code> otherwise. * @throws SQLException if a database access error occurs. */ public boolean isSearchable(int column) throws SQLException { return metaData.isSearchable(originalColumnIndex(column)); } /** * Indicates whether the designated column is a cash value. * * @param column the first column is 1, the second is 2, ... * @return <code>true</code> if so; <code>false</code> otherwise. * @throws SQLException if a database access error occurs. */ public boolean isCurrency(int column) throws SQLException { return metaData.isCurrency(originalColumnIndex(column)); } /** * Indicates the nullability of values in the designated column. * * @param column the first column is 1, the second is 2, ... * @return the nullability status of the given column; one of * {@link ResultSetMetaData#columnNoNulls}, * {@link ResultSetMetaData#columnNullable} or * {@link ResultSetMetaData#columnNullableUnknown}. * @throws SQLException if a database access error occurs. */ public int isNullable(int column) throws SQLException { return metaData.isNullable(originalColumnIndex(column)); } /** * Indicates whether values in the designated column are signed numbers. * * @param column the first column is 1, the second is 2, ... * @return <code>true</code> if so; <code>false</code> otherwise. * @throws SQLException if a database access error occurs. */ public boolean isSigned(int column) throws SQLException { return metaData.isSigned(originalColumnIndex(column)); } /** * Indicates the designated column's normal maximum width in characters. * * @param column the first column is 1, the second is 2, ... * @return the normal maximum number of characters allowed as the width of * the designated column. * @throws SQLException if a database access error occurs. */ public int getColumnDisplaySize(int column) throws SQLException { return metaData.getColumnDisplaySize(originalColumnIndex(column)); } /** * Gets the designated column's suggested title for use in printouts and * displays. * * @param column the first column is 1, the second is 2, ... * @return the suggested column title. * @throws SQLException if a database access error occurs. */ public String getColumnLabel(int column) throws SQLException { return metaData.getColumnLabel(originalColumnIndex(column)); } /** * Get the designated column's name. * * @param column the first column is 1, the second is 2, ... * @return column name. * @throws SQLException if a database access error occurs. */ public String getColumnName(int column) throws SQLException { return metaData.getColumnName(originalColumnIndex(column)); } /** * Get the designated column's table's schema. * * @param column the first column is 1, the second is 2, ... * @return schema name or "" if not applicable. * @throws SQLException if a database access error occurs. */ public String getSchemaName(int column) throws SQLException { return metaData.getSchemaName(originalColumnIndex(column)); } /** * Get the designated column's number of decimal digits. * * @param column the first column is 1, the second is 2, ... * @return precision. * @throws SQLException if a database access error occurs. */ public int getPrecision(int column) throws SQLException { return metaData.getPrecision(originalColumnIndex(column)); } /** * Gets the designated column's number of digits to right of the decimal * point. * * @param column the first column is 1, the second is 2, ... * @return scale. * @throws SQLException if a database access error occurs. */ public int getScale(int column) throws SQLException { return metaData.getScale(originalColumnIndex(column)); } /** * Gets the designated column's table name. * * @param column the first column is 1, the second is 2, ... * @return table name or "" if not applicable. * @throws SQLException if a database access error occurs. */ public String getTableName(int column) throws SQLException { return metaData.getTableName(originalColumnIndex(column)); } /** * Gets the designated column's table's catalog name. * * @param column the first column is 1, the second is 2, ... * @return the name of the catalog for the table in which the given column * appears or "" if not applicable. * @throws SQLException if a database access error occurs. */ public String getCatalogName(int column) throws SQLException { return metaData.getCatalogName(originalColumnIndex(column)); } /** * Retrieves the designated column's SQL type. * * @param column the first column is 1, the second is 2, ... * @return SQL type from java.sql.Types. * @throws SQLException if a database access error occurs. * @see Types */ public int getColumnType(int column) throws SQLException { return metaData.getColumnType(originalColumnIndex(column)); } /** * Retrieves the designated column's database-specific type name. * * @param column the first column is 1, the second is 2, ... * @return type name used by the database. If the column type is a * user-defined type, then a fully-qualified type name is returned. * @throws SQLException if a database access error occurs. */ public String getColumnTypeName(int column) throws SQLException { return metaData.getColumnTypeName(originalColumnIndex(column)); } /** * Indicates whether the designated column is definitely not writable. * * @param column the first column is 1, the second is 2, ... * @return <code>true</code> if so; <code>false</code> otherwise. * @throws SQLException if a database access error occurs. */ public boolean isReadOnly(int column) throws SQLException { return metaData.isReadOnly(originalColumnIndex(column)); } /** * Indicates whether it is possible for a write on the designated column to * succeed. * * @param column the first column is 1, the second is 2, ... * @return <code>true</code> if so; <code>false</code> otherwise. * @throws SQLException if a database access error occurs. */ public boolean isWritable(int column) throws SQLException { return metaData.isWritable(originalColumnIndex(column)); } /** * Indicates whether a write on the designated column will definitely * succeed. * * @param column the first column is 1, the second is 2, ... * @return <code>true</code> if so; <code>false</code> otherwise. * @throws SQLException if a database access error occurs. */ public boolean isDefinitelyWritable(int column) throws SQLException { return metaData.isDefinitelyWritable(originalColumnIndex(column)); } /** * Returns the fully-qualified name of the Java class whose instances are * manufactured if the method <code>ResultSet.getObject</code> is called to * retrieve a value from the column. <code>ResultSet.getObject</code> may * return a subclass of the class returned by this method. * * @param column the first column is 1, the second is 2, ... * @return the fully-qualified name of the class in the Java programming * language that would be used by the method. * <code>ResultSet.getObject</code> to retrieve the value in the * specified column. This is the class name used for custom * mapping. * @throws SQLException if a database access error occurs. */ public String getColumnClassName(int column) throws SQLException { return metaData.getColumnClassName(originalColumnIndex(column)); } /** * Returns a string representation of the object. In general, the * <code>toString</code> method returns a string that "textually * represents" this object. * * @return a string representation of the object. */ @Override public String toString() { try { if (getColumnCount() == 0) return "[]"; StringBuffer string = new StringBuffer().append('[').append(getColumnTypeName(1)).append(' ').append(getColumnName(1)); for (int column = 2; column <= getColumnCount(); column++) string.append(", ").append(getColumnTypeName(column)).append(' ').append(getColumnName(column)); return string.append(']').toString(); } catch (SQLException sqle) { throw new MetaDataException("sql exception occured during string construction: \'" + sqle.getMessage() + "\'"); } } /** * Indicates whether some other object is "equal to" this relational * metadata. * * <p>The <code>equals</code> method implements an equivalence relation: * <ul> * <li> * It is <i>reflexive</i>: for any reference value <code>x</code>, * <code>x.equals(x)</code> should return <code>true</code>. * </li> * <li> * It is <i>symmetric</i>: for any reference values <code>x</code> * and <code>y</code>, <code>x.equals(y)</code> should return * <code>true</code> if and only if <code>y.equals(x)</code> * returns <code>true</code>. * </li> * <li> * It is <i>transitive</i>: for any reference values * <code>x</code>, <code>y</code>, and <code>z</code>, if * <code>x.equals(y)</code> returns <code>true</code> and * <code>y.equals(z)</code> returns <code>true</code>, then * <code>x.equals(z)</code> should return <code>true</code>. * </li> * <li> * It is <i>consistent</i>: for any reference values <code>x</code> * and <code>y</code>, multiple invocations of * <code>x.equals(y)</code> consistently return <code>true</code> * or consistently return <code>false</code>, provided no * information used in <code>equals</code> comparisons on the * object is modified. * </li> * <li> * For any non-<code>null</code> reference value <code>x</code>, * <code>x.equals(null)</code> should return <code>false</code>. * </li> * </ul></p> * * <p>The current <code>equals</code> method returns true if and only if * the given object: * <ul> * <li> * is this relational metadata or * </li> * <li> * is an instance of the type <code>ResultSetMetaData</code> and a * {@link ResultSetMetaDatas#RESULTSET_METADATA_COMPARATOR comparator} * for relational metadata returns 0. * </li> * </ul></p> * * @param object the reference object with which to compare. * @return <code>true</code> if this object is the same as the specified * object; <code>false</code> otherwise. * @see #hashCode() */ @Override public boolean equals(Object object) { if (object == null) return false; if (this == object) return true; return object instanceof ResultSetMetaData && ResultSetMetaDatas.RESULTSET_METADATA_COMPARATOR.compare(this, (ResultSetMetaData)object) == 0; } /** * Returns the hash code value for this relational metadata using a * {@link ResultSetMetaDatas#RESULTSET_METADATA_HASH_FUNCTION hash function} * for relational metadata. * * @return the hash code value for this relational metadata. * @see Object#hashCode() * @see #equals(Object) */ @Override public int hashCode() { return ResultSetMetaDatas.RESULTSET_METADATA_HASH_FUNCTION.invoke(this); } /** * Returns an object that implements the given interface to allow access to * non-standard methods, or standard methods not exposed by the proxy. The * result may be either the object found to implement the interface or a * proxy for that object. If the receiver implements the interface then * that is the object. If the receiver is a wrapper and the wrapped object * implements the interface then that is the object. Otherwise the object * is the result of calling <code>unwrap</code> recursively on the wrapped * object. If the receiver is not a wrapper and does not implement the * interface, then an <code>SQLException</code> is thrown. * * @param iface a class defining an interface that the result must * implement. * @return an object that implements the interface. May be a proxy for the * actual implementing object. * @throws SQLException if no object found that implements the interface. */ public <T> T unwrap(Class<T> iface) throws SQLException { throw new UnsupportedOperationException("this method is not implemented yet."); } /** * Returns true if this either implements the interface argument or is * directly or indirectly a wrapper for an object that does. Returns false * otherwise. If this implements the interface then return true, else if * this is a wrapper then return the result of recursively calling * <code>isWrapperFor</code> on the wrapped object. If this does not * implement the interface and is not a wrapper, return false. This method * should be implemented as a low-cost operation compared to * <code>unwrap</code> so that callers can use this method to avoid * expensive <code>unwrap</code> calls that may fail. If this method * returns true then calling <code>unwrap</code> with the same argument * should succeed. * * @param iface a class defining an interface. * @return true if this implements the interface or directly or indirectly * wraps an object that does. * @throws SQLException if an error occurs while determining whether this * is a wrapper for an object with the given interface. */ public boolean isWrapperFor(Class<?> iface) throws SQLException { throw new UnsupportedOperationException("this method is not implemented yet."); } }