Source Code Cross Referenced for JtdsDatabaseMetaData.java in  » Database-JDBC-Connection-Pool » jTDS » net » sourceforge » jtds » jdbc » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database JDBC Connection Pool » jTDS » net.sourceforge.jtds.jdbc 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.