/* Copyright (c) 2001-2009, The HSQL Development Group * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the HSQL Development Group nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG, * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.hsqldb.jdbc; import java.sql.ResultSetMetaData; import java.sql.SQLException; import org.hsqldb.ColumnBase; import org.hsqldb.ErrorCode; import org.hsqldb.Types; import org.hsqldb.persist.HsqlProperties; import org.hsqldb.result.ResultMetaData; import org.hsqldb.types.CharacterType; import org.hsqldb.types.Type; /* $Id: JDBCResultSetMetaData.java 2980 2009-05-02 14:38:05Z fredt $ */ // fredt@users - 20040412 - removed DITypeInfo dependencies // boucherb@users - 200404xx - removed unused imports;refinement for better // usability of getColumnDisplaySize; // javadoc updates // boucherb@users - 20051207 - patch 1.8.0.x initial JDBC 4.0 support work // boucherb@users - 20060522 - doc 1.9.0 full synch up to Mustang Build 84 // fredt@users - 1.9.0 usage of types and new ResultMetadata and ColumnMetaData // Revision 1.15 2006/07/12 12:29:42 boucherb // patch 1.9.0 // - full synch up to Mustang b90 // - minor update to toString /** * <!-- start generic documentation --> * An object that can be used to get information about the types * and properties of the columns in a <code>ResultSet</code> object. * The following code fragment creates the <code>ResultSet</code> object rs, * creates the <code>ResultSetMetaData</code> object rsmd, and uses rsmd * to find out how many columns rs has and whether the first column in rs * can be used in a <code>WHERE</code> clause. * <PRE> * * ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM TABLE2"); * ResultSetMetaData rsmd = rs.getMetaData(); * int numberOfColumns = rsmd.getColumnCount(); * boolean b = rsmd.isSearchable(1); * * </PRE> * <!-- end generic documentation --> * * <!-- start Release-specific documentation --> * <div class="ReleaseSpecificDocumentation"> * <h3>HSQLDB-Specific Information:</h3> <p> * * HSQLDB supports a subset of the <code>ResultSetMetaData</code> interface.<p> * * The JDBC specification for <code>ResultSetMetaData</code> is in part very * vague. This causes potential incompatibility between interpretations of the * specification as realized in different JDBC driver implementations. As such, * deciding to what degree reporting ResultSetMetaData is accurate has been * considered very carefully. Hopefully, the design decisions made in light of * these considerations have yeilded precisely the subset of full * ResultSetMetaData support that is most commonly needed and that is most * important, while also providing, under the most common use-cases, the * fastest access with the least overhead and the best comprimise between * speed, accuracy, jar-footprint and retention of JDBC resources. <p> * * (fredt@users) <br> * (boucherb@users)<p> * </div> * <!-- end release-specific documentation --> * * @author Campbell Boucher-Burnett (boucherb@users dot sourceforge.net) * @author Fred Toussi (fredt@users dot sourceforge.net) * @version 1.9.0 * @revised JDK 1.6, HSQLDB 1.8.x * @see JDBCStatement#executeQuery * @see JDBCStatement#getResultSet * @see java.sql.ResultSetMetaData */ public class JDBCResultSetMetaData implements ResultSetMetaData { /** * <!-- start generic documentation --> * Returns the number of columns in this <code>ResultSet</code> object. * * <!-- end generic documentation --> * @return the number of columns * @exception SQLException if a database access error occurs */ public int getColumnCount() throws SQLException { return resultMetaData.getColumnCount(); } /** * <!-- start generic documentation --> * Indicates whether the designated column is automatically numbered. * <p>(JDBC4 deleted:)[, thus read-only.] * <!-- end generic documentation --> * * <!-- start Release-specific documentation --> * <div class="ReleaseSpecificDocumentation"> * <h3>HSQLDB-Specific Information:</h3> <p> * * HSQLDB 1.9.0 fully supports SQL Satandard features T174 and T176 that * define identity column support. * * <hr> * * However, it must be stated here that contrary to the generic * documentation previous to the JDBC4 specification, HSQLDB automatically * numbered columns (IDENTITY columns, in HSQLDB parlance) are not * read-only. <p> * * In fact, the generic documentation previous to the JDBC4 specification * seems to contradict the general definition of what, at minimum, * an auto-increment column is: <p> * * Simply, an auto-increment column is one that guarantees it has a * autogenerated value after a successful insert or update operation, * even if no value is supplied, or DEFAULT is specified.<p> * * </div> * <!-- end release-specific documentation --> * * @param column the first column is 1, the second is 2, ... * @return <code>true</code> if so; <code>false</code> otherwise * @exception SQLException if a database access error occurs */ public boolean isAutoIncrement(int column) throws SQLException { checkColumn(column); return resultMetaData.columns[--column].isIdentity(); } /** * <!-- start generic documentation --> * Indicates whether a column's case matters. * <!-- end generic documentation --> * * <!-- start Release-specific documentation --> * <div class="ReleaseSpecificDocumentation"> * <h3>HSQLDB-Specific Information:</h3> <p> * * HSQLDB 1.7.1 did not report this value accurately. <p> * * Starting with 1.7.2, this feature is better supported. <p> * * This method returns true for any column whose data type is a character * type, with the exception of VARCHAR_IGNORECASE for which it returns * false. It also returns false for any column whose data type is a * not a character data type. <p> * * </div> * <!-- end release-specific documentation --> * * @param column the first column is 1, the second is 2, ... * @return <code>true</code> if so; <code>false</code> otherwise * @exception SQLException if a database access error occurs */ public boolean isCaseSensitive(int column) throws SQLException { checkColumn(column); Type type = resultMetaData.columnTypes[--column]; if (type.isCharacterType()) { return !((CharacterType) type).isCaseInsensitive(); } return false; } /** * <!-- start generic documentation --> * Indicates whether the designated column can be used in a where clause. * <!-- end generic documentation --> * * <!-- start Release-specific documentation --> * <div class="ReleaseSpecificDocumentation"> * <h3>HSQLDB-Specific Information:</h3> <p> * * HSQLDB 1.9.0 handles this differently from previous versions. <p> * * If the column in question is a database table or view column, and the * type of the column allows searching, then returns true, otherwise false. * * </div> * <!-- end release-specific documentation --> * * @param column the first column is 1, the second is 2, ... * @return <code>true</code> if so; <code>false</code> otherwise * @exception SQLException if a database access error occurs */ public boolean isSearchable(int column) throws SQLException { checkColumn(column); return resultMetaData.columns[--column].isSearchable(); } /** * <!-- start generic documentation --> * Indicates whether the designated column is a cash value. * <!-- end generic documentation --> * * <!-- start Release-specific documentation --> * <div class="ReleaseSpecificDocumentation"> * <h3>HSQLDB-Specific Information:</h3> <p> * * HSQLDB 1.9.0 fully supports this feature and returns true for * NUMERIC and DECIMAL columns. <p> * * </div> * <!-- end release-specific documentation --> * * @param column the first column is 1, the second is 2, ... * @return <code>true</code> if so; <code>false</code> otherwise * @exception SQLException if a database access error occurs */ public boolean isCurrency(int column) throws SQLException { checkColumn(column); Type type = resultMetaData.columnTypes[--column]; return (type.typeCode == Types.SQL_DECIMAL || type.typeCode == Types.SQL_NUMERIC) && type.scale > 0; } /** * <!-- start generic documentation --> * Indicates the nullability of values in the designated column. * <!-- end generic documentation --> * * <!-- start Release-specific documentation --> * <div class="ReleaseSpecificDocumentation"> * <h3>HSQLDB-Specific Information:</h3> <p> * * HSQLDB 1.9.0 fully supports this feature. <p> * * <tt>columnNoNulls</tt> is always returned for result set columns * that do not directly represent table column values (i.e. are calculated), * while the corresponding value in [INFORMATION_SCHEMA.]SYSTEM_COLUMNS.NULLABLE * is returned for result set columns that do directly represent table * column values. <p> * * To determine the nullable status of a table column in isolation from * ResultSetMetaData and in a DBMS-independent fashion, the * DatabaseMetaData.getColumns() method can be invoked with the * appropriate filter values and the result should be inspected at the * position described in the DatabaseMetaData.getColumns() API * documentation. * </div> * <!-- end release-specific documentation --> * * @param column the first column is 1, the second is 2, ... * @return the nullability status of the given column; one of <code>columnNoNulls</code>, * <code>columnNullable</code> or <code>columnNullableUnknown</code> * @exception SQLException if a database access error occurs */ public int isNullable(int column) throws SQLException { checkColumn(column); return resultMetaData.columns[--column].getNullability(); } /** * <!-- start generic documentation --> * Indicates whether values in the designated column are signed numbers. * <!-- end generic documentation --> * * <!-- start Release-specific documentation --> * <div class="ReleaseSpecificDocumentation"> * <h3>HSQLDB-Specific Information:</h3> <p> * * HSQLDB 1.9.0 fully supports this feature. <p> * * </div> * <!-- end release-specific documentation --> * * @param column the first column is 1, the second is 2, ... * @return <code>true</code> if so; <code>false</code> otherwise * @exception SQLException if a database access error occurs */ public boolean isSigned(int column) throws SQLException { checkColumn(column); Type type = resultMetaData.columnTypes[--column]; return type.isNumberType(); } /** * <!-- start generic documentation --> * Indicates the designated column's normal maximum width in characters. * <!-- end generic documentation --> * * <!-- start Release-specific documentation --> * <div class="ReleaseSpecificDocumentation"> * <h3>HSQLDB-Specific Information:</h3> <p> * * HSQLDB 1.9.0 fully supports this feature. <p> * * The current calculation follows these rules: <p> * * <ol> * <li>Long character types and datetime types:<p> * * The maximum length/precision, repectively.<p> * * <li>CHAR and VARCHAR types: <p> * * <ul> * <li> If the result set column is a direct pass through of a table * column value and column size was declared, then the declared * value is returned. <p> * * <li> Otherwise, the computed length according to SQL Standard is * returned. For very large values, the value of the system property * hsqldb.max_xxxchar_display_size or the magic value * 32766 (0x7FFE) (tested usable/accepted by most tools and * compatible with assumptions made by java.io read/write * UTF) when the system property is not defined or is not * accessible, due to security constraints. <p> * * </ul> * * It must be noted that the latter value in no way affects the * ability of the HSQLDB JDBC driver to retrieve longer values * and serves only as the current best effort at providing a * value that maximizes usability across a wide range of tools, * given that the HSQLDB database engine allows very large * lengths to be declared. <p> * * <li>Number types: <p> * * The max precision, plus the length of the negation character (1), * plus (if applicable) the maximum number of characters that may * occupy the exponent character sequence. Note that some legacy tools * do not correctly handle BIGINT values of greater than 18 digits. <p> * * <li>BOOLEAN type: <p> * * The length of the character sequence "false" (5), the longer of the * two boolean value String representations. <p> * * <li>Remaining types: <p> * * The maximum length/precision, respectively, as reported by * DatabaseMetaData.getTypeInfo(), when applicable. If the maximum * display size is unknown, unknowable or inapplicable, then zero is * returned. <p> * * </ol> * * </div> * <!-- end release-specific documentation --> * * @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 * @exception SQLException if a database access error occurs */ public int getColumnDisplaySize(int column) throws SQLException { checkColumn(column); Type type = resultMetaData.columnTypes[--column]; return type.displaySize(); } /** * <!-- start generic documentation --> * Gets the designated column's suggested title for use in printouts and * displays. (JDBC4 clarification:) The suggested title is usually specified by the SQL <code>AS</code> * clause. If a SQL <code>AS</code> is not specified, the value returned from * <code>getColumnLabel</code> will be the same as the value returned by the * <code>getColumnName</code> method. * <!-- end generic documentation --> * * <!-- start Release-specific documentation --> * <div class="ReleaseSpecificDocumentation"> * <h3>HSQLDB-Specific Information:</h3> <p> * * In HSQLDB, a <code>ResultSet</code> column label is determined using the * following order of precedence:<p> * * <OL> * <LI>The label (alias) specified in the generating query.</LI> * <LI>The name of the underlying column, if no label is specified.<br> * <L1>C1, C2, etc. for computed columns that have no label.</LI> * </OL> <p> * * </div> * <!-- end release-specific documentation --> * * @param column the first column is 1, the second is 2, ... * @return the suggested column title * @exception SQLException if a database access error occurs */ public String getColumnLabel(int column) throws SQLException { checkColumn(column--); String label = resultMetaData.columnLabels[column]; return label == null ? resultMetaData.columns[column].getNameString() : label; } /** * <!-- start generic documentation --> * Get the designated column's name. * <!-- end generic documentation --> * * <!-- start Release-specific documentation --> * <div class="ReleaseSpecificDocumentation"> * <h3>HSQLDB-Specific Information:</h3> <p> * * In HSQLDB, a ResultSet column name is determined using the following * order of prcedence:<p> * * <OL> * <LI>The name of the underlying columnm, if the ResultSet column * represents a column in a table.</LI> * <LI>The label or alias specified in the generating query.</LI> * <L1>C1, C2, etc. for computed columns that have no label.</LI> * </OL> <p> * * If the <code>jdbc.get_column_name</code> property of the JDBC Connection * has been set to false, this method returns the same value as * {@link #getColumnLabel(int)}.<p> * * </div> * <!-- end release-specific documentation --> * * @param column the first column is 1, the second is 2, ... * @return column name * @exception SQLException if a database access error occurs */ public String getColumnName(int column) throws SQLException { checkColumn(column); if (useColumnName) { String name = resultMetaData.columns[--column].getNameString(); return name == null ? "" : name; } return resultMetaData.columnLabels[--column]; } /** * <!-- start generic documentation --> * Get the designated column's table's schema. * <!-- end generic documentation --> * * <!-- start Release-specific documentation --> * <div class="ReleaseSpecificDocumentation"> * <h3>HSQLDB-Specific Information:</h3> <p> * * Since 1.8.0.x, HSQLDB implements standard SQL SCHEMA support; * this method returns the actual schema of the column's table. * Columns generated in queries have no schema name. * </div> * <!-- end release-specific documentation --> * * @param column the first column is 1, the second is 2, ... * @return schema name or "" if not applicable * @exception SQLException if a database access error occurs */ public String getSchemaName(int column) throws SQLException { checkColumn(column); String name = resultMetaData.columns[--column].getSchemaNameString();; return name == null ? "" : name; } /** * <!-- start generic documentation --> * (JDBC4 clarification:) * Get the designated column's specified column size. * For numeric data, this is the maximum precision. For character data, this is the [maximum] length in characters. * For datetime datatypes, this is the [maximim] length in characters of the String representation (assuming the * maximum allowed precision of the fractional seconds component). For binary data, this is the [maximum] length in bytes. For the ROWID datatype, * this is the length in bytes[, as returned by the implementation-specific java.sql.RowId.getBytes() method]. 0 is returned for data types where the * column size is not applicable. * <!-- end generic documentation --> * * <!-- start Release-specific documentation --> * <div class="ReleaseSpecificDocumentation"> * <h3>HSQLDB-Specific Information:</h3> <p> * * Starting with 1.8.0, HSQLDB reports the declared length or precision * specifiers for table columns, if they are defined.<p> * * From 1.9.0, HSQLDB, reports the correct length or precision for * computed columns according to the SQL Standard.<p> * </div> * <!-- end release-specific documentation --> * * @param column the first column is 1, the second is 2, ... * @return precision * @exception SQLException if a database access error occurs */ public int getPrecision(int column) throws SQLException { checkColumn(column); // type in columnTypes overrides column type Type type = resultMetaData.columnTypes[--column]; long precision = type.precision; if (type.isDateTimeType() || type.isIntervalType()) { precision = type.displaySize(); } if (precision > Integer.MAX_VALUE) { precision = Integer.MAX_VALUE; } return (int) precision; } /** * <!-- start generic documentation --> * Gets the designated column's number of digits to right of the decimal point. * 0 is returned for data types where the scale is not applicable. * <!-- end generic documentation --> * * <!-- start Release-specific documentation --> * <div class="ReleaseSpecificDocumentation"> * <h3>HSQLDB-Specific Information:</h3> <p> * * Starting with 1.8.0, HSQLDB reports the declared * scale for table columns.<p> * * From 1.9.0, HSQLDB, reports the correct scale for * computed columns according to the SQL Standard.<p> * * <pre> * sql.enforce_strict_size * </pre> * For datetime and interval types such as Timestamp or Time, the * fractional second precision is reported. * </div> * <!-- end release-specific documentation --> * * @param column the first column is 1, the second is 2, ... * @return scale * @exception SQLException if a database access error occurs */ public int getScale(int column) throws SQLException { Type type = resultMetaData.columnTypes[--column]; return type.scale; } /** * <!-- start generic documentation --> * Gets the designated column's table name. * * <!-- end generic documentation --> * @param column the first column is 1, the second is 2, ... * @return table name or "" if not applicable * @exception SQLException if a database access error occurs */ public String getTableName(int column) throws SQLException { checkColumn(column); String name = resultMetaData.columns[--column].getTableNameString(); return name == null ? "" : name; } /** * <!-- start generic documentation --> * Gets the designated column's table's catalog name. * <!-- end generic documentation --> * * <!-- start Release-specific documentation --> * <div class="ReleaseSpecificDocumentation"> * <h3>HSQLDB-Specific Information:</h3> <p> * * From 1.9.0, HSQLDB returns the name of the catalog. The default name is * PUBLIC. * This value can be changed for the database using an SQL command.<p> * * HSQLDB supports use of catalog qualification in DLL or DML when it is * allowed by the Standard. <p> * * However, not all clients respect the SQL Standard and may use a * catalog qualifier in a context where it is not suppoted by the Standard. * <p> * * For greater detail, see discussion at: * {@link JDBCDatabaseMetaData}. <p> * * </div> * <!-- end release-specific documentation --> * * @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 * @exception SQLException if a database access error occurs */ public String getCatalogName(int column) throws SQLException { checkColumn(column); String name = resultMetaData.columns[--column].getCatalogNameString(); return name == null ? "" : name; } /** * <!-- start generic documentation --> * Retrieves the designated column's SQL type. * <!-- end generic documentation --> * * <!-- start Release-specific documentation --> * <div class="ReleaseSpecificDocumentation"> * <h3>HSQLDB-Specific Information:</h3> <p> * * This reports the SQL type code of the column. For time and timestamp * types that are WITH TIME ZONE, the values as the SQL Standarc CLI * codes.<p> * * </div> * <!-- end release-specific documentation --> * * * @param column the first column is 1, the second is 2, ... * @return SQL type from java.sql.Types * @exception SQLException if a database access error occurs * @see java.sql.Types */ public int getColumnType(int column) throws SQLException { checkColumn(column); Type type = resultMetaData.columnTypes[--column]; return type.getJDBCTypeCode(); } /** * <!-- start generic documentation --> * Retrieves the designated column's database-specific type name. * <!-- end generic documentation --> * * @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. * @exception SQLException if a database access error occurs */ public String getColumnTypeName(int column) throws SQLException { checkColumn(column); Type type = resultMetaData.columnTypes[--column]; return type.getNameString(); } /** * <!-- start generic documentation --> * Indicates whether the designated column is definitely not writable. * <!-- end generic documentation --> * * <!-- start Release-specific documentation --> * <div class="ReleaseSpecificDocumentation"> * <h3>HSQLDB-Specific Information:</h3> <p> * * From 1.9.0 this method returns true if the ResuleSet is not updatable * or the column in question is not updatable.<p> * </div> * <!-- end release-specific documentation --> * * @param column the first column is 1, the second is 2, ... * @return <code>true</code> if so; <code>false</code> otherwise * @exception SQLException if a database access error occurs */ public boolean isReadOnly(int column) throws SQLException { checkColumn(column); return !resultMetaData.columns[--column].isWriteable(); } /** * <!-- start generic documentation --> * Indicates whether it is possible for a write on the designated column to * succeed. * <!-- end generic documentation --> * * <!-- start Release-specific documentation --> * <div class="ReleaseSpecificDocumentation"> * <h3>HSQLDB-Specific Information:</h3> <p> * * From 1.9.0 this method returns false if the ResuleSet is not updatable * or the column in question is not updatable.<p> * * </div> * <!-- end release-specific documentation --> * * @param column the first column is 1, the second is 2, ... * @return <code>true</code> if so; <code>false</code> otherwise * @exception SQLException if a database access error occurs */ public boolean isWritable(int column) throws SQLException { checkColumn(column); return resultMetaData.colIndexes != null && resultMetaData.colIndexes[--column] > -1; } /** * <!-- start generic documentation --> * Indicates whether a write on the designated column will definitely succeed. * <!-- end generic documentation --> * * <!-- start Release-specific documentation --> * <div class="ReleaseSpecificDocumentation"> * <h3>HSQLDB-Specific Information:</h3> <p> * * From 1.9.0 this method returns false if the ResuleSet is not updatable * or the column in question is not updatable.<p> * * </div> * <!-- end release-specific documentation --> * * @param column the first column is 1, the second is 2, ... * @return <code>true</code> if so; <code>false</code> otherwise * @exception SQLException if a database access error occurs */ public boolean isDefinitelyWritable(int column) throws SQLException { checkColumn(column); return resultMetaData.colIndexes != null && resultMetaData.colIndexes[--column] > -1; } //--------------------------JDBC 2.0----------------------------------- /** * <!-- start generic documentation --> * <p>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. * <!-- end generic documentation --> * * <!-- start Release-specific documentation --> * <div class="ReleaseSpecificDocumentation"> * <h3>HSQLDB-Specific Information:</h3> <p> * * HSQLDB 1.9.0 fully supports this feature.<p> * * For columns of type OTHER, there is no specific class name and * java.lang.Object is returned. * * </div> * <!-- end release-specific documentation --> * * @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. * @exception SQLException if a database access error occurs * @since JDK 1.2 (JDK 1.1.x developers: read the overview for * JDBCResultSet) */ public String getColumnClassName(int column) throws SQLException { checkColumn(column); Type type = resultMetaData.columnTypes[--column]; return type.getJDBCClassName(); } //----------------------------- JDBC 4.0 ----------------------------------- // ------------------- java.sql.Wrapper implementation --------------------- /** * Returns an object that implements the given interface to allow access to * non-standard methods, or standard methods not exposed by the proxy. * * If the receiver implements the interface then the result is the receiver * or a proxy for the receiver. If the receiver is a wrapper * and the wrapped object implements the interface then the result is the * wrapped object or a proxy for the wrapped object. Otherwise return the * the result of calling <code>unwrap</code> recursively on the wrapped object * or a proxy for that result. 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 java.sql.SQLException If no object found that implements the interface * @since JDK 1.6, HSQLDB 1.8.x */ //#ifdef JAVA6 @SuppressWarnings("unchecked") public <T>T unwrap(java.lang.Class<T> iface) throws java.sql.SQLException { if (isWrapperFor(iface)) { return (T) this; } throw Util.invalidArgument("iface: " + iface); } //#endif JAVA6 /** * 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 java.sql.SQLException if an error occurs while determining whether this is a wrapper * for an object with the given interface. * @since JDK 1.6, HSQLDB 1.8.x */ //#ifdef JAVA6 public boolean isWrapperFor( java.lang.Class<?> iface) throws java.sql.SQLException { return (iface != null && iface.isAssignableFrom(this.getClass())); } //#endif JAVA6 // ------------------------- Internal Implementation --------------------------- private ResultMetaData resultMetaData; /** * Whether to use the underlying column name or label when reporting * getColumnName(). */ private boolean useColumnName; private int columnCount; /** * Constructs a new JDBCResultSetMetaData object from the specified * JDBCResultSet and HsqlProprties objects. * * @param meta the ResultMetaData object from which to construct a new * JDBCResultSetMetaData object * @param props the HsqlProperties object from which to construct a * new JDBCResultSetMetaData object * @throws SQLException if a database access error occurs */ JDBCResultSetMetaData(ResultMetaData meta, boolean isUpdatable, boolean isInsertable, HsqlProperties props) throws SQLException { init(meta, props); } /** * Initializes this JDBCResultSetMetaData object from the specified * Result and HsqlProperties objects. * * @param meta the ResultMetaData object from which to initialize this * JDBCResultSetMetaData object * @param props the HsqlProperties object from which to initialize this * JDBCResultSetMetaData object * @throws SQLException if a database access error occurs */ void init(ResultMetaData meta, HsqlProperties props) throws SQLException { resultMetaData = meta; columnCount = resultMetaData.getColumnCount(); // fredt - props is null for internal connections, so always use the // default behaviour in this case // JDBCDriver.getPropertyInfo says // default is true useColumnName = (props == null) ? true : props.isPropertyTrue( "get_column_name", true); } /** * Performs an internal check for column index validity. <p> * * @param column index of column to check * @throws SQLException when this object's parent ResultSet has * no such column */ private void checkColumn(int column) throws SQLException { if (column < 1 || column > columnCount) { throw Util.sqlException(ErrorCode.JDBC_COLUMN_NOT_FOUND, String.valueOf(column)); } } /** * Returns a string representation of the object. <p> * * The string consists of the name of the class of which the * object is an instance, the at-sign character `<code>@</code>', * the unsigned hexadecimal representation of the hash code of the * object and a comma-delimited list of this object's indexed attributes, * enclosed in square brakets. * * @return a string representation of the object. */ public String toString() { StringBuffer sb = new StringBuffer(); sb.append(super.toString()); if (columnCount == 0) { sb.append("[columnCount=0]"); return sb.toString(); } sb.append('['); for (int i = 0; i < columnCount; i++) { JDBCColumnMetaData meta = getColumnMetaData(i + 1); sb.append('\n'); sb.append(" column_"); sb.append(i + 1); sb.append('='); sb.append(meta); if (i + 1 < columnCount) { sb.append(','); sb.append(' '); } } sb.append('\n'); sb.append(']'); return sb.toString(); } JDBCColumnMetaData getColumnMetaData(int i) { JDBCColumnMetaData meta = new JDBCColumnMetaData(); try { meta.catalogName = getCatalogName(i); meta.columnClassName = getColumnClassName(i); meta.columnDisplaySize = getColumnDisplaySize(i); meta.columnLabel = getColumnLabel(i); meta.columnName = getColumnName(i); meta.columnType = getColumnType(i); meta.isAutoIncrement = isAutoIncrement(i); meta.isCaseSensitive = isCaseSensitive(i); meta.isCurrency = isCurrency(i); meta.isDefinitelyWritable = isDefinitelyWritable(i); meta.isNullable = isNullable(i); meta.isReadOnly = isReadOnly(i); meta.isSearchable = isSearchable(i); meta.isSigned = isSigned(i); meta.isWritable = isWritable(i); meta.precision = getPrecision(i); meta.scale = getScale(i); meta.schemaName = getSchemaName(i); meta.tableName = getTableName(i); } catch (SQLException e) { } return meta; } }