0001: // jTDS JDBC Driver for Microsoft SQL Server and Sybase
0002: // Copyright (C) 2004 The jTDS Project
0003: //
0004: // This library is free software; you can redistribute it and/or
0005: // modify it under the terms of the GNU Lesser General Public
0006: // License as published by the Free Software Foundation; either
0007: // version 2.1 of the License, or (at your option) any later version.
0008: //
0009: // This library is distributed in the hope that it will be useful,
0010: // but WITHOUT ANY WARRANTY; without even the implied warranty of
0011: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0012: // Lesser General Public License for more details.
0013: //
0014: // You should have received a copy of the GNU Lesser General Public
0015: // License along with this library; if not, write to the Free Software
0016: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0017: //
0018: package net.sourceforge.jtds.jdbc;
0019:
0020: import java.sql.*;
0021: import java.util.ArrayList;
0022: import java.util.Collection;
0023: import java.util.Collections;
0024: import java.util.Iterator;
0025: import java.util.List;
0026:
0027: /**
0028: * jTDS implementation of the java.sql.DatabaseMetaData interface.
0029: * <p>
0030: * Implementation note:
0031: * <p>
0032: * This is basically the code from the original jTDS driver.
0033: * Main changes relate to the need to support the new ResultSet
0034: * implementation.
0035: * <p>
0036: * TODO: Many of the system limits need to be revised to more accurately
0037: * reflect the target database constraints. In many cases limits are soft
0038: * and determined by bytes per column for example. Probably more of these
0039: * functions should be altered to return 0 but for now the original jTDS
0040: * values are returned.
0041: *
0042: * @author Craig Spannring
0043: * @author The FreeTDS project
0044: * @author Alin Sinpalean
0045: * created 17 March 2001
0046: * @version $Id: JtdsDatabaseMetaData.java,v 1.37 2007/07/08 17:28:23 bheineman Exp $
0047: */
0048: public class JtdsDatabaseMetaData implements java.sql.DatabaseMetaData {
0049: static final int sqlStateXOpen = 1;
0050:
0051: // Internal data needed by this implemention.
0052: private final int tdsVersion;
0053: private final int serverType;
0054: private final ConnectionJDBC2 connection;
0055:
0056: /**
0057: * Length of a sysname object (table name, catalog name etc.) -- 128 for
0058: * TDS 7.0, 30 for earlier versions.
0059: */
0060: int sysnameLength = 30;
0061:
0062: /**
0063: * <code>Boolean.TRUE</code> if identifiers are case sensitive (the server
0064: * was installed that way). Initially <code>null</code>, set the first time
0065: * any of the methods that check this are called.
0066: */
0067: Boolean caseSensitive;
0068:
0069: public JtdsDatabaseMetaData(ConnectionJDBC2 connection) {
0070: this .connection = connection;
0071: tdsVersion = connection.getTdsVersion();
0072: serverType = connection.getServerType();
0073: if (tdsVersion >= Driver.TDS70) {
0074: sysnameLength = 128;
0075: }
0076: }
0077:
0078: //----------------------------------------------------------------------
0079: // First, a variety of minor information about the target database.
0080:
0081: /**
0082: * Can all the procedures returned by getProcedures be called by the
0083: * current user?
0084: *
0085: * @return <code>true</code> if so
0086: * @throws SQLException if a database-access error occurs.
0087: */
0088: public boolean allProceduresAreCallable() throws SQLException {
0089: // Sybase - if accessible_sproc = Y in server info (normal case) return true
0090: return true; // per "Programming ODBC for SQLServer" Appendix A
0091: }
0092:
0093: /**
0094: * Can all the tables returned by getTable be SELECTed by the
0095: * current user?
0096: *
0097: * @return <code>true</code> if so
0098: * @throws SQLException if a database-access error occurs.
0099: */
0100: public boolean allTablesAreSelectable() throws SQLException {
0101: // Sybase sp_tables may return tables that you are not able to access.
0102: return connection.getServerType() == Driver.SQLSERVER;
0103: }
0104:
0105: /**
0106: * Does a data definition statement within a transaction force the
0107: * transaction to commit?
0108: *
0109: * @return <code>true</code> if so
0110: * @throws SQLException if a database-access error occurs.
0111: */
0112: public boolean dataDefinitionCausesTransactionCommit()
0113: throws SQLException {
0114: return false;
0115: }
0116:
0117: /**
0118: * Is a data definition statement within a transaction ignored?
0119: *
0120: * @return <code>true</code> if so
0121: * @throws SQLException if a database-access error occurs.
0122: */
0123: public boolean dataDefinitionIgnoredInTransactions()
0124: throws SQLException {
0125: return false;
0126: }
0127:
0128: /**
0129: * Did getMaxRowSize() include LONGVARCHAR and LONGVARBINARY blobs?
0130: *
0131: * @return <code>true</code> if so
0132: * @throws SQLException if a database-access error occurs.
0133: */
0134: public boolean doesMaxRowSizeIncludeBlobs() throws SQLException {
0135: return false;
0136: }
0137:
0138: /**
0139: * Get a description of a table's optimal set of columns that
0140: * uniquely identifies a row. They are ordered by SCOPE.
0141: *
0142: * <P>Each column description has the following columns:
0143: * <OL>
0144: * <LI> <B>SCOPE</B> short =>actual scope of result
0145: * <UL>
0146: * <LI> bestRowTemporary - very temporary, while using row
0147: * <LI> bestRowTransaction - valid for remainder of current transaction
0148: *
0149: * <LI> bestRowSession - valid for remainder of current session
0150: * </UL>
0151: *
0152: * <LI> <B>COLUMN_NAME</B> String =>column name
0153: * <LI> <B>DATA_TYPE</B> short =>SQL data type from java.sql.Types
0154: * <LI> <B>TYPE_NAME</B> String =>Data source dependent type name
0155: * <LI> <B>COLUMN_SIZE</B> int =>precision
0156: * <LI> <B>BUFFER_LENGTH</B> int =>not used
0157: * <LI> <B>DECIMAL_DIGITS</B> short =>scale
0158: * <LI> <B>PSEUDO_COLUMN</B> short =>is this a pseudo column like an
0159: * Oracle ROWID
0160: * <UL>
0161: * <LI> bestRowUnknown - may or may not be pseudo column
0162: * <LI> bestRowNotPseudo - is NOT a pseudo column
0163: * <LI> bestRowPseudo - is a pseudo column
0164: * </UL>
0165: *
0166: * </OL>
0167: *
0168: *
0169: * @param catalog a catalog name; "" retrieves those without a catalog;
0170: * <code>null</code> means drop catalog name from the selection criteria
0171: * @param schema a schema name; "" retrieves those without a schema
0172: * @param table a table name
0173: * @param scope the scope of interest; use same values as SCOPE
0174: * @param nullable include columns that are nullable?
0175: * @return ResultSet - each row is a column description
0176: * @throws SQLException if a database-access error occurs.
0177: */
0178: public java.sql.ResultSet getBestRowIdentifier(String catalog,
0179: String schema, String table, int scope, boolean nullable)
0180: throws SQLException {
0181: String colNames[] = { "SCOPE", "COLUMN_NAME", "DATA_TYPE",
0182: "TYPE_NAME", "COLUMN_SIZE", "BUFFER_LENGTH",
0183: "DECIMAL_DIGITS", "PSEUDO_COLUMN" };
0184: int colTypes[] = { Types.SMALLINT, Types.VARCHAR,
0185: Types.INTEGER, Types.VARCHAR, Types.INTEGER,
0186: Types.INTEGER, Types.SMALLINT, Types.SMALLINT };
0187:
0188: String query = "sp_special_columns ?, ?, ?, ?, ?, ?, ?";
0189:
0190: CallableStatement s = connection.prepareCall(syscall(catalog,
0191: query));
0192:
0193: s.setString(1, table);
0194: s.setString(2, schema);
0195: s.setString(3, catalog);
0196: s.setString(4, "R");
0197: s.setString(5, "T");
0198: s.setString(6, "U");
0199: s.setInt(7, 3); // ODBC version 3
0200:
0201: JtdsResultSet rs = (JtdsResultSet) s.executeQuery();
0202: CachedResultSet rsTmp = new CachedResultSet((JtdsStatement) s,
0203: colNames, colTypes);
0204: rsTmp.moveToInsertRow();
0205: int colCnt = rs.getMetaData().getColumnCount();
0206: while (rs.next()) {
0207: for (int i = 1; i <= colCnt; i++) {
0208: if (i == 3) {
0209: int type = TypeInfo.normalizeDataType(rs.getInt(i),
0210: connection.getUseLOBs());
0211: rsTmp.updateInt(i, type);
0212: } else {
0213: rsTmp.updateObject(i, rs.getObject(i));
0214: }
0215: }
0216: rsTmp.insertRow();
0217: }
0218: rs.close();
0219: // Do not close the statement, rsTmp is also built from it
0220: rsTmp.moveToCurrentRow();
0221: rsTmp.setConcurrency(ResultSet.CONCUR_READ_ONLY);
0222: return rsTmp;
0223: }
0224:
0225: /**
0226: * Get the catalog names available in this database. The results are
0227: * ordered by catalog name. <P>
0228: *
0229: * The catalog column is:
0230: * <OL>
0231: * <LI> <B>TABLE_CAT</B> String =>catalog name
0232: * </OL>
0233: *
0234: *
0235: * @return ResultSet - each row has a single String column
0236: * that is a catalog name
0237: * @throws SQLException if a database-access error occurs.
0238: */
0239: public java.sql.ResultSet getCatalogs() throws SQLException {
0240: String query = "exec sp_tables '', '', '%', NULL";
0241: Statement s = connection.createStatement();
0242: JtdsResultSet rs = (JtdsResultSet) s.executeQuery(query);
0243:
0244: rs.setColumnCount(1);
0245: rs.setColLabel(1, "TABLE_CAT");
0246:
0247: upperCaseColumnNames(rs);
0248:
0249: return rs;
0250: }
0251:
0252: /**
0253: * What's the separator between catalog and table name?
0254: *
0255: * @return the separator string
0256: * @throws SQLException if a database-access error occurs.
0257: */
0258: public String getCatalogSeparator() throws SQLException {
0259: return ".";
0260: }
0261:
0262: /**
0263: * What's the database vendor's preferred term for "catalog"?
0264: *
0265: * @return the vendor term
0266: * @throws SQLException if a database-access error occurs.
0267: */
0268: public String getCatalogTerm() throws SQLException {
0269: return "database";
0270: }
0271:
0272: /**
0273: * Get a description of the access rights for a table's columns. <P>
0274: *
0275: * Only privileges matching the column name criteria are returned. They are
0276: * ordered by COLUMN_NAME and PRIVILEGE. <P>
0277: *
0278: * Each privilige description has the following columns:
0279: * <OL>
0280: * <LI> <B>TABLE_CAT</B> String =>table catalog (may be null)
0281: * <LI> <B>TABLE_SCHEM</B> String =>table schema (may be null)
0282: * <LI> <B>TABLE_NAME</B> String =>table name
0283: * <LI> <B>COLUMN_NAME</B> String =>column name
0284: * <LI> <B>GRANTOR</B> =>grantor of access (may be null)
0285: * <LI> <B>GRANTEE</B> String =>grantee of access
0286: * <LI> <B>PRIVILEGE</B> String =>name of access (SELECT, INSERT, UPDATE,
0287: * REFRENCES, ...)
0288: * <LI> <B>IS_GRANTABLE</B> String =>"YES" if grantee is permitted to
0289: * grant to others; "NO" if not; null if unknown
0290: * </OL>
0291: *
0292: * @param catalog a catalog name; "" retrieves those without a catalog;
0293: * <code>null</code> means drop catalog name from the selection criteria
0294: * @param schema a schema name; "" retrieves those without a schema
0295: * schema
0296: * @param table a table name
0297: * @param columnNamePattern a column name pattern
0298: * @return ResultSet - each row is a column privilege description
0299: * @throws SQLException if a database-access error occurs.
0300: *
0301: * @see #getSearchStringEscape
0302: */
0303: public java.sql.ResultSet getColumnPrivileges(String catalog,
0304: String schema, String table, String columnNamePattern)
0305: throws SQLException {
0306: String query = "sp_column_privileges ?, ?, ?, ?";
0307:
0308: CallableStatement s = connection.prepareCall(syscall(catalog,
0309: query));
0310:
0311: s.setString(1, table);
0312: s.setString(2, schema);
0313: s.setString(3, catalog);
0314: s.setString(4, processEscapes(columnNamePattern));
0315:
0316: JtdsResultSet rs = (JtdsResultSet) s.executeQuery();
0317:
0318: rs.setColLabel(1, "TABLE_CAT");
0319: rs.setColLabel(2, "TABLE_SCHEM");
0320:
0321: upperCaseColumnNames(rs);
0322:
0323: return rs;
0324: }
0325:
0326: /**
0327: * Get a description of table columns available in a catalog. <P>
0328: *
0329: * Only column descriptions matching the catalog, schema, table and column
0330: * name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME
0331: * and ORDINAL_POSITION. <P>
0332: *
0333: * Each column description has the following columns:
0334: * <OL>
0335: * <LI> <B>TABLE_CAT</B> String =>table catalog (may be null)
0336: * <LI> <B>TABLE_SCHEM</B> String =>table schema (may be null)
0337: * <LI> <B>TABLE_NAME</B> String =>table name
0338: * <LI> <B>COLUMN_NAME</B> String =>column name
0339: * <LI> <B>DATA_TYPE</B> short =>SQL type from java.sql.Types
0340: * <LI> <B>TYPE_NAME</B> String =>Data source dependent type name
0341: * <LI> <B>COLUMN_SIZE</B> int =>column size. For char or date types this
0342: * is the maximum number of characters, for numeric or decimal types this
0343: * is precision.
0344: * <LI> <B>BUFFER_LENGTH</B> is not used.
0345: * <LI> <B>DECIMAL_DIGITS</B> int =>the number of fractional digits
0346: * <LI> <B>NUM_PREC_RADIX</B> int =>Radix (typically either 10 or 2)
0347: * <LI> <B>NULLABLE</B> int =>is NULL allowed?
0348: * <UL>
0349: * <LI> columnNoNulls - might not allow NULL values
0350: * <LI> columnNullable - definitely allows NULL values
0351: * <LI> columnNullableUnknown - nullability unknown
0352: * </UL>
0353: *
0354: * <LI> <B>REMARKS</B> String =>comment describing column (may be null)
0355: *
0356: * <LI> <B>COLUMN_DEF</B> String =>default value (may be null)
0357: * <LI> <B>SQL_DATA_TYPE</B> int =>unused
0358: * <LI> <B>SQL_DATETIME_SUB</B> int =>unused
0359: * <LI> <B>CHAR_OCTET_LENGTH</B> int =>for char types the maximum number
0360: * of bytes in the column
0361: * <LI> <B>ORDINAL_POSITION</B> int =>index of column in table (starting
0362: * at 1)
0363: * <LI> <B>IS_NULLABLE</B> String =>"NO" means column definitely does not
0364: * allow NULL values; "YES" means the column might allow NULL values. An
0365: * empty string means nobody knows.
0366: * </OL>
0367: *
0368: *
0369: * @param catalog a catalog name; "" retrieves those without a catalog;
0370: * <code>null</code> means drop catalog name from the selection criteria
0371: * @param schemaPattern a schema name pattern; "" retrieves those without a schema
0372: * @param tableNamePattern a table name pattern
0373: * @param columnNamePattern a column name pattern
0374: * @return ResultSet - each row is a column description
0375: * @throws SQLException if a database-access error occurs.
0376: *
0377: * @see #getSearchStringEscape
0378: */
0379: public java.sql.ResultSet getColumns(String catalog,
0380: String schemaPattern, String tableNamePattern,
0381: String columnNamePattern) throws SQLException {
0382: String colNames[] = { "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME",
0383: "COLUMN_NAME", "DATA_TYPE", "TYPE_NAME", "COLUMN_SIZE",
0384: "BUFFER_LENGTH", "DECIMAL_DIGITS", "NUM_PREC_RADIX",
0385: "NULLABLE", "REMARKS", "COLUMN_DEF", "SQL_DATA_TYPE",
0386: "SQL_DATETIME_SUB", "CHAR_OCTET_LENGTH",
0387: "ORDINAL_POSITION", "IS_NULLABLE", "SCOPE_CATALOG",
0388: "SCOPE_SCHEMA", "SCOPE_TABLE", "SOURCE_DATA_TYPE" };
0389:
0390: int colTypes[] = { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
0391: Types.VARCHAR, Types.INTEGER, Types.VARCHAR,
0392: Types.INTEGER, Types.INTEGER, Types.INTEGER,
0393: Types.INTEGER, Types.INTEGER, Types.VARCHAR,
0394: Types.VARCHAR, Types.INTEGER, Types.INTEGER,
0395: Types.INTEGER, Types.INTEGER, Types.VARCHAR,
0396: Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
0397: Types.SMALLINT };
0398: String query = "sp_columns ?, ?, ?, ?, ?";
0399:
0400: CallableStatement s = connection.prepareCall(syscall(catalog,
0401: query));
0402:
0403: s.setString(1, processEscapes(tableNamePattern));
0404: s.setString(2, processEscapes(schemaPattern));
0405: s.setString(3, catalog);
0406: s.setString(4, processEscapes(columnNamePattern));
0407: s.setInt(5, 3); // ODBC version 3
0408:
0409: JtdsResultSet rs = (JtdsResultSet) s.executeQuery();
0410:
0411: CachedResultSet rsTmp = new CachedResultSet((JtdsStatement) s,
0412: colNames, colTypes);
0413: rsTmp.moveToInsertRow();
0414: int colCnt = rs.getMetaData().getColumnCount();
0415: //
0416: // Neither type of server returns exactly the data required by the JDBC3 standard.
0417: // The result data is copied to a cached result set and modified on the fly.
0418: //
0419: while (rs.next()) {
0420: if (serverType == Driver.SYBASE) {
0421: // Sybase servers (older versions only return 14 columns)
0422: for (int i = 1; i <= 4; i++) {
0423: rsTmp.updateObject(i, rs.getObject(i));
0424: }
0425: rsTmp.updateInt(5, TypeInfo.normalizeDataType(rs
0426: .getInt(5), connection.getUseLOBs()));
0427: String typeName = rs.getString(6);
0428: rsTmp.updateString(6, typeName);
0429: for (int i = 8; i <= 12; i++) {
0430: rsTmp.updateObject(i, rs.getObject(i));
0431: }
0432: if (colCnt >= 20) {
0433: // SYBASE 11.92, 12.5
0434: for (int i = 13; i <= 18; i++) {
0435: rsTmp.updateObject(i, rs.getObject(i + 2));
0436: }
0437: } else {
0438: // SYBASE 11.03
0439: rsTmp.updateObject(16, rs.getObject(8));
0440: rsTmp.updateObject(17, rs.getObject(14));
0441: }
0442: if ("image".equals(typeName) || "text".equals(typeName)) {
0443: rsTmp.updateInt(7, Integer.MAX_VALUE);
0444: rsTmp.updateInt(16, Integer.MAX_VALUE);
0445: } else if ("univarchar".equals(typeName)
0446: || "unichar".equals(typeName)) {
0447: rsTmp.updateInt(7, rs.getInt(7) / 2);
0448: rsTmp.updateObject(16, rs.getObject(7));
0449: } else {
0450: rsTmp.updateInt(7, rs.getInt(7));
0451: }
0452: } else {
0453: // MS SQL Server - Mainly OK but we need to fix some data types.
0454: for (int i = 1; i <= colCnt; i++) {
0455: if (i == 5) {
0456: int type = TypeInfo.normalizeDataType(rs
0457: .getInt(i), connection.getUseLOBs());
0458: rsTmp.updateInt(i, type);
0459: } else if (i == 19) {
0460: // This is the SS_DATA_TYPE column and contains the TDS
0461: // data type constant. We can use this to distinguish
0462: // varchar(max) from text on SQL2005.
0463: rsTmp.updateString(6, TdsData.getMSTypeName(rs
0464: .getString(6), rs.getInt(19)));
0465: } else {
0466: rsTmp.updateObject(i, rs.getObject(i));
0467: }
0468: }
0469: }
0470: rsTmp.insertRow();
0471: }
0472: rs.close();
0473: rsTmp.moveToCurrentRow();
0474: rsTmp.setConcurrency(ResultSet.CONCUR_READ_ONLY);
0475:
0476: return rsTmp;
0477: }
0478:
0479: /**
0480: * Get a description of the foreign key columns in the foreign key table
0481: * that reference the primary key columns of the primary key table
0482: * (describe how one table imports another's key). This should normally
0483: * return a single foreign key/primary key pair (most tables only import a
0484: * foreign key from a table once.) They are ordered by FKTABLE_CAT,
0485: * FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ. <P>
0486: *
0487: * Each foreign key column description has the following columns:
0488: * <OL>
0489: * <LI> <B>PKTABLE_CAT</B> String =>primary key table catalog (may be
0490: * null)
0491: * <LI> <B>PKTABLE_SCHEM</B> String =>primary key table schema (may be
0492: * null)
0493: * <LI> <B>PKTABLE_NAME</B> String =>primary key table name
0494: * <LI> <B>PKCOLUMN_NAME</B> String =>primary key column name
0495: * <LI> <B>FKTABLE_CAT</B> String =>foreign key table catalog (may be
0496: * null) being exported (may be null)
0497: * <LI> <B>FKTABLE_SCHEM</B> String =>foreign key table schema (may be
0498: * null) being exported (may be null)
0499: * <LI> <B>FKTABLE_NAME</B> String =>foreign key table name being
0500: * exported
0501: * <LI> <B>FKCOLUMN_NAME</B> String =>foreign key column name being
0502: * exported
0503: * <LI> <B>KEY_SEQ</B> short =>sequence number within foreign key
0504: * <LI> <B>UPDATE_RULE</B> short =>What happens to foreign key when
0505: * primary is updated:
0506: * <UL>
0507: * <LI> importedNoAction - do not allow update of primary key if it has
0508: * been imported
0509: * <LI> importedKeyCascade - change imported key to agree with primary
0510: * key update
0511: * <LI> importedKeySetNull - change imported key to NULL if its primary
0512: * key has been updated
0513: * <LI> importedKeySetDefault - change imported key to default values
0514: * if its primary key has been updated
0515: * <LI> importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x
0516: * compatibility)
0517: * </UL>
0518: *
0519: * <LI> <B>DELETE_RULE</B> short =>What happens to the foreign key when
0520: * primary is deleted.
0521: * <UL>
0522: * <LI> importedKeyNoAction - do not allow delete of primary key if it
0523: * has been imported
0524: * <LI> importedKeyCascade - delete rows that import a deleted key
0525: * <LI> importedKeySetNull - change imported key to NULL if its primary
0526: * key has been deleted
0527: * <LI> importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x
0528: * compatibility)
0529: * <LI> importedKeySetDefault - change imported key to default if its
0530: * primary key has been deleted
0531: * </UL>
0532: *
0533: * <LI> <B>FK_NAME</B> String =>foreign key name (may be null)
0534: * <LI> <B>PK_NAME</B> String =>primary key name (may be null)
0535: * <LI> <B>DEFERRABILITY</B> short =>can the evaluation of foreign key
0536: * constraints be deferred until commit
0537: * <UL>
0538: * <LI> importedKeyInitiallyDeferred - see SQL92 for definition
0539: * <LI> importedKeyInitiallyImmediate - see SQL92 for definition
0540: * <LI> importedKeyNotDeferrable - see SQL92 for definition
0541: * </UL>
0542: *
0543: * </OL>
0544: *
0545: * @param primaryCatalog a catalog name; "" retrieves those without a
0546: * <code>null</code> means drop catalog name from the selection criteria
0547: * @param primarySchema a schema name pattern; "" retrieves those without a schema
0548: * @param primaryTable the table name that exports the key
0549: * @param foreignCatalog a catalog name; "" retrieves those without a
0550: * <code>null</code> means drop catalog name from the selection criteria
0551: * @param foreignSchema a schema name pattern; "" retrieves those without a schema
0552: * @param foreignTable the table name that imports the key
0553: * @return ResultSet - each row is a foreign key column description
0554: * @throws SQLException if a database-access error occurs.
0555: *
0556: * @see #getImportedKeys
0557: */
0558: public java.sql.ResultSet getCrossReference(String primaryCatalog,
0559: String primarySchema, String primaryTable,
0560: String foreignCatalog, String foreignSchema,
0561: String foreignTable) throws SQLException {
0562: String colNames[] = { "PKTABLE_CAT", "PKTABLE_SCHEM",
0563: "PKTABLE_NAME", "PKCOLUMN_NAME", "FKTABLE_CAT",
0564: "FKTABLE_SCHEM", "FKTABLE_NAME", "FKCOLUMN_NAME",
0565: "KEY_SEQ", "UPDATE_RULE", "DELETE_RULE", "FK_NAME",
0566: "PK_NAME", "DEFERRABILITY" };
0567: int colTypes[] = { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
0568: Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
0569: Types.VARCHAR, Types.VARCHAR, Types.SMALLINT,
0570: Types.SMALLINT, Types.SMALLINT, Types.VARCHAR,
0571: Types.VARCHAR, Types.SMALLINT };
0572:
0573: String query = "sp_fkeys ?, ?, ?, ?, ?, ?";
0574:
0575: if (primaryCatalog != null) {
0576: query = syscall(primaryCatalog, query);
0577: } else if (foreignCatalog != null) {
0578: query = syscall(foreignCatalog, query);
0579: } else {
0580: query = syscall(null, query);
0581: }
0582:
0583: CallableStatement s = connection.prepareCall(query);
0584:
0585: s.setString(1, primaryTable);
0586: s.setString(2, processEscapes(primarySchema));
0587: s.setString(3, primaryCatalog);
0588: s.setString(4, foreignTable);
0589: s.setString(5, processEscapes(foreignSchema));
0590: s.setString(6, foreignCatalog);
0591:
0592: JtdsResultSet rs = (JtdsResultSet) s.executeQuery();
0593: int colCnt = rs.getMetaData().getColumnCount();
0594: CachedResultSet rsTmp = new CachedResultSet((JtdsStatement) s,
0595: colNames, colTypes);
0596: rsTmp.moveToInsertRow();
0597: while (rs.next()) {
0598: for (int i = 1; i <= colCnt; i++) {
0599: rsTmp.updateObject(i, rs.getObject(i));
0600: }
0601: if (colCnt < 14) {
0602: rsTmp
0603: .updateShort(
0604: 14,
0605: (short) DatabaseMetaData.importedKeyNotDeferrable);
0606: }
0607: rsTmp.insertRow();
0608: }
0609: rs.close();
0610: rsTmp.moveToCurrentRow();
0611: rsTmp.setConcurrency(ResultSet.CONCUR_READ_ONLY);
0612:
0613: return rsTmp;
0614: }
0615:
0616: /**
0617: * Returns the name of this database product.
0618: *
0619: * @return database product name
0620: * @throws SQLException if a database-access error occurs.
0621: */
0622: public String getDatabaseProductName() throws SQLException {
0623: return connection.getDatabaseProductName();
0624: }
0625:
0626: /**
0627: * Returns the version of this database product.
0628: *
0629: * @return database version
0630: * @throws SQLException if a database-access error occurs.
0631: */
0632: public String getDatabaseProductVersion() throws SQLException {
0633: return connection.getDatabaseProductVersion();
0634: }
0635:
0636: //----------------------------------------------------------------------
0637:
0638: /**
0639: * Returns the database's default transaction isolation level. The values
0640: * are defined in java.sql.Connection.
0641: *
0642: * @return the default isolation level
0643: * @throws SQLException if a database-access error occurs.
0644: *
0645: * @see Connection
0646: */
0647: public int getDefaultTransactionIsolation() throws SQLException {
0648: return Connection.TRANSACTION_READ_COMMITTED;
0649: }
0650:
0651: /**
0652: * Returns this JDBC driver's major version number.
0653: *
0654: * @return JDBC driver major version
0655: */
0656: public int getDriverMajorVersion() {
0657: return Driver.MAJOR_VERSION;
0658: }
0659:
0660: /**
0661: * Returns this JDBC driver's minor version number.
0662: *
0663: * @return JDBC driver minor version number
0664: */
0665: public int getDriverMinorVersion() {
0666: return Driver.MINOR_VERSION;
0667: }
0668:
0669: /**
0670: * Returns the name of this JDBC driver.
0671: *
0672: * @return JDBC driver name
0673: * @throws SQLException if a database-access error occurs.
0674: */
0675: public String getDriverName() throws SQLException {
0676: return "jTDS Type 4 JDBC Driver for MS SQL Server and Sybase";
0677: }
0678:
0679: /**
0680: * Returns the version of this JDBC driver.
0681: *
0682: * @return JDBC driver version
0683: * @throws SQLException if a database-access error occurs.
0684: */
0685: public String getDriverVersion() throws SQLException {
0686: return Driver.getVersion();
0687: }
0688:
0689: /**
0690: * Get a description of the foreign key columns that reference a table's
0691: * primary key columns (the foreign keys exported by a table). They are
0692: * ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.
0693: * <p>
0694: * Each foreign key column description has the following columns:
0695: * <OL>
0696: * <LI> <B>PKTABLE_CAT</B> String =>primary key table catalog (may be
0697: * null)
0698: * <LI> <B>PKTABLE_SCHEM</B> String =>primary key table schema (may be
0699: * null)
0700: * <LI> <B>PKTABLE_NAME</B> String =>primary key table name
0701: * <LI> <B>PKCOLUMN_NAME</B> String =>primary key column name
0702: * <LI> <B>FKTABLE_CAT</B> String =>foreign key table catalog (may be
0703: * null) being exported (may be null)
0704: * <LI> <B>FKTABLE_SCHEM</B> String =>foreign key table schema (may be
0705: * null) being exported (may be null)
0706: * <LI> <B>FKTABLE_NAME</B> String =>foreign key table name being
0707: * exported
0708: * <LI> <B>FKCOLUMN_NAME</B> String =>foreign key column name being
0709: * exported
0710: * <LI> <B>KEY_SEQ</B> short =>sequence number within foreign key
0711: * <LI> <B>UPDATE_RULE</B> short =>What happens to foreign key when
0712: * primary is updated:
0713: * <UL>
0714: * <LI> importedNoAction - do not allow update of primary key if it has
0715: * been imported
0716: * <LI> importedKeyCascade - change imported key to agree with primary
0717: * key update
0718: * <LI> importedKeySetNull - change imported key to NULL if its primary
0719: * key has been updated
0720: * <LI> importedKeySetDefault - change imported key to default values
0721: * if its primary key has been updated
0722: * <LI> importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x
0723: * compatibility)
0724: * </UL>
0725: *
0726: * <LI> <B>DELETE_RULE</B> short =>What happens to the foreign key when
0727: * primary is deleted.
0728: * <UL>
0729: * <LI> importedKeyNoAction - do not allow delete of primary key if it
0730: * has been imported
0731: * <LI> importedKeyCascade - delete rows that import a deleted key
0732: * <LI> importedKeySetNull - change imported key to NULL if its primary
0733: * key has been deleted
0734: * <LI> importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x
0735: * compatibility)
0736: * <LI> importedKeySetDefault - change imported key to default if its
0737: * primary key has been deleted
0738: * </UL>
0739: *
0740: * <LI> <B>FK_NAME</B> String =>foreign key name (may be null)
0741: * <LI> <B>PK_NAME</B> String =>primary key name (may be null)
0742: * <LI> <B>DEFERRABILITY</B> short =>can the evaluation of foreign key
0743: * constraints be deferred until commit
0744: * <UL>
0745: * <LI> importedKeyInitiallyDeferred - see SQL92 for definition
0746: * <LI> importedKeyInitiallyImmediate - see SQL92 for definition
0747: * <LI> importedKeyNotDeferrable - see SQL92 for definition
0748: * </UL>
0749: *
0750: * </OL>
0751: *
0752: *
0753: * @param catalog a catalog name; "" retrieves those without a
0754: * <code>null</code> means drop catalog name from the selection criteria
0755: * @param schema a schema name; "" retrieves those without a schema
0756: * @param table a table name
0757: * @return ResultSet - each row is a foreign key column description
0758: * @throws SQLException if a database-access error occurs.
0759: *
0760: * @see #getImportedKeys
0761: */
0762: public java.sql.ResultSet getExportedKeys(String catalog,
0763: String schema, String table) throws SQLException {
0764: return getCrossReference(catalog, schema, table, null, null,
0765: null);
0766: }
0767:
0768: /**
0769: * Get all the "extra" characters that can be used in unquoted identifier
0770: * names (those beyond a-z, A-Z, 0-9 and _).
0771: *
0772: * @return the string containing the extra characters
0773: * @throws SQLException if a database-access error occurs.
0774: */
0775: public String getExtraNameCharacters() throws SQLException {
0776: // MS driver returns "$#@" Sybase JConnect returns "@#$£¥"
0777: return "$#@";
0778: }
0779:
0780: /**
0781: * Returns the string used to quote SQL identifiers. This returns a space "
0782: * " if identifier quoting isn't supported. A JDBC-Compliant driver always
0783: * uses a double quote character.
0784: *
0785: * @return the quoting string
0786: * @throws SQLException if a database-access error occurs.
0787: */
0788: public String getIdentifierQuoteString() throws SQLException {
0789: return "\"";
0790: }
0791:
0792: /**
0793: * Get a description of the primary key columns that are referenced by a
0794: * table's foreign key columns (the primary keys imported by a table). They
0795: * are ordered by PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.
0796: * <p>
0797: * Each primary key column description has the following columns:
0798: * <OL>
0799: * <LI> <B>PKTABLE_CAT</B> String =>primary key table catalog being
0800: * imported (may be null)
0801: * <LI> <B>PKTABLE_SCHEM</B> String =>primary key table schema being
0802: * imported (may be null)
0803: * <LI> <B>PKTABLE_NAME</B> String =>primary key table name being
0804: * imported
0805: * <LI> <B>PKCOLUMN_NAME</B> String =>primary key column name being
0806: * imported
0807: * <LI> <B>FKTABLE_CAT</B> String =>foreign key table catalog (may be
0808: * null)
0809: * <LI> <B>FKTABLE_SCHEM</B> String =>foreign key table schema (may be
0810: * null)
0811: * <LI> <B>FKTABLE_NAME</B> String =>foreign key table name
0812: * <LI> <B>FKCOLUMN_NAME</B> String =>foreign key column name
0813: * <LI> <B>KEY_SEQ</B> short =>sequence number within foreign key
0814: * <LI> <B>UPDATE_RULE</B> short =>What happens to foreign key when
0815: * primary is updated:
0816: * <UL>
0817: * <LI> importedNoAction - do not allow update of primary key if it has
0818: * been imported
0819: * <LI> importedKeyCascade - change imported key to agree with primary
0820: * key update
0821: * <LI> importedKeySetNull - change imported key to NULL if its primary
0822: * key has been updated
0823: * <LI> importedKeySetDefault - change imported key to default values
0824: * if its primary key has been updated
0825: * <LI> importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x
0826: * compatibility)
0827: * </UL>
0828: *
0829: * <LI> <B>DELETE_RULE</B> short =>What happens to the foreign key when
0830: * primary is deleted.
0831: * <UL>
0832: * <LI> importedKeyNoAction - do not allow delete of primary key if it
0833: * has been imported
0834: * <LI> importedKeyCascade - delete rows that import a deleted key
0835: * <LI> importedKeySetNull - change imported key to NULL if its primary
0836: * key has been deleted
0837: * <LI> importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x
0838: * compatibility)
0839: * <LI> importedKeySetDefault - change imported key to default if its
0840: * primary key has been deleted
0841: * </UL>
0842: *
0843: * <LI> <B>FK_NAME</B> String =>foreign key name (may be null)
0844: * <LI> <B>PK_NAME</B> String =>primary key name (may be null)
0845: * <LI> <B>DEFERRABILITY</B> short =>can the evaluation of foreign key
0846: * constraints be deferred until commit
0847: * <UL>
0848: * <LI> importedKeyInitiallyDeferred - see SQL92 for definition
0849: * <LI> importedKeyInitiallyImmediate - see SQL92 for definition
0850: * <LI> importedKeyNotDeferrable - see SQL92 for definition
0851: * </UL>
0852: *
0853: * </OL>
0854: *
0855: * @param catalog a catalog name; "" retrieves those without a
0856: * <code>null</code> means drop catalog name from the selection criteria
0857: * @param schema a schema name; "" retrieves those without a schema
0858: * @param table a table name
0859: * @return ResultSet - each row is a primary key column description
0860: * @throws SQLException if a database-access error occurs.
0861: *
0862: * @see #getExportedKeys
0863: */
0864: public java.sql.ResultSet getImportedKeys(String catalog,
0865: String schema, String table) throws SQLException {
0866: return getCrossReference(null, null, null, catalog, schema,
0867: table);
0868: }
0869:
0870: /**
0871: * Get a description of a table's indices and statistics. They are ordered
0872: * by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION. <P>
0873: *
0874: * Each index column description has the following columns:
0875: * <OL>
0876: * <LI> <B>TABLE_CAT</B> String =>table catalog (may be null)
0877: * <LI> <B>TABLE_SCHEM</B> String =>table schema (may be null)
0878: * <LI> <B>TABLE_NAME</B> String =>table name
0879: * <LI> <B>NON_UNIQUE</B> boolean =>Can index values be non-unique? false
0880: * when TYPE is tableIndexStatistic
0881: * <LI> <B>INDEX_QUALIFIER</B> String =>index catalog (may be null); null
0882: * when TYPE is tableIndexStatistic
0883: * <LI> <B>INDEX_NAME</B> String =>index name; null when TYPE is
0884: * tableIndexStatistic
0885: * <LI> <B>TYPE</B> short =>index type:
0886: * <UL>
0887: * <LI> tableIndexStatistic - this identifies table statistics that are
0888: * returned in conjuction with a table's index descriptions
0889: * <LI> tableIndexClustered - this is a clustered index
0890: * <LI> tableIndexHashed - this is a hashed index
0891: * <LI> tableIndexOther - this is some other style of index
0892: * </UL>
0893: *
0894: * <LI> <B>ORDINAL_POSITION</B> short =>column sequence number within
0895: * index; zero when TYPE is tableIndexStatistic
0896: * <LI> <B>COLUMN_NAME</B> String =>column name; null when TYPE is
0897: * tableIndexStatistic
0898: * <LI> <B>ASC_OR_DESC</B> String =>column sort sequence, "A" =>
0899: * ascending, "D" =>descending, may be null if sort sequence is not
0900: * supported; null when TYPE is tableIndexStatistic
0901: * <LI> <B>CARDINALITY</B> int =>When TYPE is tableIndexStatistic, then
0902: * this is the number of rows in the table; otherwise, it is the number
0903: * of unique values in the index.
0904: * <LI> <B>PAGES</B> int =>When TYPE is tableIndexStatisic then this is
0905: * the number of pages used for the table, otherwise it is the number of
0906: * pages used for the current index.
0907: * <LI> <B>FILTER_CONDITION</B> String =>Filter condition, if any. (may
0908: * be null)
0909: * </OL>
0910: *
0911: * @param catalog a catalog name; "" retrieves those without a
0912: * <code>null</code> means drop catalog name from the selection criteria
0913: * @param schema a schema name; "" retrieves those without a schema
0914: * @param table a table name
0915: * @param unique when <code>true</code>, return only indices for unique
0916: * values; when <code>false</code>, return indices regardless of
0917: * whether unique or not
0918: * @param approximate when <code>true</code>, result is allowed to reflect
0919: * approximate or out of data values; when <code>false</code>, results
0920: * are requested to be accurate
0921: * @return ResultSet - each row is an index column description
0922: * @throws SQLException if a database-access error occurs.
0923: */
0924: public java.sql.ResultSet getIndexInfo(String catalog,
0925: String schema, String table, boolean unique,
0926: boolean approximate) throws SQLException {
0927: String colNames[] = { "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME",
0928: "NON_UNIQUE", "INDEX_QUALIFIER", "INDEX_NAME", "TYPE",
0929: "ORDINAL_POSITION", "COLUMN_NAME", "ASC_OR_DESC",
0930: "CARDINALITY", "PAGES", "FILTER_CONDITION" };
0931: int colTypes[] = { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
0932: Types.BIT, Types.VARCHAR, Types.VARCHAR,
0933: Types.SMALLINT, Types.SMALLINT, Types.VARCHAR,
0934: Types.VARCHAR, Types.INTEGER, Types.INTEGER,
0935: Types.VARCHAR };
0936: String query = "sp_statistics ?, ?, ?, ?, ?, ?";
0937:
0938: CallableStatement s = connection.prepareCall(syscall(catalog,
0939: query));
0940:
0941: s.setString(1, table);
0942: s.setString(2, schema);
0943: s.setString(3, catalog);
0944: s.setString(4, "%");
0945: s.setString(5, unique ? "Y" : "N");
0946: s.setString(6, approximate ? "Q" : "E");
0947:
0948: JtdsResultSet rs = (JtdsResultSet) s.executeQuery();
0949: int colCnt = rs.getMetaData().getColumnCount();
0950: CachedResultSet rsTmp = new CachedResultSet((JtdsStatement) s,
0951: colNames, colTypes);
0952: rsTmp.moveToInsertRow();
0953: while (rs.next()) {
0954: for (int i = 1; i <= colCnt; i++) {
0955: rsTmp.updateObject(i, rs.getObject(i));
0956: }
0957: rsTmp.insertRow();
0958: }
0959: rs.close();
0960: rsTmp.moveToCurrentRow();
0961: rsTmp.setConcurrency(ResultSet.CONCUR_READ_ONLY);
0962:
0963: return rsTmp;
0964: }
0965:
0966: //----------------------------------------------------------------------
0967: // The following group of methods exposes various limitations
0968: // based on the target database with the current driver.
0969: // Unless otherwise specified, a result of zero means there is no
0970: // limit, or the limit is not known.
0971:
0972: /**
0973: * How many hex characters can you have in an inline binary literal?
0974: *
0975: * @return max literal length
0976: * @throws SQLException if a database-access error occurs.
0977: */
0978: public int getMaxBinaryLiteralLength() throws SQLException {
0979: // Sybase jConnect says 255
0980: // Actual value is 16384 for Sybase 12.5
0981: // MS JDBC says 0
0982: // Probable maximum size for MS is 65,536 * network packet size
0983: return 131072;
0984: // per "Programming ODBC for SQLServer" Appendix A
0985: }
0986:
0987: /**
0988: * What's the maximum length of a catalog name?
0989: *
0990: * @return max name length in bytes
0991: * @throws SQLException if a database-access error occurs.
0992: */
0993: public int getMaxCatalogNameLength() throws SQLException {
0994: return sysnameLength;
0995: }
0996:
0997: /**
0998: * What's the max length for a character literal?
0999: *
1000: * @return max literal length
1001: * @throws SQLException if a database-access error occurs.
1002: */
1003: public int getMaxCharLiteralLength() throws SQLException {
1004: // Sybase jConnect says 255
1005: // Actual value is 16384 for Sybase 12.5
1006: // MS JDBC says 0
1007: // Probable maximum size for MS is 65,536 * network packet size
1008: return 131072;
1009: // per "Programming ODBC for SQLServer" Appendix A
1010: }
1011:
1012: /**
1013: * What's the limit on column name length?
1014: *
1015: * @return max literal length
1016: * @throws SQLException if a database-access error occurs.
1017: */
1018: public int getMaxColumnNameLength() throws SQLException {
1019: // per "Programming ODBC for SQLServer" Appendix A
1020: return sysnameLength;
1021: }
1022:
1023: /**
1024: * What's the maximum number of columns in a "GROUP BY" clause?
1025: *
1026: * @return max number of columns
1027: * @throws SQLException if a database-access error occurs.
1028: */
1029: public int getMaxColumnsInGroupBy() throws SQLException {
1030: // Sybase jConnect says 16
1031: // MS JDBC says 16
1032: // per "Programming ODBC for SQLServer" Appendix A
1033: // Actual MS value is 8060 / average bytes per column
1034: return (tdsVersion >= Driver.TDS70) ? 0 : 16;
1035: }
1036:
1037: /**
1038: * What's the maximum number of columns allowed in an index?
1039: *
1040: * @return max columns
1041: * @throws SQLException if a database-access error occurs.
1042: */
1043: public int getMaxColumnsInIndex() throws SQLException {
1044: // per SQL Server Books Online "Administrator's Companion",
1045: // Part 1, Chapter 1.
1046: // Sybase 12.5 is 31
1047: return 16;
1048: }
1049:
1050: /**
1051: * What's the maximum number of columns in an "ORDER BY" clause?
1052: *
1053: * @return max columns
1054: * @throws SQLException if a database-access error occurs.
1055: */
1056: public int getMaxColumnsInOrderBy() throws SQLException {
1057: // per "Programming ODBC for SQLServer" Appendix A
1058: // Sybase 12.5 is 31
1059: // Actual MS value is 8060 / average bytes per column
1060: return (tdsVersion >= Driver.TDS70) ? 0 : 16;
1061: }
1062:
1063: /**
1064: * What's the maximum number of columns in a "SELECT" list?
1065: *
1066: * @return max columns
1067: * @throws SQLException if a database-access error occurs.
1068: */
1069: public int getMaxColumnsInSelect() throws SQLException {
1070: // Sybase jConnect says 0
1071: // per "Programming ODBC for SQLServer" Appendix A
1072: return 4096;
1073: }
1074:
1075: /**
1076: * What's the maximum number of columns in a table?
1077: *
1078: * @return max columns
1079: * @throws SQLException if a database-access error occurs.
1080: */
1081: public int getMaxColumnsInTable() throws SQLException {
1082: // Sybase jConnect says 250
1083: // per "Programming ODBC for SQLServer" Appendix A
1084: // MS 2000 should be 4096
1085: // Sybase 12.5 is now 1024
1086: return (tdsVersion >= Driver.TDS70) ? 1024 : 250;
1087: }
1088:
1089: /**
1090: * How many active connections can we have at a time to this database?
1091: *
1092: * @return max connections
1093: * @throws SQLException if a database-access error occurs.
1094: */
1095: public int getMaxConnections() throws SQLException {
1096: // Sybase - could query syscurconfigs to get actual value
1097: // which in practice will be a lot less than 32767!
1098: // per SQL Server Books Online "Administrator's Companion",
1099: // Part 1, Chapter 1.
1100: return 32767;
1101: }
1102:
1103: /**
1104: * What's the maximum cursor name length?
1105: *
1106: * @return max cursor name length in bytes
1107: * @throws SQLException if a database-access error occurs.
1108: */
1109: public int getMaxCursorNameLength() throws SQLException {
1110: // per "Programming ODBC for SQLServer" Appendix A
1111: return sysnameLength;
1112: }
1113:
1114: /**
1115: * What's the maximum length of an index (in bytes)?
1116: *
1117: * @return max index length in bytes
1118: * @throws SQLException if a database-access error occurs.
1119: */
1120: public int getMaxIndexLength() throws SQLException {
1121: // Sybase JConnect says 255
1122: // Actual Sybase 12.5 is 600 - 5300 depending on page size
1123: // per "Programming ODBC for SQLServer" Appendix A
1124: return (tdsVersion >= Driver.TDS70) ? 900 : 255;
1125: }
1126:
1127: /**
1128: * What's the maximum length of a procedure name?
1129: *
1130: * @return max name length in bytes
1131: * @throws SQLException if a database-access error occurs.
1132: */
1133: public int getMaxProcedureNameLength() throws SQLException {
1134: // per "Programming ODBC for SQLServer" Appendix A
1135: return sysnameLength;
1136: }
1137:
1138: /**
1139: * What's the maximum length of a single row?
1140: *
1141: * @return max row size in bytes
1142: * @throws SQLException if a database-access error occurs.
1143: */
1144: public int getMaxRowSize() throws SQLException {
1145: // Sybase jConnect says 1962 but this can be more with wide tables.
1146: // per SQL Server Books Online "Administrator's Companion",
1147: // Part 1, Chapter 1.
1148: return (tdsVersion >= Driver.TDS70) ? 8060 : 1962;
1149: }
1150:
1151: /**
1152: * What's the maximum length allowed for a schema name?
1153: *
1154: * @return max name length in bytes
1155: * @throws SQLException if a database-access error occurs.
1156: */
1157: public int getMaxSchemaNameLength() throws SQLException {
1158: return sysnameLength;
1159: }
1160:
1161: /**
1162: * What's the maximum length of a SQL statement?
1163: *
1164: * @return max length in bytes
1165: * @throws SQLException if a database-access error occurs.
1166: */
1167: public int getMaxStatementLength() throws SQLException {
1168: // I think this should return 0 (no limit)
1169: // actual limit for SQL 7/2000 is 65536 * packet size!
1170: // Sybase JConnect says 0
1171: // MS JDBC says 0
1172: // per "Programming ODBC for SQLServer" Appendix A
1173: return 0;
1174: }
1175:
1176: /**
1177: * How many active statements can we have open at one time to this
1178: * database?
1179: *
1180: * @return the maximum
1181: * @throws SQLException if a database-access error occurs.
1182: */
1183: public int getMaxStatements() throws SQLException {
1184: return 0;
1185: }
1186:
1187: /**
1188: * What's the maximum length of a table name?
1189: *
1190: * @return max name length in bytes
1191: * @throws SQLException if a database-access error occurs.
1192: */
1193: public int getMaxTableNameLength() throws SQLException {
1194: // per "Programming ODBC for SQLServer" Appendix A
1195: return sysnameLength;
1196: }
1197:
1198: /**
1199: * What's the maximum number of tables in a SELECT?
1200: *
1201: * @return the maximum
1202: * @throws SQLException if a database-access error occurs.
1203: */
1204: public int getMaxTablesInSelect() throws SQLException {
1205: // Sybase JConnect says 256
1206: // MS JDBC says 32!
1207: // Actual Sybase 12.5 is 50
1208: // per "Programming ODBC for SQLServer" Appendix A
1209: return (tdsVersion > Driver.TDS50) ? 256 : 16;
1210: }
1211:
1212: /**
1213: * What's the maximum length of a user name?
1214: *
1215: * @return max name length in bytes
1216: * @throws SQLException if a database-access error occurs.
1217: */
1218: public int getMaxUserNameLength() throws SQLException {
1219: return sysnameLength;
1220: }
1221:
1222: /**
1223: * Get a comma separated list of math functions.
1224: *
1225: * @return the list
1226: * @throws SQLException if a database-access error occurs.
1227: */
1228: public String getNumericFunctions() throws SQLException {
1229: // I don't think either Sybase or SQL have a truncate maths function
1230: // so I have removed it from the list.
1231: // Also all other drivers return this list in lower case. Should we?
1232: return "abs,acos,asin,atan,atan2,ceiling,cos,cot,degrees,exp,floor,log,"
1233: + "log10,mod,pi,power,radians,rand,round,sign,sin,sqrt,tan";
1234: }
1235:
1236: /**
1237: * Get a description of a table's primary key columns. They are ordered by
1238: * COLUMN_NAME. <P>
1239: *
1240: * Each primary key column description has the following columns:
1241: * <OL>
1242: * <LI> <B>TABLE_CAT</B> String =>table catalog (may be null)
1243: * <LI> <B>TABLE_SCHEM</B> String =>table schema (may be null)
1244: * <LI> <B>TABLE_NAME</B> String =>table name
1245: * <LI> <B>COLUMN_NAME</B> String =>column name
1246: * <LI> <B>KEY_SEQ</B> short =>sequence number within primary key
1247: * <LI> <B>PK_NAME</B> String =>primary key name (may be null)
1248: * </OL>
1249: *
1250: * @param catalog a catalog name; "" retrieves those without a
1251: * <code>null</code> means drop catalog name from the selection criteria
1252: * @param schema a schema name; "" retrieves those without a schema
1253: * @param table a table name
1254: * @return ResultSet - each row is a primary key column description
1255: * @throws SQLException if a database-access error occurs.
1256: */
1257: public java.sql.ResultSet getPrimaryKeys(String catalog,
1258: String schema, String table) throws SQLException {
1259: String colNames[] = { "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME",
1260: "COLUMN_NAME", "KEY_SEQ", "PK_NAME" };
1261: int colTypes[] = { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1262: Types.VARCHAR, Types.SMALLINT, Types.VARCHAR };
1263: String query = "sp_pkeys ?, ?, ?";
1264:
1265: CallableStatement s = connection.prepareCall(syscall(catalog,
1266: query));
1267:
1268: s.setString(1, table);
1269: s.setString(2, schema);
1270: s.setString(3, catalog);
1271:
1272: JtdsResultSet rs = (JtdsResultSet) s.executeQuery();
1273: CachedResultSet rsTmp = new CachedResultSet((JtdsStatement) s,
1274: colNames, colTypes);
1275: rsTmp.moveToInsertRow();
1276: int colCnt = rs.getMetaData().getColumnCount();
1277: while (rs.next()) {
1278: for (int i = 1; i <= colCnt; i++) {
1279: rsTmp.updateObject(i, rs.getObject(i));
1280: }
1281: rsTmp.insertRow();
1282: }
1283: rs.close();
1284: rsTmp.moveToCurrentRow();
1285: rsTmp.setConcurrency(ResultSet.CONCUR_READ_ONLY);
1286:
1287: return rsTmp;
1288: }
1289:
1290: /**
1291: * Get a description of a catalog's stored procedure parameters and result
1292: * columns. <P>
1293: *
1294: * Only descriptions matching the schema, procedure and parameter name
1295: * criteria are returned. They are ordered by PROCEDURE_SCHEM and
1296: * PROCEDURE_NAME. Within this, the return value, if any, is first. Next
1297: * are the parameter descriptions in call order. The column descriptions
1298: * follow in column number order. <P>
1299: *
1300: * Each row in the ResultSet is a parameter description or column
1301: * description with the following fields:
1302: * <OL>
1303: * <LI> <B>PROCEDURE_CAT</B> String =>procedure catalog (may be null)
1304: *
1305: * <LI> <B>PROCEDURE_SCHEM</B> String =>procedure schema (may be null)
1306: *
1307: * <LI> <B>PROCEDURE_NAME</B> String =>procedure name
1308: * <LI> <B>COLUMN_NAME</B> String =>column/parameter name
1309: * <LI> <B>COLUMN_TYPE</B> Short =>kind of column/parameter:
1310: * <UL>
1311: * <LI> procedureColumnUnknown - nobody knows
1312: * <LI> procedureColumnIn - IN parameter
1313: * <LI> procedureColumnInOut - INOUT parameter
1314: * <LI> procedureColumnOut - OUT parameter
1315: * <LI> procedureColumnReturn - procedure return value
1316: * <LI> procedureColumnResult - result column in ResultSet
1317: * </UL>
1318: *
1319: * <LI> <B>DATA_TYPE</B> short =>SQL type from java.sql.Types
1320: * <LI> <B>TYPE_NAME</B> String =>SQL type name
1321: * <LI> <B>PRECISION</B> int =>precision
1322: * <LI> <B>LENGTH</B> int =>length in bytes of data
1323: * <LI> <B>SCALE</B> short =>scale
1324: * <LI> <B>RADIX</B> short =>radix
1325: * <LI> <B>NULLABLE</B> short =>can it contain NULL?
1326: * <UL>
1327: * <LI> procedureNoNulls - does not allow NULL values
1328: * <LI> procedureNullable - allows NULL values
1329: * <LI> procedureNullableUnknown - nullability unknown
1330: * </UL>
1331: *
1332: * <LI> <B>REMARKS</B> String =>comment describing parameter/column
1333: * </OL>
1334: * <P>
1335: *
1336: * <B>Note:</B> Some databases may not return the column descriptions for a
1337: * procedure. Additional columns beyond REMARKS can be defined by the
1338: * database.
1339: *
1340: * @param catalog a catalog name; "" retrieves those without a
1341: * <code>null</code> means drop catalog name from the selection criteria
1342: * @param schemaPattern a schema name pattern; "" retrieves those
1343: * without a schema
1344: * @param procedureNamePattern a procedure name pattern
1345: * @param columnNamePattern a column name pattern
1346: * @return ResultSet - each row is a stored procedure parameter or column description
1347: * @throws SQLException if a database-access error occurs.
1348: * @see #getSearchStringEscape
1349: */
1350: public java.sql.ResultSet getProcedureColumns(String catalog,
1351: String schemaPattern, String procedureNamePattern,
1352: String columnNamePattern) throws SQLException {
1353: String colNames[] = { "PROCEDURE_CAT", "PROCEDURE_SCHEM",
1354: "PROCEDURE_NAME", "COLUMN_NAME", "COLUMN_TYPE",
1355: "DATA_TYPE", "TYPE_NAME", "PRECISION", "LENGTH",
1356: "SCALE", "RADIX", "NULLABLE", "REMARKS" };
1357: int colTypes[] = { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1358: Types.VARCHAR, Types.SMALLINT, Types.INTEGER,
1359: Types.VARCHAR, Types.INTEGER, Types.INTEGER,
1360: Types.SMALLINT, Types.SMALLINT, Types.SMALLINT,
1361: Types.VARCHAR };
1362:
1363: String query = "sp_sproc_columns ?, ?, ?, ?, ?";
1364:
1365: CallableStatement s = connection.prepareCall(syscall(catalog,
1366: query));
1367:
1368: s.setString(1, processEscapes(procedureNamePattern));
1369: s.setString(2, processEscapes(schemaPattern));
1370: s.setString(3, catalog);
1371: s.setString(4, processEscapes(columnNamePattern));
1372: s.setInt(5, 3); // ODBC version 3
1373:
1374: JtdsResultSet rs = (JtdsResultSet) s.executeQuery();
1375: ResultSetMetaData rsmd = rs.getMetaData();
1376: CachedResultSet rsTmp = new CachedResultSet((JtdsStatement) s,
1377: colNames, colTypes);
1378: rsTmp.moveToInsertRow();
1379: while (rs.next()) {
1380: int offset = 0;
1381: for (int i = 1; i + offset <= colNames.length; i++) {
1382: if (i == 5
1383: && !"column_type".equalsIgnoreCase(rsmd
1384: .getColumnName(i))) {
1385: // With Sybase 11.92 despite what the documentation says, the
1386: // column_type column is missing!
1387: // Set the output value to 0 and shift the rest along by one.
1388: String colName = rs.getString(4);
1389: if ("RETURN_VALUE".equals(colName)) {
1390: rsTmp.updateInt(i,
1391: DatabaseMetaData.procedureColumnReturn);
1392: } else {
1393: rsTmp
1394: .updateInt(
1395: i,
1396: DatabaseMetaData.procedureColumnUnknown);
1397: }
1398: offset = 1;
1399: }
1400: if (i == 3) {
1401: String name = rs.getString(i);
1402: if (name != null && name.length() > 0) {
1403: int pos = name.lastIndexOf(';');
1404: if (pos >= 0) {
1405: name = name.substring(0, pos);
1406: }
1407: }
1408: rsTmp.updateString(i + offset, name);
1409: } else if ("data_type".equalsIgnoreCase(rsmd
1410: .getColumnName(i))) {
1411: int type = TypeInfo.normalizeDataType(rs.getInt(i),
1412: connection.getUseLOBs());
1413: rsTmp.updateInt(i + offset, type);
1414: } else {
1415: rsTmp.updateObject(i + offset, rs.getObject(i));
1416: }
1417: }
1418: if (serverType == Driver.SYBASE
1419: && rsmd.getColumnCount() >= 22) {
1420: //
1421: // For Sybase 12.5+ we can obtain column in/out status from
1422: // the mode column.
1423: //
1424: String mode = rs.getString(22);
1425: if (mode != null) {
1426: if (mode.equalsIgnoreCase("in")) {
1427: rsTmp.updateInt(5,
1428: DatabaseMetaData.procedureColumnIn);
1429: } else if (mode.equalsIgnoreCase("out")) {
1430: rsTmp.updateInt(5,
1431: DatabaseMetaData.procedureColumnInOut);
1432: }
1433: }
1434: }
1435: if (serverType == Driver.SYBASE
1436: || tdsVersion == Driver.TDS42
1437: || tdsVersion == Driver.TDS70) {
1438: //
1439: // Standardise the name of the return_value column as
1440: // @RETURN_VALUE for Sybase and SQL < 2000
1441: //
1442: String colName = rs.getString(4);
1443: if ("RETURN_VALUE".equals(colName)) {
1444: rsTmp.updateString(4, "@RETURN_VALUE");
1445: }
1446: }
1447: rsTmp.insertRow();
1448: }
1449: rs.close();
1450: rsTmp.moveToCurrentRow();
1451: rsTmp.setConcurrency(ResultSet.CONCUR_READ_ONLY);
1452: return rsTmp;
1453: }
1454:
1455: /**
1456: * Get a description of stored procedures available in a catalog. <P>
1457: *
1458: * Only procedure descriptions matching the schema and procedure name
1459: * criteria are returned. They are ordered by PROCEDURE_SCHEM, and
1460: * PROCEDURE_NAME. <P>
1461: *
1462: * Each procedure description has the the following columns:
1463: * <OL>
1464: * <LI> <B>PROCEDURE_CAT</B> String =>procedure catalog (may be null)
1465: *
1466: * <LI> <B>PROCEDURE_SCHEM</B> String =>procedure schema (may be null)
1467: *
1468: * <LI> <B>PROCEDURE_NAME</B> String =>procedure name
1469: * <LI> reserved for future use
1470: * <LI> reserved for future use
1471: * <LI> reserved for future use
1472: * <LI> <B>REMARKS</B> String =>explanatory comment on the procedure
1473: * <LI> <B>PROCEDURE_TYPE</B> short =>kind of procedure:
1474: * <UL>
1475: * <LI> procedureResultUnknown - May return a result
1476: * <LI> procedureNoResult - Does not return a result
1477: * <LI> procedureReturnsResult - Returns a result
1478: * </UL>
1479: * </OL>
1480: *
1481: * @param catalog a catalog name; "" retrieves those without a
1482: * <code>null</code> means drop catalog name from the selection criteria
1483: * @param schemaPattern a schema name pattern; "" retrieves those
1484: * without a schema
1485: * @param procedureNamePattern a procedure name pattern
1486: * @return ResultSet - each row is a procedure description
1487: * @throws SQLException if a database-access error occurs.
1488: *
1489: * @see #getSearchStringEscape
1490: */
1491: public java.sql.ResultSet getProcedures(String catalog,
1492: String schemaPattern, String procedureNamePattern)
1493: throws SQLException {
1494: String colNames[] = { "PROCEDURE_CAT", "PROCEDURE_SCHEM",
1495: "PROCEDURE_NAME", "RESERVED_1", "RESERVED_2",
1496: "RESERVED_3", "REMARKS", "PROCEDURE_TYPE" };
1497: int colTypes[] = { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1498: Types.INTEGER, Types.INTEGER, Types.INTEGER,
1499: Types.VARCHAR, Types.SMALLINT };
1500:
1501: String query = "sp_stored_procedures ?, ?, ?";
1502:
1503: CallableStatement s = connection.prepareCall(syscall(catalog,
1504: query));
1505:
1506: s.setString(1, processEscapes(procedureNamePattern));
1507: s.setString(2, processEscapes(schemaPattern));
1508: s.setString(3, catalog);
1509:
1510: JtdsResultSet rs = (JtdsResultSet) s.executeQuery();
1511:
1512: CachedResultSet rsTmp = new CachedResultSet((JtdsStatement) s,
1513: colNames, colTypes);
1514: rsTmp.moveToInsertRow();
1515: int colCnt = rs.getMetaData().getColumnCount();
1516: //
1517: // Copy results to local result set.
1518: //
1519: while (rs.next()) {
1520: rsTmp.updateString(1, rs.getString(1));
1521: rsTmp.updateString(2, rs.getString(2));
1522: String name = rs.getString(3);
1523: if (name != null) {
1524: // Remove grouping integer
1525: if (name.endsWith(";1")) {
1526: name = name.substring(0, name.length() - 2);
1527: }
1528: }
1529: rsTmp.updateString(3, name);
1530: // Copy over rest of fields
1531: for (int i = 4; i <= colCnt; i++) {
1532: rsTmp.updateObject(i, rs.getObject(i));
1533: }
1534: if (colCnt < 8) {
1535: // Sybase does not return this column so fake it now.
1536: rsTmp
1537: .updateShort(
1538: 8,
1539: (short) DatabaseMetaData.procedureReturnsResult);
1540: }
1541: rsTmp.insertRow();
1542: }
1543: rsTmp.moveToCurrentRow();
1544: rsTmp.setConcurrency(ResultSet.CONCUR_READ_ONLY);
1545: rs.close();
1546: return rsTmp;
1547: }
1548:
1549: /**
1550: * What's the database vendor's preferred term for "procedure"?
1551: *
1552: * @return the vendor term
1553: * @throws SQLException if a database-access error occurs.
1554: */
1555: public String getProcedureTerm() throws SQLException {
1556: // per "Programming ODBC for SQLServer" Appendix A
1557: return "stored procedure";
1558: }
1559:
1560: /**
1561: * Get the schema names available in this database. The results are ordered
1562: * by schema name. <P>
1563: *
1564: * The schema column is:
1565: * <OL>
1566: * <LI> <B>TABLE_SCHEM</B> String => schema name
1567: * <LI> <B>TABLE_CATALOG</B> String => catalog name (may be <code>null</code>, JDBC 3.0)
1568: * </OL>
1569: *
1570: * @return a <code>ResultSet</code> object in which each row is a schema decription
1571: * @throws SQLException if a database access error occurs
1572: */
1573: public java.sql.ResultSet getSchemas() throws SQLException {
1574: java.sql.Statement statement = connection.createStatement();
1575:
1576: String sql = Driver.JDBC3 ? "SELECT name AS TABLE_SCHEM, NULL as TABLE_CATALOG FROM dbo.sysusers"
1577: : "SELECT name AS TABLE_SCHEM FROM dbo.sysusers";
1578:
1579: //
1580: // MJH - isLogin column only in MSSQL >= 7.0
1581: //
1582: if (tdsVersion >= Driver.TDS70) {
1583: sql += " WHERE islogin=1";
1584: } else {
1585: sql += " WHERE uid>0";
1586: }
1587:
1588: sql += " ORDER BY TABLE_SCHEM";
1589:
1590: return statement.executeQuery(sql);
1591: }
1592:
1593: /**
1594: * What's the database vendor's preferred term for "schema"?
1595: *
1596: * @return the vendor term
1597: * @throws SQLException if a database-access error occurs.
1598: */
1599: public String getSchemaTerm() throws SQLException {
1600: return "owner";
1601: }
1602:
1603: /**
1604: * This is the string that can be used to escape '_' or '%' in the string
1605: * pattern style catalog search parameters. <P>
1606: *
1607: * The '_' character represents any single character. <P>
1608: *
1609: * The '%' character represents any sequence of zero or more characters.
1610: *
1611: * @return the string used to escape wildcard characters
1612: * @throws SQLException if a database-access error occurs.
1613: */
1614: public String getSearchStringEscape() throws SQLException {
1615: // per "Programming ODBC for SQLServer" Appendix A
1616: return "\\";
1617: }
1618:
1619: /**
1620: * Get a comma separated list of all a database's SQL keywords that are NOT
1621: * also SQL92 keywords.
1622: *
1623: * @return the list
1624: * @throws SQLException if a database-access error occurs.
1625: */
1626: public String getSQLKeywords() throws SQLException {
1627: //
1628: // This is a superset of the SQL keywords in SQL Server and Sybase
1629: //
1630: return "ARITH_OVERFLOW,BREAK,BROWSE,BULK,CHAR_CONVERT,CHECKPOINT,"
1631: + "CLUSTERED,COMPUTE,CONFIRM,CONTROLROW,DATA_PGS,DATABASE,DBCC,"
1632: + "DISK,DUMMY,DUMP,ENDTRAN,ERRLVL,ERRORDATA,ERROREXIT,EXIT,"
1633: + "FILLFACTOR,HOLDLOCK,IDENTITY_INSERT,IF,INDEX,KILL,LINENO,"
1634: + "LOAD,MAX_ROWS_PER_PAGE,MIRROR,MIRROREXIT,NOHOLDLOCK,NONCLUSTERED,"
1635: + "NUMERIC_TRUNCATION,OFF,OFFSETS,ONCE,ONLINE,OVER,PARTITION,PERM,"
1636: + "PERMANENT,PLAN,PRINT,PROC,PROCESSEXIT,RAISERROR,READ,READTEXT,"
1637: + "RECONFIGURE,REPLACE,RESERVED_PGS,RETURN,ROLE,ROWCNT,ROWCOUNT,"
1638: + "RULE,SAVE,SETUSER,SHARED,SHUTDOWN,SOME,STATISTICS,STRIPE,"
1639: + "SYB_IDENTITY,SYB_RESTREE,SYB_TERMINATE,TEMP,TEXTSIZE,TRAN,"
1640: + "TRIGGER,TRUNCATE,TSEQUAL,UNPARTITION,USE,USED_PGS,USER_OPTION,"
1641: + "WAITFOR,WHILE,WRITETEXT";
1642: }
1643:
1644: /**
1645: * Get a comma separated list of string functions.
1646: *
1647: * @return the list
1648: * @throws SQLException if a database-access error occurs.
1649: */
1650: public String getStringFunctions() throws SQLException {
1651: if (connection.getServerType() == Driver.SQLSERVER) {
1652: return "ascii,char,concat,difference,insert,lcase,left,length,locate,"
1653: + "ltrim,repeat,replace,right,rtrim,soundex,space,substring,ucase";
1654: } else {
1655: return "ascii,char,concat,difference,insert,lcase,length,"
1656: + "ltrim,repeat,right,rtrim,soundex,space,substring,ucase";
1657: }
1658: }
1659:
1660: /**
1661: * Get a comma separated list of system functions.
1662: *
1663: * @return the list
1664: * @throws SQLException if a database-access error occurs.
1665: */
1666: public String getSystemFunctions() throws SQLException {
1667: return "database,ifnull,user,convert";
1668: }
1669:
1670: /**
1671: * Get a description of the access rights for each table available in a
1672: * catalog. Note that a table privilege applies to one or more columns in
1673: * the table. It would be wrong to assume that this priviledge applies to
1674: * all columns (this may be true for some systems but is not true for all.)
1675: * <P>
1676: *
1677: * Only privileges matching the schema and table name criteria are
1678: * returned. They are ordered by TABLE_SCHEM, TABLE_NAME, and PRIVILEGE.
1679: * <P>
1680: *
1681: * Each privilige description has the following columns:
1682: * <OL>
1683: * <LI> <B>TABLE_CAT</B> String =>table catalog (may be null)
1684: * <LI> <B>TABLE_SCHEM</B> String =>table schema (may be null)
1685: * <LI> <B>TABLE_NAME</B> String =>table name
1686: * <LI> <B>GRANTOR</B> =>grantor of access (may be null)
1687: * <LI> <B>GRANTEE</B> String =>grantee of access
1688: * <LI> <B>PRIVILEGE</B> String =>name of access (SELECT, INSERT, UPDATE,
1689: * REFRENCES, ...)
1690: * <LI> <B>IS_GRANTABLE</B> String =>"YES" if grantee is permitted to
1691: * grant to others; "NO" if not; null if unknown
1692: * </OL>
1693: *
1694: * @param catalog a catalog name; "" retrieves those without a
1695: * <code>null</code> means drop catalog name from the selection criteria
1696: * @param schemaPattern a schema name pattern; "" retrieves those
1697: * without a schema
1698: * @param tableNamePattern a table name pattern
1699: * @return ResultSet - each row is a table privilege description
1700: * @throws SQLException if a database-access error occurs.
1701: *
1702: * @see #getSearchStringEscape
1703: */
1704: public java.sql.ResultSet getTablePrivileges(String catalog,
1705: String schemaPattern, String tableNamePattern)
1706: throws SQLException {
1707: String query = "sp_table_privileges ?, ?, ?";
1708:
1709: CallableStatement s = connection.prepareCall(syscall(catalog,
1710: query));
1711:
1712: s.setString(1, processEscapes(tableNamePattern));
1713: s.setString(2, processEscapes(schemaPattern));
1714: s.setString(3, catalog);
1715:
1716: JtdsResultSet rs = (JtdsResultSet) s.executeQuery();
1717:
1718: rs.setColLabel(1, "TABLE_CAT");
1719: rs.setColLabel(2, "TABLE_SCHEM");
1720:
1721: upperCaseColumnNames(rs);
1722:
1723: return rs;
1724: }
1725:
1726: /**
1727: * Get a description of tables available in a catalog. <P>
1728: *
1729: * Only table descriptions matching the catalog, schema, table name and
1730: * type criteria are returned. They are ordered by TABLE_TYPE, TABLE_SCHEM
1731: * and TABLE_NAME. <P>
1732: *
1733: * Each table description has the following columns:
1734: * <OL>
1735: * <LI> <B>TABLE_CAT</B> String =>table catalog (may be null)
1736: * <LI> <B>TABLE_SCHEM</B> String =>table schema (may be null)
1737: * <LI> <B>TABLE_NAME</B> String =>table name
1738: * <LI> <B>TABLE_TYPE</B> String =>table type. Typical types are "TABLE",
1739: * "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY",
1740: * "ALIAS", "SYNONYM".
1741: * <LI> <B>REMARKS</B> String =>explanatory comment on the table
1742: * <LI> <B>TYPE_CAT</B> String => the types catalog (may be
1743: * <code>null</code>)
1744: * <LI> <B>TYPE_SCHEM</B> String => the types schema (may be
1745: * <code>null</code>)
1746: * <LI> <B>TYPE_NAME</B> String => type name (may be <code>null</code>)
1747: * <LI> <B>SELF_REFERENCING_COL_NAME</B> String => name of the designated
1748: * "identifier" column of a typed table (may be <code>null</code>)
1749: * <LI> <B>REF_GENERATION</B> String => specifies how values in
1750: * SELF_REFERENCING_COL_NAME are created. Values are "SYSTEM", "USER",
1751: * "DERIVED". (may be <code>null</code>)
1752: * </OL>
1753: * <P>
1754: *
1755: * <B>Note:</B> Some databases may not return information for all tables.
1756: *
1757: * @param catalog a catalog name; "" retrieves those without a
1758: * <code>null</code> means drop catalog name from the selection criteria
1759: * @param schemaPattern a schema name pattern; "" retrieves those
1760: * without a schema
1761: * @param tableNamePattern a table name pattern
1762: * @param types a list of table types to include; null returns all types
1763: * @return ResultSet - each row is a table description
1764: * @throws SQLException if a database-access error occurs.
1765: *
1766: * @see #getSearchStringEscape
1767: */
1768: public java.sql.ResultSet getTables(String catalog,
1769: String schemaPattern, String tableNamePattern,
1770: String types[]) throws SQLException {
1771: String colNames[] = { "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME",
1772: "TABLE_TYPE", "REMARKS", "TYPE_CAT", "TYPE_SCHEM",
1773: "TYPE_NAME", "SELF_REFERENCING_COL_NAME",
1774: "REF_GENERATION" };
1775: int colTypes[] = { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1776: Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1777: Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1778: Types.VARCHAR };
1779: String query = "sp_tables ?, ?, ?, ?";
1780:
1781: CallableStatement cstmt = connection.prepareCall(syscall(
1782: catalog, query));
1783:
1784: cstmt.setString(1, processEscapes(tableNamePattern));
1785: cstmt.setString(2, processEscapes(schemaPattern));
1786: cstmt.setString(3, catalog);
1787:
1788: if (types == null) {
1789: cstmt.setString(4, null);
1790: } else {
1791: StringBuffer buf = new StringBuffer(64);
1792:
1793: buf.append('"');
1794:
1795: for (int i = 0; i < types.length; i++) {
1796: buf.append('\'').append(types[i]).append("',");
1797: }
1798:
1799: if (buf.length() > 1) {
1800: buf.setLength(buf.length() - 1);
1801: }
1802:
1803: buf.append('"');
1804: cstmt.setString(4, buf.toString());
1805: }
1806:
1807: JtdsResultSet rs = (JtdsResultSet) cstmt.executeQuery();
1808: CachedResultSet rsTmp = new CachedResultSet(
1809: (JtdsStatement) cstmt, colNames, colTypes);
1810: rsTmp.moveToInsertRow();
1811: int colCnt = rs.getMetaData().getColumnCount();
1812: //
1813: // Copy results to local result set.
1814: //
1815: while (rs.next()) {
1816: for (int i = 1; i <= colCnt; i++) {
1817: rsTmp.updateObject(i, rs.getObject(i));
1818: }
1819: rsTmp.insertRow();
1820: }
1821: rsTmp.moveToCurrentRow();
1822: rsTmp.setConcurrency(ResultSet.CONCUR_READ_ONLY);
1823: rs.close();
1824: return rsTmp;
1825: }
1826:
1827: /**
1828: * Get the table types available in this database. The results are ordered
1829: * by table type. <P>
1830: *
1831: * The table type is:
1832: * <OL>
1833: * <LI> <B>TABLE_TYPE</B> String => table type. Typical types are "TABLE",
1834: * "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY",
1835: * "ALIAS", "SYNONYM".
1836: * </OL>
1837: *
1838: * @return ResultSet - each row has a single String column that is a table type
1839: * @throws SQLException if a database-access error occurs.
1840: */
1841: public java.sql.ResultSet getTableTypes() throws SQLException {
1842: String sql = "select 'SYSTEM TABLE' TABLE_TYPE "
1843: + "union select 'TABLE' TABLE_TYPE "
1844: + "union select 'VIEW' TABLE_TYPE "
1845: + "order by TABLE_TYPE";
1846: java.sql.Statement stmt = connection.createStatement();
1847:
1848: return stmt.executeQuery(sql);
1849: }
1850:
1851: /**
1852: * Get a comma separated list of time and date functions.
1853: *
1854: * @return the list
1855: * @throws SQLException if a database-access error occurs.
1856: */
1857: public String getTimeDateFunctions() throws SQLException {
1858: return "curdate,curtime,dayname,dayofmonth,dayofweek,dayofyear,hour,"
1859: + "minute,month,monthname,now,quarter,timestampadd,timestampdiff,"
1860: + "second,week,year";
1861: }
1862:
1863: /**
1864: * Get a description of all the standard SQL types supported by this
1865: * database. They are ordered by DATA_TYPE and then by how closely the data
1866: * type maps to the corresponding JDBC SQL type. <P>
1867: *
1868: * Each type description has the following columns:
1869: * <OL>
1870: * <LI> <B>TYPE_NAME</B> String =>Type name
1871: * <LI> <B>DATA_TYPE</B> short =>SQL data type from java.sql.Types
1872: * <LI> <B>PRECISION</B> int =>maximum precision
1873: * <LI> <B>LITERAL_PREFIX</B> String =>prefix used to quote a literal
1874: * (may be null)
1875: * <LI> <B>LITERAL_SUFFIX</B> String =>suffix used to quote a literal
1876: * (may be null)
1877: * <LI> <B>CREATE_PARAMS</B> String =>parameters used in creating the
1878: * type (may be null)
1879: * <LI> <B>NULLABLE</B> short =>can you use NULL for this type?
1880: * <UL>
1881: * <LI> typeNoNulls - does not allow NULL values
1882: * <LI> typeNullable - allows NULL values
1883: * <LI> typeNullableUnknown - nullability unknown
1884: * </UL>
1885: *
1886: * <LI> <B>CASE_SENSITIVE</B> boolean=>is it case sensitive?
1887: * <LI> <B>SEARCHABLE</B> short =>can you use "WHERE" based on this type:
1888: *
1889: * <UL>
1890: * <LI> typePredNone - No support
1891: * <LI> typePredChar - Only supported with WHERE .. LIKE
1892: * <LI> typePredBasic - Supported except for WHERE .. LIKE
1893: * <LI> typeSearchable - Supported for all WHERE ..
1894: * </UL>
1895: *
1896: * <LI> <B>UNSIGNED_ATTRIBUTE</B> boolean =>is it unsigned?
1897: * <LI> <B>FIXED_PREC_SCALE</B> boolean =>can it be a money value?
1898: * <LI> <B>AUTO_INCREMENT</B> boolean =>can it be used for an
1899: * auto-increment value?
1900: * <LI> <B>LOCAL_TYPE_NAME</B> String =>localized version of type name
1901: * (may be null)
1902: * <LI> <B>MINIMUM_SCALE</B> short =>minimum scale supported
1903: * <LI> <B>MAXIMUM_SCALE</B> short =>maximum scale supported
1904: * <LI> <B>SQL_DATA_TYPE</B> int =>unused
1905: * <LI> <B>SQL_DATETIME_SUB</B> int =>unused
1906: * <LI> <B>NUM_PREC_RADIX</B> int =>usually 2 or 10
1907: * </OL>
1908: *
1909: * @return ResultSet - each row is a SQL type description
1910: * @throws SQLException if a database-access error occurs.
1911: */
1912: public java.sql.ResultSet getTypeInfo() throws SQLException {
1913: Statement s = connection.createStatement();
1914: JtdsResultSet rs;
1915:
1916: try {
1917: rs = (JtdsResultSet) s
1918: .executeQuery("exec sp_datatype_info @ODBCVer=3");
1919: } catch (SQLException ex) {
1920: s.close();
1921: throw ex;
1922: }
1923:
1924: try {
1925: return createTypeInfoResultSet(rs, connection.getUseLOBs());
1926: } finally {
1927: // CachedResultSet retains reference to same statement as rs, so don't close statement
1928: rs.close();
1929: }
1930: }
1931:
1932: /**
1933: * JDBC 2.0 Gets a description of the user-defined types defined in a
1934: * particular schema. Schema-specific UDTs may have type JAVA_OBJECT,
1935: * STRUCT, or DISTINCT. <P>
1936: *
1937: * Only types matching the catalog, schema, type name and type criteria are
1938: * returned. They are ordered by DATA_TYPE, TYPE_SCHEM and TYPE_NAME. The
1939: * type name parameter may be a fully-qualified name. In this case, the
1940: * catalog and schemaPattern parameters are ignored. <P>
1941: *
1942: * Each type description has the following columns:
1943: * <OL>
1944: * <LI> <B>TYPE_CAT</B> String =>the type's catalog (may be null)
1945: * <LI> <B>TYPE_SCHEM</B> String =>type's schema (may be null)
1946: * <LI> <B>TYPE_NAME</B> String =>type name
1947: * <LI> <B>CLASS_NAME</B> String =>Java class name
1948: * <LI> <B>DATA_TYPE</B> String =>type value defined in java.sql.Types.
1949: * One of JAVA_OBJECT, STRUCT, or DISTINCT
1950: * <LI> <B>REMARKS</B> String =>explanatory comment on the type
1951: * </OL>
1952: * <P>
1953: *
1954: * <B>Note:</B> If the driver does not support UDTs, an empty result set is
1955: * returned.
1956: *
1957: * @param catalog a catalog name; "" retrieves those without a
1958: * <code>null</code> means drop catalog name from the selection criteria
1959: * @param schemaPattern a schema name pattern; "" retrieves those
1960: * without a schema
1961: * @param typeNamePattern a type name pattern; may be a fully-qualified
1962: * name
1963: * @param types a list of user-named types to include
1964: * (JAVA_OBJECT, STRUCT, or DISTINCT); null returns all types
1965: * @return ResultSet - each row is a type description
1966: * @throws SQLException if a database access error occurs
1967: */
1968: public java.sql.ResultSet getUDTs(String catalog,
1969: String schemaPattern, String typeNamePattern, int[] types)
1970: throws SQLException {
1971: String colNames[] = { "TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME",
1972: "CLASS_NAME", "DATA_TYPE", "REMARKS", "BASE_TYPE" };
1973: int colTypes[] = { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1974: Types.VARCHAR, Types.INTEGER, Types.VARCHAR,
1975: Types.SMALLINT };
1976: //
1977: // Return an empty result set
1978: //
1979: JtdsStatement dummyStmt = (JtdsStatement) connection
1980: .createStatement();
1981: CachedResultSet rs = new CachedResultSet(dummyStmt, colNames,
1982: colTypes);
1983: rs.setConcurrency(ResultSet.CONCUR_READ_ONLY);
1984: return rs;
1985: }
1986:
1987: /**
1988: * What's the URL for this database?
1989: *
1990: * @return the URL or null if it can't be generated
1991: * @throws SQLException if a database-access error occurs
1992: */
1993: public String getURL() throws SQLException {
1994: return connection.getURL();
1995: }
1996:
1997: /**
1998: * What's our user name as known to the database?
1999: *
2000: * @return our database user name
2001: * @throws SQLException if a database-access error occurs.
2002: */
2003: public String getUserName() throws SQLException {
2004: java.sql.Statement s = null;
2005: java.sql.ResultSet rs = null;
2006: String result = "";
2007:
2008: try {
2009: s = connection.createStatement();
2010:
2011: // MJH Sybase does not support system_user
2012: if (connection.getServerType() == Driver.SYBASE) {
2013: rs = s.executeQuery("select suser_name()");
2014: } else {
2015: rs = s.executeQuery("select system_user");
2016: }
2017:
2018: if (!rs.next()) {
2019: throw new SQLException(Messages
2020: .get("error.dbmeta.nouser"), "HY000");
2021: }
2022:
2023: result = rs.getString(1);
2024: } finally {
2025: if (rs != null) {
2026: rs.close();
2027: }
2028:
2029: if (s != null) {
2030: s.close();
2031: }
2032: }
2033: return result;
2034: }
2035:
2036: /**
2037: * Get a description of a table's columns that are automatically updated
2038: * when any value in a row is updated. They are unordered. <P>
2039: *
2040: * Each column description has the following columns:
2041: * <OL>
2042: * <LI> <B>SCOPE</B> short =>is not used
2043: * <LI> <B>COLUMN_NAME</B> String =>column name
2044: * <LI> <B>DATA_TYPE</B> short =>SQL data type from java.sql.Types
2045: * <LI> <B>TYPE_NAME</B> String =>Data source dependent type name
2046: * <LI> <B>COLUMN_SIZE</B> int =>precision
2047: * <LI> <B>BUFFER_LENGTH</B> int =>length of column value in bytes
2048: * <LI> <B>DECIMAL_DIGITS</B> short =>scale
2049: * <LI> <B>PSEUDO_COLUMN</B> short =>is this a pseudo column like an
2050: * Oracle ROWID
2051: * <UL>
2052: * <LI> versionColumnUnknown - may or may not be pseudo column
2053: * <LI> versionColumnNotPseudo - is NOT a pseudo column
2054: * <LI> versionColumnPseudo - is a pseudo column
2055: * </UL>
2056: * </OL>
2057: *
2058: * @param catalog a catalog name; "" retrieves those without a
2059: * <code>null</code> means drop catalog name from the selection criteria
2060: * @param schema a schema name; "" retrieves those without a schema
2061: * @param table a table name
2062: * @return ResultSet - each row is a column description
2063: * @throws SQLException if a database-access error occurs.
2064: */
2065: public java.sql.ResultSet getVersionColumns(String catalog,
2066: String schema, String table) throws SQLException {
2067: String colNames[] = { "SCOPE", "COLUMN_NAME", "DATA_TYPE",
2068: "TYPE_NAME", "COLUMN_SIZE", "BUFFER_LENGTH",
2069: "DECIMAL_DIGITS", "PSEUDO_COLUMN" };
2070: int colTypes[] = { Types.SMALLINT, Types.VARCHAR,
2071: Types.INTEGER, Types.VARCHAR, Types.INTEGER,
2072: Types.INTEGER, Types.SMALLINT, Types.SMALLINT };
2073:
2074: String query = "sp_special_columns ?, ?, ?, ?, ?, ?, ?";
2075:
2076: CallableStatement s = connection.prepareCall(syscall(catalog,
2077: query));
2078:
2079: s.setString(1, table);
2080: s.setString(2, schema);
2081: s.setString(3, catalog);
2082: s.setString(4, "V");
2083: s.setString(5, "C");
2084: s.setString(6, "O");
2085: s.setInt(7, 3); // ODBC version 3
2086:
2087: JtdsResultSet rs = (JtdsResultSet) s.executeQuery();
2088: CachedResultSet rsTmp = new CachedResultSet((JtdsStatement) s,
2089: colNames, colTypes);
2090: rsTmp.moveToInsertRow();
2091: int colCnt = rs.getMetaData().getColumnCount();
2092: //
2093: // Copy results to local result set.
2094: //
2095: while (rs.next()) {
2096: for (int i = 1; i <= colCnt; i++) {
2097: rsTmp.updateObject(i, rs.getObject(i));
2098: }
2099: rsTmp.insertRow();
2100: }
2101: rsTmp.moveToCurrentRow();
2102: rsTmp.setConcurrency(ResultSet.CONCUR_READ_ONLY);
2103: rs.close();
2104: return rsTmp;
2105: }
2106:
2107: /**
2108: * Retrieves whether a catalog appears at the start of a fully qualified
2109: * table name. If not, the catalog appears at the end.
2110: *
2111: * @return true if it appears at the start
2112: * @throws SQLException if a database-access error occurs.
2113: */
2114: public boolean isCatalogAtStart() throws SQLException {
2115: return true;
2116: }
2117:
2118: /**
2119: * Is the database in read-only mode?
2120: *
2121: * @return <code>true</code> if so
2122: * @throws SQLException if a database-access error occurs.
2123: */
2124: public boolean isReadOnly() throws SQLException {
2125: return false;
2126: }
2127:
2128: /**
2129: * JDBC 2.0 Retrieves the connection that produced this metadata object.
2130: *
2131: * @return the connection that produced this metadata object
2132: * @throws SQLException if a database-access error occurs.
2133: */
2134: public java.sql.Connection getConnection() throws SQLException {
2135: return connection;
2136: }
2137:
2138: /**
2139: * Retrieves whether this database supports concatenations between
2140: * <code>NULL</code> and non-<code>NULL</code> values being
2141: * <code>NULL</code>.
2142: *
2143: * @return <code>true</code> if so
2144: * @throws SQLException if a database-access error occurs.
2145: */
2146: public boolean nullPlusNonNullIsNull() throws SQLException {
2147: // Sybase 11.92 says true
2148: // MS SQLServer seems to break with the SQL standard here.
2149: // maybe there is an option to make null behavior comply
2150: //
2151: // SAfe: Nope, it seems to work fine in SQL Server 7.0
2152: return true;
2153: }
2154:
2155: /**
2156: * Are NULL values sorted at the end regardless of sort order?
2157: *
2158: * @return <code>true</code> if so
2159: * @throws SQLException if a database-access error occurs.
2160: */
2161: public boolean nullsAreSortedAtEnd() throws SQLException {
2162: return false;
2163: }
2164:
2165: /**
2166: * Are NULL values sorted at the start regardless of sort order?
2167: *
2168: * @return <code>true</code> if so
2169: * @throws SQLException if a database-access error occurs.
2170: */
2171: public boolean nullsAreSortedAtStart() throws SQLException {
2172: return false;
2173: }
2174:
2175: /**
2176: * Are NULL values sorted high?
2177: *
2178: * @return <code>true</code> if so
2179: * @throws SQLException if a database-access error occurs.
2180: */
2181: public boolean nullsAreSortedHigh() throws SQLException {
2182: return false;
2183: }
2184:
2185: /**
2186: * Are NULL values sorted low?
2187: *
2188: * @return <code>true</code> if so
2189: * @throws SQLException if a database-access error occurs.
2190: */
2191: public boolean nullsAreSortedLow() throws SQLException {
2192: return true;
2193: }
2194:
2195: /**
2196: * Does the database treat mixed case unquoted SQL identifiers as case
2197: * insensitive and store them in lower case?
2198: *
2199: * @return <code>true</code> if so
2200: * @throws SQLException if a database-access error occurs.
2201: */
2202: public boolean storesLowerCaseIdentifiers() throws SQLException {
2203: return false;
2204: }
2205:
2206: /**
2207: * Does the database treat mixed case quoted SQL identifiers as case
2208: * insensitive and store them in lower case?
2209: *
2210: * @return <code>true</code> if so
2211: * @throws SQLException if a database-access error occurs.
2212: */
2213: public boolean storesLowerCaseQuotedIdentifiers()
2214: throws SQLException {
2215: return false;
2216: }
2217:
2218: /**
2219: * Does the database treat mixed case unquoted SQL identifiers as case
2220: * insensitive and store them in mixed case?
2221: *
2222: * @return <code>true</code> if so
2223: * @throws SQLException if a database-access error occurs.
2224: */
2225: public boolean storesMixedCaseIdentifiers() throws SQLException {
2226: setCaseSensitiveFlag();
2227:
2228: return !caseSensitive.booleanValue();
2229: }
2230:
2231: /**
2232: * Does the database treat mixed case quoted SQL identifiers as case
2233: * insensitive and store them in mixed case?
2234: *
2235: * @return <code>true</code> if so
2236: * @throws SQLException if a database-access error occurs.
2237: */
2238: public boolean storesMixedCaseQuotedIdentifiers()
2239: throws SQLException {
2240: setCaseSensitiveFlag();
2241:
2242: return !caseSensitive.booleanValue();
2243: }
2244:
2245: /**
2246: * Does the database treat mixed case unquoted SQL identifiers as case
2247: * insensitive and store them in upper case?
2248: *
2249: * @return <code>true</code> if so
2250: * @throws SQLException if a database-access error occurs.
2251: */
2252: public boolean storesUpperCaseIdentifiers() throws SQLException {
2253: return false;
2254: }
2255:
2256: /**
2257: * Does the database treat mixed case quoted SQL identifiers as case
2258: * insensitive and store them in upper case?
2259: *
2260: * @return <code>true</code> if so
2261: * @throws SQLException if a database-access error occurs.
2262: */
2263: public boolean storesUpperCaseQuotedIdentifiers()
2264: throws SQLException {
2265: return false;
2266: }
2267:
2268: //--------------------------------------------------------------------
2269: // Functions describing which features are supported.
2270:
2271: /**
2272: * Is "ALTER TABLE" with add column supported?
2273: *
2274: * @return <code>true</code> if so
2275: * @throws SQLException if a database-access error occurs.
2276: */
2277: public boolean supportsAlterTableWithAddColumn()
2278: throws SQLException {
2279: return true;
2280: }
2281:
2282: /**
2283: * Is "ALTER TABLE" with drop column supported?
2284: *
2285: * @return <code>true</code> if so
2286: * @throws SQLException if a database-access error occurs.
2287: */
2288: public boolean supportsAlterTableWithDropColumn()
2289: throws SQLException {
2290: return true;
2291: }
2292:
2293: /**
2294: * Retrieves whether this database supports the ANSI92 entry level SQL
2295: * grammar.
2296: *
2297: * @return <code>true</code> if so
2298: * @throws SQLException if a database-access error occurs.
2299: */
2300: public boolean supportsANSI92EntryLevelSQL() throws SQLException {
2301: return true;
2302: }
2303:
2304: /**
2305: * Is the ANSI92 full SQL grammar supported?
2306: *
2307: * @return <code>true</code> if so
2308: * @throws SQLException if a database-access error occurs.
2309: */
2310: public boolean supportsANSI92FullSQL() throws SQLException {
2311: return false;
2312: }
2313:
2314: /**
2315: * Is the ANSI92 intermediate SQL grammar supported?
2316: *
2317: * @return <code>true</code> if so
2318: * @throws SQLException if a database-access error occurs.
2319: */
2320: public boolean supportsANSI92IntermediateSQL() throws SQLException {
2321: return false;
2322: }
2323:
2324: /**
2325: * Can a catalog name be used in a data manipulation statement?
2326: *
2327: * @return <code>true</code> if so
2328: * @throws SQLException if a database-access error occurs.
2329: */
2330: public boolean supportsCatalogsInDataManipulation()
2331: throws SQLException {
2332: return true;
2333: }
2334:
2335: /**
2336: * Can a catalog name be used in an index definition statement?
2337: *
2338: * @return <code>true</code> if so
2339: * @throws SQLException if a database-access error occurs.
2340: */
2341: public boolean supportsCatalogsInIndexDefinitions()
2342: throws SQLException {
2343: return true;
2344: }
2345:
2346: /**
2347: * Can a catalog name be used in a privilege definition statement?
2348: *
2349: * @return <code>true</code> if so
2350: * @throws SQLException if a database-access error occurs.
2351: */
2352: public boolean supportsCatalogsInPrivilegeDefinitions()
2353: throws SQLException {
2354: return true;
2355: }
2356:
2357: /**
2358: * Can a catalog name be used in a procedure call statement?
2359: *
2360: * @return <code>true</code> if so
2361: * @throws SQLException if a database-access error occurs.
2362: */
2363: public boolean supportsCatalogsInProcedureCalls()
2364: throws SQLException {
2365: return true;
2366: }
2367:
2368: /**
2369: * Can a catalog name be used in a table definition statement?
2370: *
2371: * @return <code>true</code> if so
2372: * @throws SQLException if a database-access error occurs.
2373: */
2374: public boolean supportsCatalogsInTableDefinitions()
2375: throws SQLException {
2376: return true;
2377: }
2378:
2379: /**
2380: * Retrieves whether this database supports column aliasing.
2381: * <p>
2382: * If so, the SQL AS clause can be used to provide names for computed
2383: * columns or to provide alias names for columns as required. A
2384: * JDBC-Compliant driver always returns true.
2385: *
2386: * @return <code>true</code> if so
2387: * @throws SQLException if a database-access error occurs.
2388: */
2389: public boolean supportsColumnAliasing() throws SQLException {
2390: return true;
2391: }
2392:
2393: /**
2394: * Is the CONVERT function between SQL types supported?
2395: *
2396: * @return <code>true</code> if so
2397: * @throws SQLException if a database-access error occurs.
2398: */
2399: public boolean supportsConvert() throws SQLException {
2400: return true;
2401: }
2402:
2403: /**
2404: * Is CONVERT between the given SQL types supported?
2405: *
2406: * @param fromType the type to convert from
2407: * @param toType the type to convert to
2408: * @return <code>true</code> if so
2409: * @throws SQLException if a database-access error occurs.
2410: */
2411: public boolean supportsConvert(int fromType, int toType)
2412: throws SQLException {
2413: if (fromType == toType) {
2414: return true;
2415: }
2416:
2417: switch (fromType) {
2418: // SAfe Most types will convert to anything but IMAGE and
2419: // TEXT/NTEXT (and UNIQUEIDENTIFIER, but that's not a standard
2420: // type).
2421: case Types.BIT:
2422: case Types.TINYINT:
2423: case Types.SMALLINT:
2424: case Types.INTEGER:
2425: case Types.BIGINT:
2426: case Types.FLOAT:
2427: case Types.REAL:
2428: case Types.DOUBLE:
2429: case Types.NUMERIC:
2430: case Types.DECIMAL:
2431: case Types.DATE:
2432: case Types.TIME:
2433: case Types.TIMESTAMP:
2434: return toType != Types.LONGVARCHAR
2435: && toType != Types.LONGVARBINARY
2436: && toType != Types.BLOB && toType != Types.CLOB;
2437:
2438: case Types.BINARY:
2439: case Types.VARBINARY:
2440: return toType != Types.FLOAT && toType != Types.REAL
2441: && toType != Types.DOUBLE;
2442:
2443: // IMAGE
2444: case Types.BLOB:
2445: case Types.LONGVARBINARY:
2446: return toType == Types.BINARY || toType == Types.VARBINARY
2447: || toType == Types.BLOB
2448: || toType == Types.LONGVARBINARY;
2449:
2450: // TEXT and NTEXT
2451: case Types.CLOB:
2452: case Types.LONGVARCHAR:
2453: return toType == Types.CHAR || toType == Types.VARCHAR
2454: || toType == Types.CLOB
2455: || toType == Types.LONGVARCHAR;
2456:
2457: // These types can be converted to anything
2458: case Types.NULL:
2459: case Types.CHAR:
2460: case Types.VARCHAR:
2461: return true;
2462:
2463: // We can't tell for sure what will happen with other types, so...
2464: case Types.OTHER:
2465: default:
2466: return false;
2467: }
2468: }
2469:
2470: /**
2471: * Is the ODBC Core SQL grammar supported?
2472: *
2473: * @return <code>true</code> if so
2474: * @throws SQLException if a database-access error occurs.
2475: */
2476: public boolean supportsCoreSQLGrammar() throws SQLException {
2477: return true;
2478: }
2479:
2480: /**
2481: * Retrieves whether this database supports correlated subqueries.
2482: *
2483: * @return <code>true</code> if so
2484: * @throws SQLException if a database-access error occurs.
2485: */
2486: public boolean supportsCorrelatedSubqueries() throws SQLException {
2487: return true;
2488: }
2489:
2490: /**
2491: * Are both data definition and data manipulation statements within a
2492: * transaction supported?
2493: *
2494: * @return <code>true</code> if so
2495: * @throws SQLException if a database-access error occurs.
2496: */
2497: public boolean supportsDataDefinitionAndDataManipulationTransactions()
2498: throws SQLException {
2499: // Sybase requires the 'DDL IN TRAN' db option to be set for
2500: // This to be strictly true.
2501: return true;
2502: }
2503:
2504: /**
2505: * Are only data manipulation statements within a transaction supported?
2506: *
2507: * @return <code>true</code> if so
2508: * @throws SQLException if a database-access error occurs.
2509: */
2510: public boolean supportsDataManipulationTransactionsOnly()
2511: throws SQLException {
2512: return false;
2513: }
2514:
2515: /**
2516: * If table correlation names are supported, are they restricted to be
2517: * different from the names of the tables?
2518: *
2519: * @return <code>true</code> if so
2520: * @throws SQLException if a database-access error occurs.
2521: */
2522: public boolean supportsDifferentTableCorrelationNames()
2523: throws SQLException {
2524: return false;
2525: }
2526:
2527: /**
2528: * Are expressions in "ORDER BY" lists supported?
2529: *
2530: * @return <code>true</code> if so
2531: * @throws SQLException if a database-access error occurs.
2532: */
2533: public boolean supportsExpressionsInOrderBy() throws SQLException {
2534: return true;
2535: }
2536:
2537: /**
2538: * Is the ODBC Extended SQL grammar supported?
2539: *
2540: * @return <code>true</code> if so
2541: * @throws SQLException if a database-access error occurs.
2542: */
2543: public boolean supportsExtendedSQLGrammar() throws SQLException {
2544: return false;
2545: }
2546:
2547: /**
2548: * Are full nested outer joins supported?
2549: *
2550: * @return <code>true</code> if so
2551: * @throws SQLException if a database-access error occurs.
2552: */
2553: public boolean supportsFullOuterJoins() throws SQLException {
2554: if (connection.getServerType() == Driver.SYBASE) {
2555: // Supported since version 12
2556: return getDatabaseMajorVersion() >= 12;
2557: }
2558: return true;
2559: }
2560:
2561: /**
2562: * Is some form of "GROUP BY" clause supported?
2563: *
2564: * @return <code>true</code> if so
2565: * @throws SQLException if a database-access error occurs.
2566: */
2567: public boolean supportsGroupBy() throws SQLException {
2568: return true;
2569: }
2570:
2571: /**
2572: * Can a "GROUP BY" clause add columns not in the SELECT provided it
2573: * specifies all the columns in the SELECT?
2574: *
2575: * @return <code>true</code> if so
2576: * @throws SQLException if a database-access error occurs.
2577: */
2578: public boolean supportsGroupByBeyondSelect() throws SQLException {
2579: // per "Programming ODBC for SQLServer" Appendix A
2580: return true;
2581: }
2582:
2583: /**
2584: * Can a "GROUP BY" clause use columns not in the SELECT?
2585: *
2586: * @return <code>true</code> if so
2587: * @throws SQLException if a database-access error occurs.
2588: */
2589: public boolean supportsGroupByUnrelated() throws SQLException {
2590: return true;
2591: }
2592:
2593: /**
2594: * Is the SQL Integrity Enhancement Facility supported?
2595: *
2596: * @return <code>true</code> if so
2597: * @throws SQLException if a database-access error occurs.
2598: */
2599: public boolean supportsIntegrityEnhancementFacility()
2600: throws SQLException {
2601: return false;
2602: }
2603:
2604: /**
2605: * Retrieves whether this database supports specifying a <code>LIKE</code>
2606: * escape clause.
2607: *
2608: * @return <code>true</code> if so
2609: * @throws SQLException if a database-access error occurs.
2610: */
2611: public boolean supportsLikeEscapeClause() throws SQLException {
2612: // per "Programming ODBC for SQLServer" Appendix A
2613: return true;
2614: }
2615:
2616: /**
2617: * Retrieves whether this database provides limited support for outer
2618: * joins. (This will be <code>true</code> if the method
2619: * <code>supportsFullOuterJoins</code> returns <code>true</code>).
2620: *
2621: * @return <code>true</code> if so
2622: * @throws SQLException if a database-access error occurs.
2623: */
2624: public boolean supportsLimitedOuterJoins() throws SQLException {
2625: return true;
2626: }
2627:
2628: /**
2629: * Retrieves whether this database supports the ODBC Minimum SQL grammar.
2630: *
2631: * @return <code>true</code> if so
2632: * @throws SQLException if a database-access error occurs.
2633: */
2634: public boolean supportsMinimumSQLGrammar() throws SQLException {
2635: return true;
2636: }
2637:
2638: /**
2639: * Retrieves whether this database treats mixed case unquoted SQL identifiers as
2640: * case sensitive and as a result stores them in mixed case.
2641: *
2642: * @return <code>true</code> if so
2643: * @throws SQLException if a database-access error occurs.
2644: */
2645: public boolean supportsMixedCaseIdentifiers() throws SQLException {
2646: setCaseSensitiveFlag();
2647:
2648: return caseSensitive.booleanValue();
2649: }
2650:
2651: /**
2652: * Retrieves whether this database treats mixed case quoted SQL identifiers as
2653: * case sensitive and as a result stores them in mixed case.
2654: *
2655: * @return <code>true</code> if so
2656: * @throws SQLException if a database-access error occurs.
2657: */
2658: public boolean supportsMixedCaseQuotedIdentifiers()
2659: throws SQLException {
2660: setCaseSensitiveFlag();
2661:
2662: return caseSensitive.booleanValue();
2663: }
2664:
2665: /**
2666: * Are multiple ResultSets from a single execute supported?
2667: *
2668: * @return <code>true</code> if so
2669: * @throws SQLException if a database-access error occurs.
2670: */
2671: public boolean supportsMultipleResultSets() throws SQLException {
2672: return true;
2673: }
2674:
2675: /**
2676: * Can we have multiple transactions open at once (on different
2677: * connections)?
2678: *
2679: * @return <code>true</code> if so
2680: * @throws SQLException if a database-access error occurs.
2681: */
2682: public boolean supportsMultipleTransactions() throws SQLException {
2683: return true;
2684: }
2685:
2686: /**
2687: * Retrieves whether columns in this database may be defined as non-nullable.
2688: *
2689: * @return <code>true</code> if so
2690: * @throws SQLException if a database-access error occurs.
2691: */
2692: public boolean supportsNonNullableColumns() throws SQLException {
2693: return true;
2694: }
2695:
2696: /**
2697: * Can cursors remain open across commits?
2698: *
2699: * @return <code>true</code> if cursors always remain open;
2700: * <code>false</code> if they might not remain open
2701: * @throws SQLException if a database-access error occurs.
2702: */
2703: public boolean supportsOpenCursorsAcrossCommit()
2704: throws SQLException {
2705: // MS JDBC says false
2706: return true;
2707: }
2708:
2709: /**
2710: * Can cursors remain open across rollbacks?
2711: *
2712: * @return <code>true</code> if cursors always remain open;
2713: * <code>false</code> if they might not remain open
2714: * @throws SQLException if a database-access error occurs.
2715: */
2716: public boolean supportsOpenCursorsAcrossRollback()
2717: throws SQLException {
2718: // JConnect says true
2719: return connection.getServerType() == Driver.SYBASE;
2720: }
2721:
2722: /**
2723: * Can statements remain open across commits?
2724: *
2725: * @return <code>true</code> if statements always remain open;
2726: * <code>false</code> if they might not remain open
2727: * @throws SQLException if a database-access error occurs.
2728: */
2729: public boolean supportsOpenStatementsAcrossCommit()
2730: throws SQLException {
2731: return true;
2732: }
2733:
2734: /**
2735: * Can statements remain open across rollbacks?
2736: *
2737: * @return <code>true</code> if statements always remain open;
2738: * <code>false</code> if they might not remain open
2739: * @throws SQLException if a database-access error occurs.
2740: */
2741: public boolean supportsOpenStatementsAcrossRollback()
2742: throws SQLException {
2743: return true;
2744: }
2745:
2746: /**
2747: * Can an "ORDER BY" clause use columns not in the SELECT?
2748: *
2749: * @return <code>true</code> if so
2750: * @throws SQLException if a database-access error occurs.
2751: */
2752: public boolean supportsOrderByUnrelated() throws SQLException {
2753: return true;
2754: }
2755:
2756: /**
2757: * Is some form of outer join supported?
2758: *
2759: * @return <code>true</code> if so
2760: * @throws SQLException if a database-access error occurs.
2761: */
2762: public boolean supportsOuterJoins() throws SQLException {
2763: return true;
2764: }
2765:
2766: /**
2767: * Is positioned DELETE supported?
2768: *
2769: * @return <code>true</code> if so
2770: * @throws SQLException if a database-access error occurs.
2771: */
2772: public boolean supportsPositionedDelete() throws SQLException {
2773: return true;
2774: }
2775:
2776: /**
2777: * Is positioned UPDATE supported?
2778: *
2779: * @return <code>true</code> if so
2780: * @throws SQLException if a database-access error occurs.
2781: */
2782: public boolean supportsPositionedUpdate() throws SQLException {
2783: return true;
2784: }
2785:
2786: /**
2787: * Can a schema name be used in a data manipulation statement?
2788: *
2789: * @return <code>true</code> if so
2790: * @throws SQLException if a database-access error occurs.
2791: */
2792: public boolean supportsSchemasInDataManipulation()
2793: throws SQLException {
2794: return true;
2795: }
2796:
2797: /**
2798: * Can a schema name be used in an index definition statement?
2799: *
2800: * @return <code>true</code> if so
2801: * @throws SQLException if a database-access error occurs.
2802: */
2803: public boolean supportsSchemasInIndexDefinitions()
2804: throws SQLException {
2805: return true;
2806: }
2807:
2808: /**
2809: * Can a schema name be used in a privilege definition statement?
2810: *
2811: * @return <code>true</code> if so
2812: * @throws SQLException if a database-access error occurs.
2813: */
2814: public boolean supportsSchemasInPrivilegeDefinitions()
2815: throws SQLException {
2816: return true;
2817: }
2818:
2819: /**
2820: * Can a schema name be used in a procedure call statement?
2821: *
2822: * @return <code>true</code> if so
2823: * @throws SQLException if a database-access error occurs.
2824: */
2825: public boolean supportsSchemasInProcedureCalls()
2826: throws SQLException {
2827: return true;
2828: }
2829:
2830: /**
2831: * Can a schema name be used in a table definition statement?
2832: *
2833: * @return <code>true</code> if so
2834: * @throws SQLException if a database-access error occurs.
2835: */
2836: public boolean supportsSchemasInTableDefinitions()
2837: throws SQLException {
2838: return true;
2839: }
2840:
2841: /**
2842: * Is SELECT for UPDATE supported?
2843: *
2844: * @return <code>true</code> if so
2845: * @throws SQLException if a database-access error occurs.
2846: */
2847: public boolean supportsSelectForUpdate() throws SQLException {
2848: // XXX Server supports it driver doesn't currently
2849: // As far as I know the SQL Server FOR UPDATE is not the same as the
2850: // standard SQL FOR UPDATE
2851: return false;
2852: }
2853:
2854: /**
2855: * Are stored procedure calls using the stored procedure escape syntax
2856: * supported?
2857: *
2858: * @return <code>true</code> if so
2859: * @throws SQLException if a database-access error occurs.
2860: */
2861: public boolean supportsStoredProcedures() throws SQLException {
2862: return true;
2863: }
2864:
2865: /**
2866: * Retrieves whether this database supports subqueries in comparison
2867: * expressions.
2868: *
2869: * @return <code>true</code> if so
2870: * @throws SQLException if a database-access error occurs.
2871: */
2872: public boolean supportsSubqueriesInComparisons()
2873: throws SQLException {
2874: return true;
2875: }
2876:
2877: /**
2878: * Retrieves whether this database supports subqueries in
2879: * <code>EXISTS</code> expressions.
2880: *
2881: * @return <code>true</code> if so
2882: * @throws SQLException if a database-access error occurs.
2883: */
2884: public boolean supportsSubqueriesInExists() throws SQLException {
2885: return true;
2886: }
2887:
2888: /**
2889: * Retrieves whether this database supports subqueries in
2890: * <code>IN</code> statements.
2891: *
2892: * @return <code>true</code> if so
2893: * @throws SQLException if a database-access error occurs.
2894: */
2895: public boolean supportsSubqueriesInIns() throws SQLException {
2896: return true;
2897: }
2898:
2899: /**
2900: * Retrieves whether this database supports subqueries in quantified
2901: * expressions.
2902: *
2903: * @return <code>true</code> if so
2904: * @throws SQLException if a database-access error occurs.
2905: */
2906: public boolean supportsSubqueriesInQuantifieds()
2907: throws SQLException {
2908: return true;
2909: }
2910:
2911: /**
2912: * Retrieves whether this database supports table correlation names.
2913: *
2914: * @return <code>true</code> if so
2915: * @throws SQLException if a database-access error occurs.
2916: */
2917: public boolean supportsTableCorrelationNames() throws SQLException {
2918: return true;
2919: }
2920:
2921: /**
2922: * Does the database support the given transaction isolation level?
2923: *
2924: * @param level the values are defined in java.sql.Connection
2925: * @return <code>true</code> if so
2926: * @throws SQLException if a database-access error occurs.
2927: *
2928: * @see Connection
2929: */
2930: public boolean supportsTransactionIsolationLevel(int level)
2931: throws SQLException {
2932: switch (level) {
2933: case Connection.TRANSACTION_READ_UNCOMMITTED:
2934: case Connection.TRANSACTION_READ_COMMITTED:
2935: case Connection.TRANSACTION_REPEATABLE_READ:
2936: case Connection.TRANSACTION_SERIALIZABLE:
2937: return true;
2938:
2939: // TRANSACTION_NONE not supported. It means there is no support for
2940: // transactions
2941: case Connection.TRANSACTION_NONE:
2942: default:
2943: return false;
2944: }
2945: }
2946:
2947: /**
2948: * Retrieves whether this database supports transactions. If not, invoking the
2949: * method <code>commit</code> is a noop, and the isolation level is
2950: * <code>TRANSACTION_NONE</code>.
2951: *
2952: * @return <code>true</code> if transactions are supported
2953: * @throws SQLException if a database-access error occurs.
2954: */
2955: public boolean supportsTransactions() throws SQLException {
2956: return true;
2957: }
2958:
2959: /**
2960: * Is SQL UNION supported?
2961: *
2962: * @return <code>true</code> if so
2963: * @throws SQLException if a database-access error occurs.
2964: */
2965: public boolean supportsUnion() throws SQLException {
2966: return true;
2967: }
2968:
2969: /**
2970: * Is SQL UNION ALL supported?
2971: *
2972: * @return <code>true</code> if so
2973: * @throws SQLException if a database-access error occurs.
2974: */
2975: public boolean supportsUnionAll() throws SQLException {
2976: return true;
2977: }
2978:
2979: /**
2980: * Does the database use a file for each table?
2981: *
2982: * @return <code>true</code> if the database uses a local file for each
2983: * table
2984: * @throws SQLException if a database-access error occurs.
2985: */
2986: public boolean usesLocalFilePerTable() throws SQLException {
2987: return false;
2988: }
2989:
2990: /**
2991: * Does the database store tables in a local file?
2992: *
2993: * @return <code>true</code> if so
2994: * @throws SQLException if a database-access error occurs.
2995: */
2996: public boolean usesLocalFiles() throws SQLException {
2997: return false;
2998: }
2999:
3000: //--------------------------JDBC 2.0-----------------------------
3001:
3002: /**
3003: * Does the database support the given result set type?
3004: * <p/>
3005: * Supported types for SQL Server:
3006: * <table>
3007: * <tr>
3008: * <td valign="top">JDBC type</td>
3009: * <td valign="top">SQL Server cursor type</td>
3010: * <td valign="top">Server load</td>
3011: * <td valign="top">Description</td>
3012: * </tr>
3013: * <tr>
3014: * <td valign="top">TYPE_FORWARD_ONLY</td>
3015: * <td valign="top">Forward-only, dynamic (fast forward-only, static with <code>useCursors=true</code>)</td>
3016: * <td valign="top">Light</td>
3017: * <td valign="top">Fast, will read all data (less fast, doesn't read all data with <code>useCursors=true</code>). Forward only.</td>
3018: * </tr>
3019: * <tr>
3020: * <td valign="top">TYPE_SCROLL_INSENSITIVE</td>
3021: * <td valign="top">Static cursor</td>
3022: * <td valign="top">Heavy</td>
3023: * <td valign="top">Only use with CONCUR_READ_ONLY. SQL Server generates a temporary table, so changes made by others are not visible. Scrollable.</td>
3024: * </tr>
3025: * <tr>
3026: * <td valign="top">TYPE_SCROLL_SENSITIVE</td>
3027: * <td valign="top">Keyset cursor</td>
3028: * <td valign="top">Medium</td>
3029: * <td valign="top">Others' updates or deletes visible, but not others' inserts. Scrollable.</td>
3030: * </tr>
3031: * <tr>
3032: * <td valign="top">TYPE_SCROLL_SENSITIVE + 1</td>
3033: * <td valign="top">Dynamic cursor</td>
3034: * <td valign="top">Heavy</td>
3035: * <td valign="top">Others' updates, deletes and inserts visible. Scrollable.</td>
3036: * </tr>
3037: * </table>
3038: *
3039: * @param type defined in <code>java.sql.ResultSet</code>
3040: * @return <code>true</code> if so; <code>false</code> otherwise
3041: * @throws SQLException if a database access error occurs
3042: *
3043: * @see Connection
3044: * @see #supportsResultSetConcurrency
3045: */
3046: public boolean supportsResultSetType(int type) throws SQLException {
3047: // jTDS supports all standard ResultSet types plus
3048: // TYPE_SCROLL_SENSITIVE + 1
3049: return type >= ResultSet.TYPE_FORWARD_ONLY
3050: && type <= ResultSet.TYPE_SCROLL_SENSITIVE + 1;
3051: }
3052:
3053: /**
3054: * Does the database support the concurrency type in combination with the
3055: * given result set type?
3056: * <p/>
3057: * Supported concurrencies for SQL Server:
3058: * <table>
3059: * <tr>
3060: * <td>JDBC concurrency</td>
3061: * <td>SQL Server concurrency</td>
3062: * <td>Row locks</td>
3063: * <td>Description</td>
3064: * </tr>
3065: * <tr>
3066: * <td>CONCUR_READ_ONLY</td>
3067: * <td>Read only</td>
3068: * <td>No</td>
3069: * <td>Read-only.</td>
3070: * </tr>
3071: * <tr>
3072: * <td>CONCUR_UPDATABLE</td>
3073: * <td>Optimistic concurrency, updatable</td>
3074: * <td>No</td>
3075: * <td>Row integrity checked with timestamp comparison or, when not available, value comparison (except text and image fields).</td>
3076: * </tr>
3077: * <tr>
3078: * <td>CONCUR_UPDATABLE+1</td>
3079: * <td>Pessimistic concurrency, updatable</td>
3080: * <td>Yes</td>
3081: * <td>Row integrity is ensured by locking rows.</td>
3082: * </tr>
3083: * <tr>
3084: * <td>CONCUR_UPDATABLE+2</td>
3085: * <td>Optimistic concurrency, updatable</td>
3086: * <td>No</td>
3087: * <td>Row integrity checked with value comparison (except text and image fields).</td>
3088: * </tr>
3089: * </table>
3090: *
3091: * @param type defined in <code>java.sql.ResultSet</code>
3092: * @param concurrency type defined in <code>java.sql.ResultSet</code>
3093: * @return <code>true</code> if so; <code>false</code> otherwise
3094: * @throws SQLException if a database access error occurs
3095: *
3096: * @see Connection
3097: * @see #supportsResultSetType
3098: */
3099: public boolean supportsResultSetConcurrency(int type,
3100: int concurrency) throws SQLException {
3101: // jTDS supports both all standard ResultSet concurencies plus
3102: // CONCUR_UPDATABLE + 1 and CONCUR_UPDATABLE + 2, except the
3103: // TYPE_SCROLL_INSENSITIVE/CONCUR_UPDATABLE combination on SQL Server
3104: if (!supportsResultSetType(type)) {
3105: return false;
3106: }
3107:
3108: if (concurrency < ResultSet.CONCUR_READ_ONLY
3109: || concurrency > ResultSet.CONCUR_UPDATABLE + 2) {
3110: return false;
3111: }
3112:
3113: return type != ResultSet.TYPE_SCROLL_INSENSITIVE
3114: || concurrency == ResultSet.CONCUR_READ_ONLY;
3115: }
3116:
3117: /**
3118: * JDBC 2.0 Indicates whether a result set's own updates are visible.
3119: *
3120: * @param type <code>ResultSet</code> type
3121: * @return <code>true</code> if updates are visible for the
3122: * result set type; <code>false</code> otherwise
3123: * @throws SQLException if a database access error occurs
3124: */
3125: public boolean ownUpdatesAreVisible(int type) throws SQLException {
3126: return true;
3127: }
3128:
3129: /**
3130: * JDBC 2.0 Indicates whether a result set's own deletes are visible.
3131: *
3132: * @param type <code>ResultSet</code> type
3133: * @return <code>true</code> if deletes are visible for the
3134: * result set type; <code>false</code> otherwise
3135: * @throws SQLException if a database access error occurs
3136: */
3137: public boolean ownDeletesAreVisible(int type) throws SQLException {
3138: return true;
3139: }
3140:
3141: /**
3142: * JDBC 2.0 Indicates whether a result set's own inserts are visible.
3143: *
3144: * @param type <code>ResultSet</code> type
3145: * @return <code>true</code> if inserts are visible for the
3146: * result set type; <code>false</code> otherwise
3147: * @throws SQLException if a database access error occurs
3148: */
3149: public boolean ownInsertsAreVisible(int type) throws SQLException {
3150: return true;
3151: }
3152:
3153: /**
3154: * JDBC 2.0 Indicates whether updates made by others are visible.
3155: *
3156: * @param type <code>ResultSet</code> type
3157: * @return <code>true</code> if updates made by others are
3158: * visible for the result set type; <code>false</code> otherwise
3159: * @throws SQLException if a database access error occurs
3160: */
3161: public boolean othersUpdatesAreVisible(int type)
3162: throws SQLException {
3163: // Updates are visibile in scroll sensitive ResultSets
3164: return type >= ResultSet.TYPE_SCROLL_SENSITIVE;
3165: }
3166:
3167: /**
3168: * JDBC 2.0 Indicates whether deletes made by others are visible.
3169: *
3170: * @param type <code>ResultSet</code> type
3171: * @return <code>true</code> if deletes made by others are
3172: * visible for the result set type; <code>false</code> otherwise
3173: * @throws SQLException if a database access error occurs
3174: */
3175: public boolean othersDeletesAreVisible(int type)
3176: throws SQLException {
3177: // Deletes are visibile in scroll sensitive ResultSets
3178: return type >= ResultSet.TYPE_SCROLL_SENSITIVE;
3179: }
3180:
3181: /**
3182: * JDBC 2.0 Indicates whether inserts made by others are visible.
3183: *
3184: * @param type <code>ResultSet</code> type
3185: * @return <code>true</code> if inserts made by others are visible
3186: * for the result set type; <code>false</code> otherwise
3187: * @throws SQLException if a database access error occurs
3188: */
3189: public boolean othersInsertsAreVisible(int type)
3190: throws SQLException {
3191: // Inserts are only visibile with dynamic cursors
3192: return type == ResultSet.TYPE_SCROLL_SENSITIVE + 1;
3193: }
3194:
3195: /**
3196: * JDBC 2.0 Indicates whether or not a visible row update can be detected
3197: * by calling the method <code>ResultSet.rowUpdated</code> .
3198: *
3199: * @param type <code>ResultSet</code> type
3200: * @return <code>true</code> if changes are detected by the
3201: * result set type; <code>false</code> otherwise
3202: * @throws SQLException if a database access error occurs
3203: */
3204: public boolean updatesAreDetected(int type) throws SQLException {
3205: // Seems like there's no support for this in SQL Server
3206: return false;
3207: }
3208:
3209: /**
3210: * JDBC 2.0 Indicates whether or not a visible row delete can be detected
3211: * by calling ResultSet.rowDeleted(). If deletesAreDetected() returns
3212: * false, then deleted rows are removed from the result set.
3213: *
3214: * @param type <code>ResultSet</code> type
3215: * @return <code>true</code> if changes are detected by the result set type
3216: * @throws SQLException if a database access error occurs
3217: */
3218: public boolean deletesAreDetected(int type) throws SQLException {
3219: return true;
3220: }
3221:
3222: /**
3223: * JDBC 2.0 Indicates whether or not a visible row insert can be detected
3224: * by calling ResultSet.rowInserted().
3225: *
3226: * @param type <code>ResultSet</code> type
3227: * @return <code>true</code> if changes are detected by the result set type
3228: * @throws SQLException if a database access error occurs
3229: */
3230: public boolean insertsAreDetected(int type) throws SQLException {
3231: // Seems like there's no support for this in SQL Server
3232: return false;
3233: }
3234:
3235: /**
3236: * JDBC 2.0 Indicates whether the driver supports batch updates.
3237: *
3238: * @return <code>true</code> if the driver supports batch updates;
3239: * <code>false</code> otherwise
3240: * @throws SQLException if a database access error occurs
3241: */
3242: public boolean supportsBatchUpdates() throws SQLException {
3243: return true;
3244: }
3245:
3246: private void setCaseSensitiveFlag() throws SQLException {
3247: if (caseSensitive == null) {
3248: Statement s = connection.createStatement();
3249: ResultSet rs = s.executeQuery("sp_server_info 16");
3250:
3251: rs.next();
3252:
3253: caseSensitive = "MIXED".equalsIgnoreCase(rs.getString(3)) ? Boolean.FALSE
3254: : Boolean.TRUE;
3255: s.close();
3256: }
3257: }
3258:
3259: public java.sql.ResultSet getAttributes(String catalog,
3260: String schemaPattern, String typeNamePattern,
3261: String attributeNamePattern) throws SQLException {
3262: String colNames[] = { "TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME",
3263: "ATTR_NAME", "DATA_TYPE", "ATTR_TYPE_NAME",
3264: "ATTR_SIZE", "DECIMAL_DIGITS", "NUM_PREC_RADIX",
3265: "NULLABLE", "REMARKS", "ATTR_DEF", "SQL_DATA_TYPE",
3266: "SQL_DATETIME_SUB", "CHAR_OCTET_LENGTH",
3267: "ORDINAL_POSITION", "IS_NULLABLE", "SCOPE_CATALOG",
3268: "SCOPE_SCHEMA", "SCOPE_TABLE", "SOURCE_DATA_TYPE" };
3269: int colTypes[] = { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
3270: Types.VARCHAR, Types.INTEGER, Types.VARCHAR,
3271: Types.INTEGER, Types.INTEGER, Types.INTEGER,
3272: Types.INTEGER, Types.VARCHAR, Types.VARCHAR,
3273: Types.INTEGER, Types.INTEGER, Types.INTEGER,
3274: Types.INTEGER, Types.VARCHAR, Types.VARCHAR,
3275: Types.VARCHAR, Types.VARCHAR, Types.SMALLINT };
3276: //
3277: // Return an empty result set
3278: //
3279: JtdsStatement dummyStmt = (JtdsStatement) connection
3280: .createStatement();
3281: CachedResultSet rs = new CachedResultSet(dummyStmt, colNames,
3282: colTypes);
3283: rs.setConcurrency(ResultSet.CONCUR_READ_ONLY);
3284:
3285: return rs;
3286: }
3287:
3288: /**
3289: * Returns the database major version.
3290: */
3291: public int getDatabaseMajorVersion() throws SQLException {
3292: return connection.getDatabaseMajorVersion();
3293: }
3294:
3295: /**
3296: * Returns the database minor version.
3297: */
3298: public int getDatabaseMinorVersion() throws SQLException {
3299: return connection.getDatabaseMinorVersion();
3300: }
3301:
3302: /**
3303: * Returns the JDBC major version.
3304: */
3305: public int getJDBCMajorVersion() throws SQLException {
3306: return 3;
3307: }
3308:
3309: /**
3310: * Returns the JDBC minor version.
3311: */
3312: public int getJDBCMinorVersion() throws SQLException {
3313: return 0;
3314: }
3315:
3316: public int getResultSetHoldability() throws SQLException {
3317: return JtdsResultSet.HOLD_CURSORS_OVER_COMMIT;
3318: }
3319:
3320: public int getSQLStateType() throws SQLException {
3321: return sqlStateXOpen;
3322: }
3323:
3324: public java.sql.ResultSet getSuperTables(String catalog,
3325: String schemaPattern, String tableNamePattern)
3326: throws SQLException {
3327: String colNames[] = { "TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME",
3328: "SUPERTABLE_NAME" };
3329: int colTypes[] = { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
3330: Types.VARCHAR };
3331: //
3332: // Return an empty result set
3333: //
3334: JtdsStatement dummyStmt = (JtdsStatement) connection
3335: .createStatement();
3336: CachedResultSet rs = new CachedResultSet(dummyStmt, colNames,
3337: colTypes);
3338: rs.setConcurrency(ResultSet.CONCUR_READ_ONLY);
3339: return rs;
3340: }
3341:
3342: public java.sql.ResultSet getSuperTypes(String catalog,
3343: String schemaPattern, String typeNamePattern)
3344: throws SQLException {
3345: String colNames[] = { "TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME",
3346: "SUPERTYPE_CAT", "SUPERTYPE_SCHEM", "SUPERTYPE_NAME" };
3347: int colTypes[] = { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
3348: Types.VARCHAR, Types.VARCHAR, Types.VARCHAR };
3349: //
3350: // Return an empty result set
3351: //
3352: JtdsStatement dummyStmt = (JtdsStatement) connection
3353: .createStatement();
3354: CachedResultSet rs = new CachedResultSet(dummyStmt, colNames,
3355: colTypes);
3356: rs.setConcurrency(ResultSet.CONCUR_READ_ONLY);
3357: return rs;
3358: }
3359:
3360: /**
3361: * Returns <code>true</code> if updates are made to a copy of the LOB; returns
3362: * <code>false</code> if LOB updates are made directly to the database.
3363: * <p>
3364: * NOTE: Since SQL Server / Sybase do not support LOB locators as Oracle does (AFAIK);
3365: * this method always returns <code>true</code>.
3366: */
3367: public boolean locatorsUpdateCopy() throws SQLException {
3368: return true;
3369: }
3370:
3371: /**
3372: * Returns <code>true</code> if getting auto-generated keys is supported after a
3373: * statment is executed; returns <code>false</code> otherwise
3374: */
3375: public boolean supportsGetGeneratedKeys() throws SQLException {
3376: return true;
3377: }
3378:
3379: /**
3380: * Returns <code>true</code> if Callable statements can return multiple result sets;
3381: * returns <code>false</code> if they can only return one result set.
3382: */
3383: public boolean supportsMultipleOpenResults() throws SQLException {
3384: return true;
3385: }
3386:
3387: /**
3388: * Returns <code>true</code> if the database supports named parameters;
3389: * returns <code>false</code> if the database does not support named parameters.
3390: */
3391: public boolean supportsNamedParameters() throws SQLException {
3392: return true;
3393: }
3394:
3395: public boolean supportsResultSetHoldability(int param)
3396: throws SQLException {
3397: // Not really sure about this one!
3398: return false;
3399: }
3400:
3401: /**
3402: * Returns <code>true</code> if savepoints are supported; returns
3403: * <code>false</code> otherwise
3404: */
3405: public boolean supportsSavepoints() throws SQLException {
3406: return true;
3407: }
3408:
3409: /**
3410: * Returns <code>true</code> if the database supports statement pooling;
3411: * returns <code>false</code> otherwise.
3412: */
3413: public boolean supportsStatementPooling() throws SQLException {
3414: return true;
3415: }
3416:
3417: /**
3418: * Format the supplied search pattern to transform the escape \x into [x].
3419: *
3420: * @param pattern the pattern to tranform
3421: * @return the transformed pattern as a <code>String</code>
3422: */
3423: private static String processEscapes(String pattern) {
3424: final char escChar = '\\';
3425:
3426: if (pattern == null || pattern.indexOf(escChar) == -1) {
3427: return pattern;
3428: }
3429:
3430: int len = pattern.length();
3431: StringBuffer buf = new StringBuffer(len + 10);
3432:
3433: for (int i = 0; i < len; i++) {
3434: if (pattern.charAt(i) != escChar) {
3435: buf.append(pattern.charAt(i));
3436: } else if (i < len - 1) {
3437: buf.append('[');
3438: buf.append(pattern.charAt(++i));
3439: buf.append(']');
3440: } else {
3441: // Ignore final \
3442: }
3443:
3444: }
3445:
3446: return buf.toString();
3447: }
3448:
3449: /**
3450: * Format the supplied procedure call as a valid JDBC call escape.
3451: *
3452: * @param catalog the database name or null
3453: * @param call the stored procedure call to format
3454: * @return the formatted call escape as a <code>String</code>
3455: */
3456: private String syscall(String catalog, String call) {
3457: StringBuffer sql = new StringBuffer(30 + call.length());
3458: sql.append("{call ");
3459: if (catalog != null) {
3460: if (tdsVersion >= Driver.TDS70) {
3461: sql.append('[').append(catalog).append(']');
3462: } else {
3463: sql.append(catalog);
3464: }
3465: sql.append("..");
3466: }
3467: sql.append(call).append('}');
3468: return sql.toString();
3469: }
3470:
3471: /**
3472: * Uppercase all column names.
3473: * <p>
3474: * Sybase returns column names in lowecase while the JDBC standard suggests
3475: * they should be uppercase.
3476: *
3477: * @param results the result set to modify
3478: * @throws SQLException
3479: */
3480: private static void upperCaseColumnNames(JtdsResultSet results)
3481: throws SQLException {
3482: ResultSetMetaData rsmd = results.getMetaData();
3483: int cnt = rsmd.getColumnCount();
3484:
3485: for (int i = 1; i <= cnt; i++) {
3486: String name = rsmd.getColumnLabel(i);
3487: if (name != null && name.length() > 0) {
3488: results.setColLabel(i, name.toUpperCase());
3489: }
3490: }
3491: }
3492:
3493: private static CachedResultSet createTypeInfoResultSet(
3494: JtdsResultSet rs, boolean useLOBs) throws SQLException {
3495: CachedResultSet result = new CachedResultSet(rs, false);
3496: if (result.getMetaData().getColumnCount() > TypeInfo.NUM_COLS) {
3497: result.setColumnCount(TypeInfo.NUM_COLS);
3498: }
3499: result.setColLabel(3, "PRECISION");
3500: result.setColLabel(11, "FIXED_PREC_SCALE");
3501: upperCaseColumnNames(result);
3502: result.setConcurrency(ResultSet.CONCUR_UPDATABLE);
3503: result.moveToInsertRow();
3504:
3505: for (Iterator iter = getSortedTypes(rs, useLOBs).iterator(); iter
3506: .hasNext();) {
3507: TypeInfo ti = (TypeInfo) iter.next();
3508: ti.update(result);
3509: result.insertRow();
3510: }
3511:
3512: result.moveToCurrentRow();
3513: result.setConcurrency(ResultSet.CONCUR_READ_ONLY);
3514:
3515: return result;
3516: }
3517:
3518: private static Collection getSortedTypes(ResultSet rs,
3519: boolean useLOBs) throws SQLException {
3520: List types = new ArrayList(40); // 40 should be enough capacity to hold all types
3521:
3522: while (rs.next()) {
3523: types.add(new TypeInfo(rs, useLOBs));
3524: }
3525:
3526: Collections.sort(types);
3527:
3528: return types;
3529: }
3530: }
|