📄 jdbcresultsetmetadata.java
字号:
/* Copyright (c) 2001-2005, 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.Result;import org.hsqldb.ResultConstants;import org.hsqldb.Trace;import org.hsqldb.Types;import org.hsqldb.persist.HsqlProperties;// fredt@users 20040412 - removed DITypeInfo dependencies// boucherb@users - 200404xx - removed unused imports;refinement for better// usability of getColumnDisplaySize;// javadoc updates/** * <!-- 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-foootprint and retention of JDBC resources. <p> * * (fredt@users) <br> * (boucherb@users)<p> * </div> * <!-- end release-specific documentation --> * * @author boucherb@users * @version 1.7.2 * @see jdbcStatement#executeQuery * @see jdbcStatement#getResultSet * @see java.sql.ResultSetMetaData */public class jdbcResultSetMetaData implements ResultSetMetaData { /** * An array of objects, each of which represents the reported attributes * for a single column of this object's parent ResultSet. */ private jdbcColumnMetaData[] columnMetaData; /** The number of columns in this object's parent ResultSet. */ private int columnCount; /** * Whether to use the underlying column name or label when reporting * getColumnName(). */ private boolean useColumnName; /** * If true, then timings for init() are printed * to the console. */ private static final boolean TRACE = false; /** * Constructs a new jdbcResultSetMetaData object from the specified * jdbcResultSet and HsqlProprties objects. * * @param rs the jdbcResultSet 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(jdbcResultSet rs, HsqlProperties props) throws SQLException { init(rs, props); } /** * Constructs a new jdbcResultSetMetaData object from the specified * Result and HsqlProprties objects. * * @param r the Result 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(Result r, HsqlProperties props) throws SQLException { init(r, props); } /** * Initializes this jdbcResultSetMetaData object from the specified * jdbcResultSet and HsqlProperties objects. * * @param rs the jdbcResultSet 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(jdbcResultSet rs, HsqlProperties props) throws SQLException { if (rs == null) { throw Util.sqlException(Trace.GENERAL_ERROR, Trace.JDBC_NO_RESULT_SET_METADATA, null); } init(rs.rResult, props); } /** * Initializes this jdbcResultSetMetaData object from the specified * Result and HsqlProperties objects. * * @param r the Result 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(Result r, HsqlProperties props) throws SQLException { jdbcColumnMetaData cmd; int type; Result.ResultMetaData rmd; if (r == null) { throw Util.sqlException(Trace.GENERAL_ERROR, Trace.JDBC_NO_RESULT_SET, null); } if (r.mode != ResultConstants.DATA) { // implied: columnCount = 0; return; } columnCount = r.getColumnCount(); // fredt - props is null for internal connections, so always use the default behaviour in this case useColumnName = props == null ? true : props.isPropertyTrue( "get_column_name"); columnMetaData = new jdbcColumnMetaData[columnCount]; rmd = r.metaData; for (int i = 0; i < columnCount; i++) { cmd = new jdbcColumnMetaData(); columnMetaData[i] = cmd; // Typically, these null checks are not needed, but as // above, it is not _guaranteed_ that these values // will be non-null. So, it is better to do the work // here than have to perform checks and conversions later. cmd.catalogName = rmd.catalogNames[i] == null ? "" : rmd .catalogNames[i]; cmd.schemaName = rmd.schemaNames[i] == null ? "" : rmd .schemaNames[i]; cmd.tableName = rmd.tableNames[i] == null ? "" : rmd .tableNames[i]; cmd.columnName = rmd.colNames[i] == null ? "" : rmd.colNames[i]; cmd.columnLabel = rmd.colLabels[i] == null ? "" : rmd.colLabels[i]; cmd.columnType = rmd.colTypes[i]; cmd.columnTypeName = Types.getTypeString(cmd.columnType); cmd.isWritable = rmd.isWritable[i]; cmd.isReadOnly = !cmd.isWritable; // default: cmd.isDefinitelyWritable = false; cmd.isAutoIncrement = rmd.isIdentity[i]; cmd.isNullable = rmd.colNullable[i]; type = cmd.columnType; cmd.columnClassName = rmd.classNames[i]; if (cmd.columnClassName == null || cmd.columnClassName.length() == 0) { cmd.columnClassName = Types.getColStClsName(type); } // Some tools, such as PowerBuilder, require that (for char and // varchar types, at any rate) getMaxDisplaySize returns a value // _at least_ as large as the length of the longest value in this // column of the result set, or else an internal error will occur // at retrieve time the instant a longer value is fetched. // // org.hsqldb.Types has been patched to retrieve, by default, either // a large-but-reasonable value or a value defined through system // properties that is expected to be unlikely to cause problems in // the majority of cases. if (Types.acceptsPrecisionCreateParam(type)) { if (rmd.colSizes[i] == 0) { cmd.columnDisplaySize = Types.getMaxDisplaySize(type); } else { cmd.columnDisplaySize = rmd.colSizes[i]; if (Types.acceptsScaleCreateParam(type)) { if (rmd.colScales[i] != 0) { cmd.columnDisplaySize += (1 + rmd.colScales[i]); } } } } else { cmd.columnDisplaySize = Types.getMaxDisplaySize(type); } if (Types.isNumberType(type) && Types.acceptsPrecisionCreateParam(type)) { cmd.precision = rmd.colSizes[i]; if (cmd.precision == 0) { cmd.precision = Types.getPrecision(type); } } else { cmd.precision = Types.getPrecision(type); } // Without a non-zero scale value, some (legacy only?) tools will // simply truncate digits to the right of the decimal point when // retrieving values from the result set. The measure below can // help, but currently only as long as one is connected to an // embedded instance at design time, not via a network connection. if (Types.acceptsScaleCreateParam(type)) { cmd.scale = rmd.colScales[i]; } Boolean iua = Types.isUnsignedAttribute(type); cmd.isSigned = iua != null &&!iua.booleanValue(); Boolean ics = Types.isCaseSensitive(type); cmd.isCaseSensitive = ics != null && ics.booleanValue(); cmd.isSearchable = Types.isSearchable(type); } } /** * <!-- start generic documentation --> * Returns the number of columns in this <code>ResultSet</code> * object. <p> * <!-- end generic documentation --> * @return the number of columns * @exception SQLException if a database access error occurs */ public int getColumnCount() throws SQLException { return columnCount; } /** * <!-- start generic documentation --> * Indicates whether the designated column is automatically numbered, * thus read-only. <p> * <!-- 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, * either always throwing or always returning false, depending * upon client property values.<p> * * Starting with HSQLDB 1.7.2, this feature is better supported. <p> * * <hr> * * However, it must be stated here that, contrary to the generic * documentation above, HSQLDB automatically numbered columns * (IDENTITY columns, in HSQLDB parlance) are not read-only. <p> * * In fact, the generic documentation above 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 * unique value after a successful insert or update operation, even if * no value is supplied or NULL is explicitly specified by the application * or a default value expression. <p> * * Further, without SQL Feature T176, Sequence generator support, the * attributes of the internal source consulted for unique values are not * defined. That is, unlike for a standard SQL SEQUENCE object or a system * with full SQL 9x or 200n support for SQL Feature T174, Identity columns, * an application must not assume and cannot determine in a standard way * that auto-increment values start at any particular point, increment by * any particular value or have any of the other attributes generally * associated with SQL SEQUENCE generators. Further still, without full * support for both feature T174 and T176, if a unique value is supplied * by an application or provided by a declared or implicit default value * expression, then whether that value is used or substituted with one * from the automatic unique value source is implementation-defined * and cannot be known in a standard way. Finally, without full support * for features T174 and T176, it is also implementation-defined and * cannot be know in a standard way whether an exception is thrown or * a unique value is automatically substituted when an application or * default value expression supplies a non-NULL, * non-unique value. <p> * * Up to and including HSQLDB 1.7.2, values supplied by an application or * default value expression are used if they are indeed non-NULL unique * values, while an exception is thrown if either possible value source * for the site attempts to supply a non-NULL, non-unique value. This is * very likely to remain the behaviour of HSQLDB for its foreseable * lifetime and at the very least for the duration of the 1.7.x release * series.<p> * * <hr> * * Regardless of the new and better support for reporting * isAutoIncrement(), it is still possible under certain conditions that * accurate reporting may be impossible. For example, if this object's * parent Connection is closed before the first call to this method or to * any other method of this class that initializes the connection-dependent * ResultSetMetaData values, then it is impossible to report accurately for * result set columns that directly represent table column values.<p> * * Under such special circumstances, the driver rethrows the exception that * occured during the initialization, or a SQLException wrapping it. <p> * * Those wishing to determine the auto-increment status of a table column * in isolation from ResultSetMetaData can do so by inspecting the * corresponding value of the SYSTEM_COLUMNS.IS_IDENTITY BOOLEAN column which * is also currently included (in a fashion proprietary to HSQLDB) as the * last column of the jdbcDatabaseMetaData.getColumns() result.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -