/* 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.util.Iterator; import xxl.core.cursors.Cursor; import xxl.core.cursors.Cursors; import xxl.core.cursors.sources.SingleObjectCursor; import xxl.core.util.metaData.MetaDataException; /** * Appends a number of given ResultSetMetaData objects to each other and * returns a new ResultSetMetaData object. */ public class AppendedResultSetMetaData extends MergedResultSetMetaData { /** * An array of int value holding the column counts from the underlying * wrapped ResultSetMetaData objects. */ protected int[] columnCounts; /** * An int value holding the column count for the AppendedResultSetMetaData * objectt. */ protected int columnCount; /** * Constructs an AppendedResultSetMetaData object that wraps the given * ResultSetMetaData objects. * * @param metaData an array holding the ResultSetMetaData objects to be * appended to one ResultSetMetaData object. */ public AppendedResultSetMetaData(ResultSetMetaData... metaData) { super(metaData); try { columnCounts = new int[this.metaData.length]; for (int i = 0; i < this.metaData.length; i++) columnCount += columnCounts[i] = metaData[i].getColumnCount(); } catch (SQLException sqle) { throw new MetaDataException("meta data cannot be constructed due to the following sql exception: " + sqle.getMessage()); } } /** * Constructs an AppendedResultSetMetaData object that wraps the * ResultSetMetaData objects contained by the given iteration. * * @param metaData an iteration holding the ResultSetMetaData objects to be * appended to one ResultSetMetaData object. */ public AppendedResultSetMetaData(Iterator<? extends ResultSetMetaData> metaData) { this(Cursors.toFittingArray(metaData, new ResultSetMetaData[0])); } /** * Returns the number of columns. The number of columns of an * AppendedResultSetMetaData object is equal to the sum of the number of * columns of the appended ResultSetMetaData objects. * * @return the number of columns. * @throws SQLException if a database access error occurs. */ @Override public int getColumnCount() throws SQLException { return columnCount; } /** * Returns an iteration over the indices of the underlying * ResultSetMetaData objects the given column is originated in. Iterates * over the ResultSetMetaData objects wrapped by this * AppendedResultSetMetaData object and subtracts the number of columns * from the given column as long as the number of columns are greater than * the given (modified) column. When the (modified) column is smaller than * or equal to the number of columns the column is located in the actual * ResultSetMetaData object and has the (modified) column index. * * @param column number of the column: the first column is 1, the second is * 2, ... * @return returns an iteration over the indices of the underlying * ResultSetMetaData objects the given column is originated in. * @throws SQLException if a database access error occurs. */ @Override public Cursor<Integer> originalMetaDataIndices(int column) throws SQLException { if (1 <= column) for (int i = 0; i < metaData.length; i++) if (column > columnCounts[i]) column -= columnCounts[i]; else return new SingleObjectCursor<Integer>(column); throw new SQLException("the specified column " + column + " cannot be identified"); } /** * Determines the original column index from the underlying * ResultSetMetaData object with the given index, on which the specified * column of this object is based. * * @param originalMetaData the index of the underlying ResultSetMetaData * object that should be tested for being the origin of the * specified column. * @param column number of the column: the first column is 1, the second is * 2, ... If the given column does not originate in the specified * ResultSetMetaData object, the return value has to be 0. * @return the original column number from the underlying ResultSetMetaData * object with the given index, on which the specified column of * this object is based. * @throws SQLException if a database access error occurs. */ @Override public int originalColumnIndex(int originalMetaData, int column) throws SQLException { if (0 <= originalMetaData && originalMetaData < metaData.length) { for (int i = 0; i < originalMetaData; column -= columnCounts[i], i++); return 1 <= column && column <= columnCounts[originalMetaData] ? column : 0; } throw new SQLException("the specified metadata index " + originalMetaData + " cannot be identified"); } /** * Determines the original ResultSetMetaData objects and column indices, on * which the specified column of this object is based. Iterates over the * ResultSetMetaData objects wrapped by this AppendedResultSetMetaData * object and subtracts the number of columns from the given column as long * as the number of columns are greater than the given (modified) column. * When the (modified) column is smaller than or equal to the number of * columns the column is located in the actual ResultSetMetaData object and * has the (modified) column index. * * @param column number of the column: the first column is 1, the second is * 2, ... If the given column does not originate in the specified * ResultSetMetaData object, the return value has to be 0. * @return the original ResultSetMetaData objects and column indices, on * which the specified column of this object is based. The returned * iteration contains two-dimensional <code>int</code>-arrays * holding the index of the original ResultSetMetaData object and * the index of the original column. * @throws SQLException if a database access error occurs. */ @Override public Cursor<int[]> originalColumnIndices(int column) throws SQLException { if (1 <= column) for (int i = 0; i < metaData.length; i++) if (column > columnCounts[i]) column -= columnCounts[i]; else return new SingleObjectCursor<int[]>(new int[] {i, column}); throw new SQLException("the specified column " + column + " cannot be identified"); } /** * 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); } }