0001: /* Copyright (c) 2001-2005, The HSQL Development Group
0002: * All rights reserved.
0003: *
0004: * Redistribution and use in source and binary forms, with or without
0005: * modification, are permitted provided that the following conditions are met:
0006: *
0007: * Redistributions of source code must retain the above copyright notice, this
0008: * list of conditions and the following disclaimer.
0009: *
0010: * Redistributions in binary form must reproduce the above copyright notice,
0011: * this list of conditions and the following disclaimer in the documentation
0012: * and/or other materials provided with the distribution.
0013: *
0014: * Neither the name of the HSQL Development Group nor the names of its
0015: * contributors may be used to endorse or promote products derived from this
0016: * software without specific prior written permission.
0017: *
0018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021: * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
0022: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0025: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0026: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0027: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0028: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0029: */
0030:
0031: package org.hsqldb.jdbc;
0032:
0033: import java.sql.ResultSetMetaData;
0034: import java.sql.SQLException;
0035:
0036: import org.hsqldb.Result;
0037: import org.hsqldb.ResultConstants;
0038: import org.hsqldb.Trace;
0039: import org.hsqldb.Types;
0040: import org.hsqldb.persist.HsqlProperties;
0041:
0042: // fredt@users 20040412 - removed DITypeInfo dependencies
0043: // boucherb@users - 200404xx - removed unused imports;refinement for better
0044: // usability of getColumnDisplaySize;
0045: // javadoc updates
0046:
0047: /**
0048: * <!-- start generic documentation -->
0049: * An object that can be used to get information about the types
0050: * and properties of the columns in a <code>ResultSet</code> object.
0051: * The following code fragment creates the <code>ResultSet</code>
0052: * object rs, creates the <code>ResultSetMetaData</code> object rsmd,
0053: * and uses rsmd to find out how many columns rs has and whether the
0054: * first column in rs can be used in a <code>WHERE</code> clause.
0055: * <PRE>
0056: *
0057: * ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM TABLE2");
0058: * ResultSetMetaData rsmd = rs.getMetaData();
0059: * int numberOfColumns = rsmd.getColumnCount();
0060: * boolean b = rsmd.isSearchable(1);
0061: *
0062: * </PRE>
0063: * <!-- end generic documentation -->
0064: *
0065: * <!-- start Release-specific documentation -->
0066: * <div class="ReleaseSpecificDocumentation">
0067: * <h3>HSQLDB-Specific Information:</h3> <p>
0068: *
0069: * HSQLDB supports a subset of the <code>ResultSetMetaData</code> interface.<p>
0070: *
0071: * The JDBC specification for <code>ResultSetMetaData</code> is in part very
0072: * vague. This causes potential incompatibility between interpretations of the
0073: * specification as realized in different JDBC driver implementations. As such,
0074: * deciding to what degree reporting ResultSetMetaData is accurate has been
0075: * considered very carefully. Hopefully, the design decisions made in light of
0076: * these considerations have yeilded precisely the subset of full
0077: * ResultSetMetaData support that is most commonly needed and that is most
0078: * important, while also providing, under the most common use-cases, the
0079: * fastest access with the least overhead and the best comprimise between
0080: * speed, accuracy, jar-foootprint and retention of JDBC resources. <p>
0081: *
0082: * (fredt@users) <br>
0083: * (boucherb@users)<p>
0084: * </div>
0085: * <!-- end release-specific documentation -->
0086: *
0087: * @author boucherb@users
0088: * @version 1.7.2
0089: * @see jdbcStatement#executeQuery
0090: * @see jdbcStatement#getResultSet
0091: * @see java.sql.ResultSetMetaData
0092: */
0093: public class jdbcResultSetMetaData implements ResultSetMetaData {
0094:
0095: /**
0096: * An array of objects, each of which represents the reported attributes
0097: * for a single column of this object's parent ResultSet.
0098: */
0099: private jdbcColumnMetaData[] columnMetaData;
0100:
0101: /** The number of columns in this object's parent ResultSet. */
0102: private int columnCount;
0103:
0104: /**
0105: * Whether to use the underlying column name or label when reporting
0106: * getColumnName().
0107: */
0108: private boolean useColumnName;
0109:
0110: /**
0111: * If true, then timings for init() are printed
0112: * to the console.
0113: */
0114: private static final boolean TRACE = false;
0115:
0116: /**
0117: * Constructs a new jdbcResultSetMetaData object from the specified
0118: * jdbcResultSet and HsqlProprties objects.
0119: *
0120: * @param rs the jdbcResultSet object from which to construct a new
0121: * jdbcResultSetMetaData object
0122: * @param props the HsqlProperties object from which to construct a
0123: * new jdbcResultSetMetaData object
0124: * @throws SQLException if a database access error occurs
0125: */
0126: jdbcResultSetMetaData(jdbcResultSet rs, HsqlProperties props)
0127: throws SQLException {
0128: init(rs, props);
0129: }
0130:
0131: /**
0132: * Constructs a new jdbcResultSetMetaData object from the specified
0133: * Result and HsqlProprties objects.
0134: *
0135: * @param r the Result object from which to construct a new
0136: * jdbcResultSetMetaData object
0137: * @param props the HsqlProperties object from which to construct a
0138: * new jdbcResultSetMetaData object
0139: * @throws SQLException if a database access error occurs
0140: */
0141: jdbcResultSetMetaData(Result r, HsqlProperties props)
0142: throws SQLException {
0143: init(r, props);
0144: }
0145:
0146: /**
0147: * Initializes this jdbcResultSetMetaData object from the specified
0148: * jdbcResultSet and HsqlProperties objects.
0149: *
0150: * @param rs the jdbcResultSet object from which to initialize this
0151: * jdbcResultSetMetaData object
0152: * @param props the HsqlProperties object from which to initialize this
0153: * jdbcResultSetMetaData object
0154: * @throws SQLException if a database access error occurs
0155: */
0156: void init(jdbcResultSet rs, HsqlProperties props)
0157: throws SQLException {
0158:
0159: if (rs == null) {
0160: throw Util.sqlException(Trace.GENERAL_ERROR,
0161: Trace.JDBC_NO_RESULT_SET_METADATA, null);
0162: }
0163:
0164: init(rs.rResult, props);
0165: }
0166:
0167: /**
0168: * Initializes this jdbcResultSetMetaData object from the specified
0169: * Result and HsqlProperties objects.
0170: *
0171: * @param r the Result object from which to initialize this
0172: * jdbcResultSetMetaData object
0173: * @param props the HsqlProperties object from which to initialize this
0174: * jdbcResultSetMetaData object
0175: * @throws SQLException if a database access error occurs
0176: */
0177: void init(Result r, HsqlProperties props) throws SQLException {
0178:
0179: jdbcColumnMetaData cmd;
0180: int type;
0181: Result.ResultMetaData rmd;
0182:
0183: if (r == null) {
0184: throw Util.sqlException(Trace.GENERAL_ERROR,
0185: Trace.JDBC_NO_RESULT_SET, null);
0186: }
0187:
0188: if (!r.isData()) {
0189:
0190: // implied: columnCount = 0;
0191: return;
0192: }
0193:
0194: columnCount = r.getColumnCount();
0195:
0196: // fredt - props is null for internal connections, so always use the default behaviour in this case
0197: useColumnName = props == null ? true : props
0198: .isPropertyTrue("get_column_name");
0199: columnMetaData = new jdbcColumnMetaData[columnCount];
0200: rmd = r.metaData;
0201:
0202: for (int i = 0; i < columnCount; i++) {
0203: cmd = new jdbcColumnMetaData();
0204: columnMetaData[i] = cmd;
0205:
0206: // Typically, these null checks are not needed, but as
0207: // above, it is not _guaranteed_ that these values
0208: // will be non-null. So, it is better to do the work
0209: // here than have to perform checks and conversions later.
0210: cmd.catalogName = rmd.catalogNames[i] == null ? ""
0211: : rmd.catalogNames[i];
0212: cmd.schemaName = rmd.schemaNames[i] == null ? ""
0213: : rmd.schemaNames[i];
0214: cmd.tableName = rmd.tableNames[i] == null ? ""
0215: : rmd.tableNames[i];
0216: cmd.columnName = rmd.colNames[i] == null ? ""
0217: : rmd.colNames[i];
0218: cmd.columnLabel = rmd.colLabels[i] == null ? ""
0219: : rmd.colLabels[i];
0220: cmd.columnType = rmd.colTypes[i];
0221: cmd.columnTypeName = Types.getTypeString(cmd.columnType);
0222: cmd.isWritable = rmd.isWritable[i];
0223: cmd.isReadOnly = !cmd.isWritable;
0224:
0225: // default: cmd.isDefinitelyWritable = false;
0226: cmd.isAutoIncrement = rmd.isIdentity[i];
0227: cmd.isNullable = rmd.colNullable[i];
0228: type = cmd.columnType;
0229: cmd.columnClassName = rmd.classNames[i];
0230:
0231: if (cmd.columnClassName == null
0232: || cmd.columnClassName.length() == 0) {
0233: cmd.columnClassName = Types.getColStClsName(type);
0234: }
0235:
0236: // Some tools, such as PowerBuilder, require that (for char and
0237: // varchar types, at any rate) getMaxDisplaySize returns a value
0238: // _at least_ as large as the length of the longest value in this
0239: // column of the result set, or else an internal error will occur
0240: // at retrieve time the instant a longer value is fetched.
0241: //
0242: // org.hsqldb.Types has been patched to retrieve, by default, either
0243: // a large-but-reasonable value or a value defined through system
0244: // properties that is expected to be unlikely to cause problems in
0245: // the majority of cases.
0246: if (Types.acceptsPrecisionCreateParam(type)) {
0247: if (rmd.colSizes[i] == 0) {
0248: cmd.columnDisplaySize = Types
0249: .getMaxDisplaySize(type);
0250: } else {
0251: cmd.columnDisplaySize = rmd.colSizes[i];
0252:
0253: if (Types.acceptsScaleCreateParam(type)) {
0254: if (rmd.colScales[i] != 0) {
0255: cmd.columnDisplaySize += (1 + rmd.colScales[i]);
0256: }
0257: }
0258: }
0259: } else {
0260: cmd.columnDisplaySize = Types.getMaxDisplaySize(type);
0261: }
0262:
0263: if (Types.isNumberType(type)
0264: && Types.acceptsPrecisionCreateParam(type)) {
0265: cmd.precision = rmd.colSizes[i];
0266:
0267: if (cmd.precision == 0) {
0268: cmd.precision = Types.getPrecision(type);
0269: }
0270: } else {
0271: cmd.precision = Types.getPrecision(type);
0272: }
0273:
0274: // Without a non-zero scale value, some (legacy only?) tools will
0275: // simply truncate digits to the right of the decimal point when
0276: // retrieving values from the result set. The measure below can
0277: // help, but currently only as long as one is connected to an
0278: // embedded instance at design time, not via a network connection.
0279: if (Types.acceptsScaleCreateParam(type)) {
0280: cmd.scale = rmd.colScales[i];
0281: }
0282:
0283: Boolean iua = Types.isUnsignedAttribute(type);
0284:
0285: cmd.isSigned = iua != null && !iua.booleanValue();
0286:
0287: Boolean ics = Types.isCaseSensitive(type);
0288:
0289: cmd.isCaseSensitive = ics != null && ics.booleanValue();
0290: cmd.isSearchable = Types.isSearchable(type);
0291: }
0292: }
0293:
0294: /**
0295: * <!-- start generic documentation -->
0296: * Returns the number of columns in this <code>ResultSet</code>
0297: * object. <p>
0298: * <!-- end generic documentation -->
0299: * @return the number of columns
0300: * @exception SQLException if a database access error occurs
0301: */
0302: public int getColumnCount() throws SQLException {
0303: return columnCount;
0304: }
0305:
0306: /**
0307: * <!-- start generic documentation -->
0308: * Indicates whether the designated column is automatically numbered,
0309: * thus read-only. <p>
0310: * <!-- end generic documentation -->
0311: *
0312: * <!-- start Release-specific documentation -->
0313: * <div class="ReleaseSpecificDocumentation">
0314: * <h3>HSQLDB-Specific Information:</h3> <p>
0315: *
0316: * HSQLDB 1.7.1 did not report this value accurately,
0317: * either always throwing or always returning false, depending
0318: * upon client property values.<p>
0319: *
0320: * Starting with HSQLDB 1.7.2, this feature is better supported. <p>
0321: *
0322: * <hr>
0323: *
0324: * However, it must be stated here that, contrary to the generic
0325: * documentation above, HSQLDB automatically numbered columns
0326: * (IDENTITY columns, in HSQLDB parlance) are not read-only. <p>
0327: *
0328: * In fact, the generic documentation above seems to contradict the general
0329: * definition of what, at minimum, an auto-increment column is: <p>
0330: *
0331: * Simply, an auto-increment column is one that guarantees it has a
0332: * unique value after a successful insert or update operation, even if
0333: * no value is supplied or NULL is explicitly specified by the application
0334: * or a default value expression. <p>
0335: *
0336: * Further, without SQL Feature T176, Sequence generator support, the
0337: * attributes of the internal source consulted for unique values are not
0338: * defined. That is, unlike for a standard SQL SEQUENCE object or a system
0339: * with full SQL 9x or 200n support for SQL Feature T174, Identity columns,
0340: * an application must not assume and cannot determine in a standard way
0341: * that auto-increment values start at any particular point, increment by
0342: * any particular value or have any of the other attributes generally
0343: * associated with SQL SEQUENCE generators. Further still, without full
0344: * support for both feature T174 and T176, if a unique value is supplied
0345: * by an application or provided by a declared or implicit default value
0346: * expression, then whether that value is used or substituted with one
0347: * from the automatic unique value source is implementation-defined
0348: * and cannot be known in a standard way. Finally, without full support
0349: * for features T174 and T176, it is also implementation-defined and
0350: * cannot be know in a standard way whether an exception is thrown or
0351: * a unique value is automatically substituted when an application or
0352: * default value expression supplies a non-NULL,
0353: * non-unique value. <p>
0354: *
0355: * Up to and including HSQLDB 1.7.2, values supplied by an application or
0356: * default value expression are used if they are indeed non-NULL unique
0357: * values, while an exception is thrown if either possible value source
0358: * for the site attempts to supply a non-NULL, non-unique value. This is
0359: * very likely to remain the behaviour of HSQLDB for its foreseable
0360: * lifetime and at the very least for the duration of the 1.7.x release
0361: * series.<p>
0362: *
0363: * <hr>
0364: *
0365: * Regardless of the new and better support for reporting
0366: * isAutoIncrement(), it is still possible under certain conditions that
0367: * accurate reporting may be impossible. For example, if this object's
0368: * parent Connection is closed before the first call to this method or to
0369: * any other method of this class that initializes the connection-dependent
0370: * ResultSetMetaData values, then it is impossible to report accurately for
0371: * result set columns that directly represent table column values.<p>
0372: *
0373: * Under such special circumstances, the driver rethrows the exception that
0374: * occured during the initialization, or a SQLException wrapping it. <p>
0375: *
0376: * Those wishing to determine the auto-increment status of a table column
0377: * in isolation from ResultSetMetaData can do so by inspecting the
0378: * corresponding value of the SYSTEM_COLUMNS.IS_IDENTITY BOOLEAN column which
0379: * is also currently included (in a fashion proprietary to HSQLDB) as the
0380: * last column of the jdbcDatabaseMetaData.getColumns() result.
0381: *
0382: * </div>
0383: * <!-- end release-specific documentation -->
0384: *
0385: * @param column the first column is 1, the second is 2, ...
0386: * @return <code>true</code> if so; <code>false</code> otherwise
0387: * @exception SQLException if a database access error occurs
0388: */
0389: public boolean isAutoIncrement(int column) throws SQLException {
0390:
0391: checkColumn(column);
0392:
0393: return columnMetaData[--column].isAutoIncrement;
0394: }
0395:
0396: /**
0397: * <!-- start generic documentation -->
0398: * Indicates whether a column's case matters. <p>
0399: * <!-- end generic documentation -->
0400: *
0401: * <!-- start Release-specific documentation -->
0402: * <div class="ReleaseSpecificDocumentation">
0403: * <h3>HSQLDB-Specific Information:</h3> <p>
0404: *
0405: * HSQLDB 1.7.1 did not report this value accurately. <p>
0406: *
0407: * Starting with 1.7.2, this feature is better supported. <p>
0408: *
0409: * This method returns true for any column whose data type is a character
0410: * type, with the exception of VARCHAR_IGNORECASE for which it returns
0411: * false. It also returns false for any column whose data type is a
0412: * not a character data type. <p>
0413: *
0414: * </div>
0415: * <!-- end release-specific documentation -->
0416: *
0417: * @param column the first column is 1, the second is 2, ...
0418: * @return <code>true</code> if so; <code>false</code> otherwise
0419: * @exception SQLException if a database access error occurs
0420: */
0421: public boolean isCaseSensitive(int column) throws SQLException {
0422:
0423: checkColumn(column);
0424:
0425: return columnMetaData[--column].isCaseSensitive;
0426: }
0427:
0428: /**
0429: * <!-- start generic documentation -->
0430: * Indicates whether the designated column can be used in a where
0431: * clause. <p>
0432: * <!-- end generic documentation -->
0433: *
0434: * <!-- start Release-specific documentation -->
0435: * <div class="ReleaseSpecificDocumentation">
0436: * <h3>HSQLDB-Specific Information:</h3> <p>
0437: *
0438: * HSQLDB 1.7.1 did not report this value accurately. <p>
0439: *
0440: * Starting with 1.7.2, this feature is better supported. <p>
0441: *
0442: * If the data type of the column is definitely known to be searchable
0443: * in any way under HSQLDB, then true is returned, else false. That is,
0444: * if the type is reported in DatabaseMetaData.getTypeInfo() as having
0445: * DatabaseMetaData.typePredNone or is not reported, then false is
0446: * returned, else true.
0447: *
0448: * </div>
0449: * <!-- end release-specific documentation -->
0450: *
0451: * @param column the first column is 1, the second is 2, ...
0452: * @return <code>true</code> if so; <code>false</code> otherwise
0453: * @exception SQLException if a database access error occurs
0454: */
0455: public boolean isSearchable(int column) throws SQLException {
0456:
0457: checkColumn(column);
0458:
0459: return columnMetaData[--column].isSearchable;
0460: }
0461:
0462: /**
0463: * <!-- start generic documentation -->
0464: * Indicates whether the designated column is a cash value. <p>
0465: * <!-- end generic documentation -->
0466: *
0467: * <!-- start Release-specific documentation -->
0468: * <div class="ReleaseSpecificDocumentation">
0469: * <h3>HSQLDB-Specific Information:</h3> <p>
0470: *
0471: * Up to and including HSQLDB 1.7.2, this method always returns
0472: * false. <p>
0473: *
0474: * This is because true fixed (precision,scale) data types are not yet
0475: * supported. That is, DECIMAL and NUMERIC types are implemented
0476: * as a thin wrap of java.math.BigDecimal, which cannot, without
0477: * additional, as yet unimplemented constraint enforcement code, be
0478: * said to be a fixed (precision,scale) types. <p>
0479: *
0480: * </div>
0481: * <!-- end release-specific documentation -->
0482: *
0483: * @param column the first column is 1, the second is 2, ...
0484: * @return <code>true</code> if so; <code>false</code> otherwise
0485: * @exception SQLException if a database access error occurs
0486: */
0487: public boolean isCurrency(int column) throws SQLException {
0488:
0489: checkColumn(column);
0490:
0491: return columnMetaData[--column].isCurrency;
0492: }
0493:
0494: /**
0495: * <!-- start generic documentation -->
0496: * Indicates the nullability of values in the designated column. <p>
0497: * <!-- end generic documentation -->
0498: *
0499: * <!-- start Release-specific documentation -->
0500: * <div class="ReleaseSpecificDocumentation">
0501: * <h3>HSQLDB-Specific Information:</h3> <p>
0502: *
0503: * Up to 1.7.1, HSQLDB did not report this value accurately. <p>
0504: *
0505: * Starting with 1.7.2, this feature is better supported. <p>
0506: *
0507: * columnNullableUnknown is always returned for result set columns that
0508: * do not directly represent table column values (i.e. are calculated),
0509: * while the corresponding value in SYSTEM_COLUMNS.NULLABLE is returned
0510: * for result set columns that do directly represent table column values. <p>
0511: *
0512: * Those wishing to determine the nullable status of a table column in
0513: * isolation from ResultSetMetaData and in a DBMS-independent fashion
0514: * can do so by calling DatabaseMetaData.getColumns() with the appropriate
0515: * filter values and inspecting the result at the position described in
0516: * the API documentation. <p>
0517: *
0518: * </div>
0519: * <!-- end release-specific documentation -->
0520: *
0521: * @param column the first column is 1, the second is 2, ...
0522: * @return the nullability status of the given column; one of
0523: * <code>columnNoNulls</code>,
0524: * <code>columnNullable</code> or <code>columnNullableUnknown</code>
0525: * @exception SQLException if a database access error occurs
0526: */
0527: public int isNullable(int column) throws SQLException {
0528:
0529: checkColumn(column);
0530:
0531: return columnMetaData[--column].isNullable;
0532: }
0533:
0534: /**
0535: * <!-- start generic documentation -->
0536: * Indicates whether values in the designated column are signed
0537: * numbers. <p>
0538: * <!-- end generic documentation -->
0539: *
0540: * <!-- start Release-specific documentation -->
0541: * <div class="ReleaseSpecificDocumentation">
0542: * <h3>HSQLDB-Specific Information:</h3> <p>
0543: *
0544: * HSQLDB 1.7.1 introduced support for this feature and 1.7.2
0545: * reports identical values (although using a slightly different
0546: * implementation).<p>
0547: *
0548: * </div>
0549: * <!-- end release-specific documentation -->
0550: *
0551: * @param column the first column is 1, the second is 2, ...
0552: * @return <code>true</code> if so; <code>false</code> otherwise
0553: * @exception SQLException if a database access error occurs
0554: */
0555: public boolean isSigned(int column) throws SQLException {
0556:
0557: checkColumn(column);
0558:
0559: return columnMetaData[--column].isSigned;
0560: }
0561:
0562: /**
0563: * <!-- start generic documentation -->
0564: * Indicates the designated column's normal maximum width in
0565: * characters. <p>
0566: * <!-- end generic documentation -->
0567: *
0568: * <!-- start Release-specific documentation -->
0569: * <div class="ReleaseSpecificDocumentation">
0570: * <h3>HSQLDB-Specific Information:</h3> <p>
0571: *
0572: * Up to and including HSQLDB 1.7.1, this method always returned
0573: * 0, which was intended to convey unknown display size.
0574: * Unfortunately, this value is not universally handled by all
0575: * clients and in the worst case can cause some applications to
0576: * crash. <p>
0577: *
0578: * Starting with 1.7.2, this feature is better supported. <p>
0579: *
0580: * The current calculation follows these rules: <p>
0581: *
0582: * <ol>
0583: * <li>Long character types and datetime types:<p>
0584: *
0585: * The maximum length/precision, repectively.<p>
0586: *
0587: * <li>CHAR and VARCHAR types: <p>
0588: *
0589: * <ul>
0590: * <li> If the result set column is a direct pass through of a table
0591: * column value, column size was declared and the connection is
0592: * to an embedded database instance, then the declared value is
0593: * returned.<p>
0594: *
0595: * <li> Otherwise, the value of the system property
0596: * hsqldb.max_xxxchar_display_size or the magic value
0597: * 32766 (0x7FFE) (tested usable/accepted by most tools and
0598: * compatible with assumptions made by java.io read/write
0599: * UTF) when the system property is not defined or is not
0600: * accessible, due to security constraints. <p>
0601: *
0602: * </ul>
0603: *
0604: * It must be noted that the latter value in no way affects the
0605: * ability of the HSQLDB JDBC driver to retrieve longer values
0606: * and serves only as the current best effort at providing a
0607: * value that maximizes usability across a wide range of tools,
0608: * given that the HSQLDB database engine does not require the
0609: * length to be declared and does not necessarily enforce it,
0610: * even if declared. <p>
0611: *
0612: * <li>Number types: <p>
0613: *
0614: * The max precision, plus the length of the negation character (1),
0615: * plus (if applicable) the maximum number of characters that may
0616: * occupy the exponent character sequence. Note that some legacy tools
0617: * do not correctly handle BIGINT values of greater than 18 digits. <p>
0618: *
0619: * <li>BOOLEAN (BIT) type: <p>
0620: *
0621: * The length of the character sequence "false" (5), the longer of the
0622: * two boolean value String representations. <p>
0623: *
0624: * <li>Remaining types: <p>
0625: *
0626: * The maximum length/precision, respectively, as reported by
0627: * DatabaseMetaData.getTypeInfo(), when applicable. If the maximum
0628: * display size is unknown, unknowable or inapplicable, then zero is
0629: * returned. <p>
0630: *
0631: * </ol>
0632: *
0633: * </div>
0634: * <!-- end release-specific documentation -->
0635: *
0636: * @param column the first column is 1, the second is 2, ...
0637: * @return the normal maximum number of characters allowed as the width
0638: * of the designated column
0639: * @exception SQLException if a database access error occurs
0640: */
0641: public int getColumnDisplaySize(int column) throws SQLException {
0642:
0643: checkColumn(column);
0644:
0645: return columnMetaData[--column].columnDisplaySize;
0646: }
0647:
0648: /**
0649: * <!-- start generic documentation -->
0650: * Gets the designated column's suggested title for use in printouts and
0651: * displays. <p>
0652: * <!-- end generic documentation -->
0653: *
0654: * <!-- start Release-specific documentation -->
0655: * <div class="ReleaseSpecificDocumentation">
0656: * <h3>HSQLDB-Specific Information:</h3> <p>
0657: *
0658: * In HSQLDB a <code>ResultSet</code> column label is determined in the
0659: * following order of precedence:<p>
0660: *
0661: * <OL>
0662: * <LI>The label (alias) specified in the generating query.</LI>
0663: * <LI>The name of the underlying column, if no label is specified.<br>
0664: * This also applies to aggregate functions.</LI>
0665: * <LI>An empty <code>String</code>.</LI>
0666: * </OL> <p>
0667: *
0668: * </div>
0669: * <!-- end release-specific documentation -->
0670: *
0671: * @param column the first column is 1, the second is 2, ...
0672: * @return the suggested column title
0673: * @exception SQLException if a database access error occurs
0674: */
0675: public String getColumnLabel(int column) throws SQLException {
0676:
0677: checkColumn(column);
0678:
0679: return columnMetaData[--column].columnLabel;
0680: }
0681:
0682: /**
0683: * <!-- start generic documentation -->
0684: * Get the designated column's name. <p>
0685: * <!-- end generic documentation -->
0686: *
0687: * <!-- start Release-specific documentation -->
0688: * <div class="ReleaseSpecificDocumentation">
0689: * <h3>HSQLDB-Specific Information:</h3> <p>
0690: *
0691: * In HSQLDB a ResultSet column name is determined in the following
0692: * order of prcedence:<p>
0693: *
0694: * <OL>
0695: * <LI>The name of the underlying columnm, if the ResultSet column
0696: * represents a column in a table.</LI>
0697: * <LI>The label or alias specified in the generating query.</LI>
0698: * <LI>An empty <code>String</code>.</LI>
0699: * </OL> <p>
0700: *
0701: * If the <code>jdbc.get_column_name</code> property of the database
0702: * has been set to false, this method returns the same value as
0703: * {@link #getColumnLabel(int)}.<p>
0704: *
0705: * </div>
0706: * <!-- end release-specific documentation -->
0707: *
0708: * @param column the first column is 1, the second is 2, ...
0709: * @return column name
0710: * @exception SQLException if a database access error occurs
0711: */
0712: public String getColumnName(int column) throws SQLException {
0713:
0714: checkColumn(column);
0715:
0716: column--;
0717:
0718: return useColumnName ? columnMetaData[column].columnName
0719: : columnMetaData[column].columnLabel;
0720: }
0721:
0722: /**
0723: * <!-- start generic documentation -->
0724: * Get the designated column's table's schema. <p>
0725: * <!-- end generic documentation -->
0726: *
0727: * <!-- start Release-specific documentation -->
0728: * <div class="ReleaseSpecificDocumentation">
0729: * <h3>HSQLDB-Specific Information:</h3> <p>
0730: *
0731: * Up to 1.7.1, HSQLDB did not support the notion of schemas at all,
0732: * including schema names in result set metadata; this method always
0733: * returned "". <p>
0734: *
0735: * Staring with 1.7.2, schema name reporting is supported only as an
0736: * optional, experimental feature that is disabled by default.
0737: * Enabling this feature requires setting the database property
0738: * "hsqldb.schemas=true". <p>
0739: *
0740: * Specifically, when this feature is enabled under 1.7.2, only very
0741: * limited support is provided by the engine for executing SQL containing
0742: * schema-qualified database object identifiers. That is, when this
0743: * feature is enabled under 1.7.2, it is not yet possible in most cases
0744: * to use what would otherwise be the correct, canonical SQL calculated
0745: * from ResultSetMetaData. <p>
0746: *
0747: * Regardless, reporting is done only in system table content and is
0748: * not yet carried over to ResultSetMetaData. <p>
0749: *
0750: * For greater detail, see discussion at:
0751: * {@link jdbcDatabaseMetaData}. <p>
0752: *
0753: * </div>
0754: * <!-- end release-specific documentation -->
0755: *
0756: * @param column the first column is 1, the second is 2, ...
0757: * @return schema name or "" if not applicable
0758: * @exception SQLException if a database access error occurs
0759: */
0760: public String getSchemaName(int column) throws SQLException {
0761:
0762: checkColumn(column);
0763:
0764: return columnMetaData[--column].schemaName;
0765: }
0766:
0767: /**
0768: * <!-- start generic documentation -->
0769: * Get the designated column's number of decimal digits. <p>
0770: * <!-- end generic documentation -->
0771: *
0772: * <!-- start Release-specific documentation -->
0773: * <div class="ReleaseSpecificDocumentation">
0774: * <h3>HSQLDB-Specific Information:</h3> <p>
0775: *
0776: * Starting with 1.8.0, HSQLDB reports the the declared
0777: * length or precision specifiers for table columns (if they are defined,
0778: * which up to 1.7.2 is not a requirement in DDL), as these values may or
0779: * may not be enforced, depending on the value of the database
0780: * property: <p>
0781: *
0782: * <pre>
0783: * sql.enforce_strict_size
0784: * </pre>
0785: *
0786: * Because the property may change from one instantiation of a Database
0787: * to the next and because, when set true, is not applied to existing
0788: * values in table columns (only to new values introduced by following
0789: * inserts and updates), the length and/or precision specifiers for table
0790: * columns still do not neccessarily accurately reflect true constraints
0791: * upon the contents of the columns. This situation may or may not change
0792: * in a future release. <p>
0793: *
0794: * </div>
0795: * <!-- end release-specific documentation -->
0796: *
0797: * @param column the first column is 1, the second is 2, ...
0798: * @return precision
0799: * @exception SQLException if a database access error occurs
0800: */
0801: public int getPrecision(int column) throws SQLException {
0802:
0803: checkColumn(column);
0804:
0805: return columnMetaData[--column].precision;
0806: }
0807:
0808: /**
0809: * <!-- start generic documentation -->
0810: * Gets the designated column's number of digits to right of the
0811: * decimal point. <p>
0812: * <!-- end generic documentation -->
0813: *
0814: * <!-- start Release-specific documentation -->
0815: * <div class="ReleaseSpecificDocumentation">
0816: * <h3>HSQLDB-Specific Information:</h3> <p>
0817: *
0818: * Starting with 1.8.0, HSQLDB reports the declared
0819: * scale for table columns depending on the value of the database
0820: * property: <p>
0821: *
0822: * <pre>
0823: * sql.enforce_strict_size
0824: * </pre>
0825: *
0826: * </div>
0827: * <!-- end release-specific documentation -->
0828: *
0829: * @param column the first column is 1, the second is 2, ...
0830: * @return scale
0831: * @exception SQLException if a database access error occurs
0832: */
0833: public int getScale(int column) throws SQLException {
0834:
0835: checkColumn(column);
0836:
0837: return columnMetaData[--column].scale;
0838: }
0839:
0840: /**
0841: * <!-- start generic documentation -->
0842: * Gets the designated column's table name. <p>
0843: * <!-- end generic documentation -->
0844: * @param column the first column is 1, the second is 2, ...
0845: * @return table name or "" if not applicable
0846: * @exception SQLException if a database access error occurs
0847: */
0848: public String getTableName(int column) throws SQLException {
0849:
0850: checkColumn(column);
0851:
0852: return columnMetaData[--column].tableName;
0853: }
0854:
0855: /**
0856: * <!-- start generic documentation -->
0857: * Gets the designated column's table's catalog name. <p>
0858: * <!-- end generic documentation -->
0859: *
0860: * <!-- start Release-specific documentation -->
0861: * <div class="ReleaseSpecificDocumentation">
0862: * <h3>HSQLDB-Specific Information:</h3> <p>
0863: *
0864: * Up to and including 1.7.1, HSQLDB did not support the notion of
0865: * catalog and this method always returned "". <p>
0866: *
0867: * Starting with 1.7.2, HSQLDB supports catalog reporting only as an
0868: * optional, experimental feature that is disabled by default. Enabling
0869: * this feature requires setting the database property
0870: * "hsqldb.catalogs=true". When enabled, the catalog name for table columns
0871: * is reported as the name by which the hosting Database knows itself. <p>
0872: *
0873: * HSQLDB does not yet support any use of catalog qualification in
0874: * DLL or DML. This fact is accurately indicated in the corresponding
0875: * DatabaseMetaData.supportsXXX() method return values. <p>
0876: *
0877: * Regardless, reporting is done only in system table content and is
0878: * not yet carried over to ResultSetMetaData. <p>
0879: *
0880: * For greater detail, see discussion at:
0881: * {@link jdbcDatabaseMetaData}. <p>
0882: *
0883: * </div>
0884: * <!-- end release-specific documentation -->
0885: *
0886: * @param column the first column is 1, the second is 2, ...
0887: * @return the name of the catalog for the table in which the given column
0888: * appears or "" if not applicable
0889: * @exception SQLException if a database access error occurs
0890: */
0891: public String getCatalogName(int column) throws SQLException {
0892:
0893: checkColumn(column);
0894:
0895: return columnMetaData[--column].catalogName;
0896: }
0897:
0898: /**
0899: * <!-- start generic documentation -->
0900: * Retrieves the designated column's SQL type. <p>
0901: * <!-- end generic documentation -->
0902: *
0903: * <!-- start Release-specific documentation -->
0904: * <div class="ReleaseSpecificDocumentation">
0905: * <h3>HSQLDB-Specific Information:</h3> <p>
0906: *
0907: * This reports the SQL type of the column. HSQLDB can return Objects in
0908: * any Java integral type wider than <code>Integer</code> for an SQL
0909: * integral type.<p>
0910: *
0911: * </div>
0912: * <!-- end release-specific documentation -->
0913: *
0914: *
0915: * @param column the first column is 1, the second is 2, ...
0916: * @return SQL type from java.sql.Types
0917: * @exception SQLException if a database access error occurs
0918: * @see java.sql.Types
0919: */
0920: public int getColumnType(int column) throws SQLException {
0921:
0922: checkColumn(column);
0923:
0924: int type = columnMetaData[--column].columnType;
0925:
0926: return type == Types.VARCHAR_IGNORECASE ? Types.VARCHAR : type;
0927: }
0928:
0929: /**
0930: * <!-- start generic documentation -->
0931: * Retrieves the designated column's database-specific type name. <p>
0932: * <!-- end generic documentation -->
0933: *
0934: * @param column the first column is 1, the second is 2, ...
0935: * @return type name used by the database. If the column type is
0936: * a user-defined type, then a fully-qualified type name is returned.
0937: * @exception SQLException if a database access error occurs
0938: */
0939: public String getColumnTypeName(int column) throws SQLException {
0940:
0941: checkColumn(column);
0942:
0943: return columnMetaData[--column].columnTypeName;
0944: }
0945:
0946: /**
0947: * <!-- start generic documentation -->
0948: * Indicates whether the designated column is definitely not writable.<p>
0949: * <!-- end generic documentation -->
0950: *
0951: * <!-- start Release-specific documentation -->
0952: * <div class="ReleaseSpecificDocumentation">
0953: * <h3>HSQLDB-Specific Information:</h3> <p>
0954: *
0955: * Up to and including 1.7.1, HSQLDB did not report this value accurately.
0956: * <p>
0957: *
0958: * Starting with HSQLDB 1.7.2, this feature is better supported. <p>
0959: *
0960: * For result set columns that do not directly
0961: * represent table column values (i.e. are calculated), true is reported.
0962: * Otherwise, the read only status of the table and the database are used
0963: * in the calculation, but not the read-only status of the session. <p>
0964: *
0965: * </div>
0966: * <!-- end release-specific documentation -->
0967: *
0968: * @param column the first column is 1, the second is 2, ...
0969: * @return <code>true</code> if so; <code>false</code> otherwise
0970: * @exception SQLException if a database access error occurs
0971: */
0972: public boolean isReadOnly(int column) throws SQLException {
0973:
0974: checkColumn(column);
0975:
0976: return columnMetaData[--column].isReadOnly;
0977: }
0978:
0979: /**
0980: * <!-- start generic documentation -->
0981: * Indicates whether it is possible for a write on the designated
0982: * column to succeed. <p>
0983: * <!-- end generic documentation -->
0984: *
0985: * <!-- start Release-specific documentation -->
0986: * <div class="ReleaseSpecificDocumentation">
0987: * <h3>HSQLDB-Specific Information:</h3> <p>
0988: *
0989: * Up to and including 1.7.1, HSQLDB did not report this value accurately.
0990: * <p>
0991: *
0992: * Starting with HSQLDB 1.7.2, this feature is better supported. <p>
0993: *
0994: * In essense, the negation of isReadOnly() is reported. <p>
0995: *
0996: * </div>
0997: * <!-- end release-specific documentation -->
0998: *
0999: * @param column the first column is 1, the second is 2, ...
1000: * @return <code>true</code> if so; <code>false</code> otherwise
1001: * @exception SQLException if a database access error occurs
1002: */
1003: public boolean isWritable(int column) throws SQLException {
1004:
1005: checkColumn(column);
1006:
1007: return columnMetaData[--column].isWritable;
1008: }
1009:
1010: /**
1011: * <!-- start generic documentation -->
1012: * Indicates whether a write on the designated column will definitely
1013: * succeed. <p>
1014: * <!-- end generic documentation -->
1015: *
1016: * <!-- start Release-specific documentation -->
1017: * <div class="ReleaseSpecificDocumentation">
1018: * <h3>HSQLDB-Specific Information:</h3> <p>
1019: *
1020: * HSQLDB 1.7.1 did not report this value accurately. <p>
1021: *
1022: * Starting with HSQLDB 1.7.2, this method always returns false. The
1023: * reason for this is that it is generally either very complex or
1024: * simply impossible to calculate deterministically true for table columns
1025: * under all concievable conditions. The value is of dubious usefulness, except
1026: * perhaps if there were support for updateable result sets using
1027: * "SELECT ... FOR UPDATE" style locking. However, this is not anticipated to
1028: * occur any time in the 1.7.x release series. <p>
1029: *
1030: * </div>
1031: * <!-- end release-specific documentation -->
1032: *
1033: * @param column the first column is 1, the second is 2, ...
1034: * @return <code>true</code> if so; <code>false</code> otherwise
1035: * @exception SQLException if a database access error occurs
1036: */
1037: public boolean isDefinitelyWritable(int column) throws SQLException {
1038:
1039: checkColumn(column);
1040:
1041: // NOTE:
1042: // boucherb@users - 20020329
1043: // currently, we can't tell _for sure_ that this is true without a
1044: // great deal more work (and even then, not necessarily deterministically),
1045: // plus it is of dubious usefulness to know this is true _for sure_ anyway.
1046: // It's not like one can do an insert or update without a try-catch block
1047: // using JDBC, even if one knows that a column is definitely writable. And
1048: // the catch will always let us know if there is a failure and why. Also,
1049: // it is typically completely useless to know that, although it is _possible_
1050: // that a write may succeed (as indicated by a true value of isWritable()),
1051: // it also might fail (as indicated by a false returned here).
1052: // as of 1.7.2, always false
1053: return columnMetaData[--column].isDefinitelyWritable;
1054: }
1055:
1056: //--------------------------JDBC 2.0-----------------------------------
1057:
1058: /**
1059: * <!-- start generic documentation -->
1060: * Returns the fully-qualified name of the Java class whose instances
1061: * are manufactured if the method <code>ResultSet.getObject</code>
1062: * is called to retrieve a value from the column.
1063: * <code>ResultSet.getObject</code> may return a subclass of the class
1064: * returned by this method. <p>
1065: * <!-- end generic documentation -->
1066: *
1067: * <!-- start Release-specific documentation -->
1068: * <div class="ReleaseSpecificDocumentation">
1069: * <h3>HSQLDB-Specific Information:</h3> <p>
1070: *
1071: * HSQLDB 1.7.1 did not support this feature; calling this method
1072: * always caused an <code>SQLException</code> to be thrown,
1073: * stating that the function was not supported. <p>
1074: *
1075: * </div>
1076: * <!-- end release-specific documentation -->
1077: *
1078: * @param column the first column is 1, the second is 2, ...
1079: * @return the fully-qualified name of the class in the Java programming
1080: * language that would be used by the method
1081: * <code>ResultSet.getObject</code> to retrieve the value in the
1082: * specified column. This is the class name used for custom mapping.
1083: * @exception SQLException if a database access error occurs
1084: * @since JDK 1.2 (JDK 1.1.x developers: read the new overview for
1085: * jdbcResultSet)
1086: */
1087: public String getColumnClassName(int column) throws SQLException {
1088:
1089: checkColumn(column);
1090:
1091: return columnMetaData[--column].columnClassName;
1092: }
1093:
1094: public String toString() {
1095:
1096: StringBuffer sb = new StringBuffer();
1097:
1098: sb.append(super .toString());
1099:
1100: if (columnCount == 0) {
1101: sb.append("[columnCount=0]");
1102:
1103: return sb.toString();
1104: }
1105:
1106: sb.append('[');
1107:
1108: for (int i = 0; i < columnCount; i++) {
1109: sb.append('\n');
1110: sb.append(" column_");
1111: sb.append(i + 1);
1112: sb.append('=');
1113: sb.append(columnMetaData[i]);
1114:
1115: if (i + 1 < columnCount) {
1116: sb.append(',');
1117: sb.append(' ');
1118: }
1119: }
1120:
1121: sb.append('\n');
1122: sb.append(']');
1123:
1124: return sb.toString();
1125: }
1126:
1127: // ------------------------- Internal Implementation ---------------------------
1128:
1129: /**
1130: * Performs an internal check for column index validity. <p>
1131: *
1132: * @param column index of column to check
1133: * @throws SQLException when this object's parent ResultSet has
1134: * no such column
1135: */
1136: private void checkColumn(int column) throws SQLException {
1137:
1138: if (column < 1 || column > columnCount) {
1139: throw Util.sqlException(Trace.COLUMN_NOT_FOUND, String
1140: .valueOf(column));
1141: }
1142: }
1143: }
|