Source Code Cross Referenced for DatabaseMetaData.java in  » Database-JDBC-Connection-Pool » mysql-connector-java-5.1.3 » com » mysql » 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 » mysql connector java 5.1.3 » com.mysql.jdbc 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         Copyright (C) 2002-2007 MySQL AB
0003:
0004:         This program is free software; you can redistribute it and/or modify
0005:         it under the terms of version 2 of the GNU General Public License as 
0006:         published by the Free Software Foundation.
0007:
0008:         There are special exceptions to the terms and conditions of the GPL 
0009:         as it is applied to this software. View the full text of the 
0010:         exception in file EXCEPTIONS-CONNECTOR-J in the directory of this 
0011:         software distribution.
0012:
0013:         This program is distributed in the hope that it will be useful,
0014:         but WITHOUT ANY WARRANTY; without even the implied warranty of
0015:         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0016:         GNU General Public License for more details.
0017:
0018:         You should have received a copy of the GNU General Public License
0019:         along with this program; if not, write to the Free Software
0020:         Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0021:
0022:
0023:
0024:         */
0025:        package com.mysql.jdbc;
0026:
0027:        import java.io.UnsupportedEncodingException;
0028:        import java.lang.reflect.Constructor;
0029:        import java.lang.reflect.InvocationTargetException;
0030:
0031:        import java.sql.ResultSet;
0032:        import java.sql.SQLException;
0033:        import java.sql.Statement;
0034:        import java.sql.Types;
0035:
0036:        import java.util.ArrayList;
0037:        import java.util.Collections;
0038:        import java.util.HashMap;
0039:        import java.util.Iterator;
0040:        import java.util.List;
0041:        import java.util.Locale;
0042:        import java.util.Map;
0043:        import java.util.Properties;
0044:        import java.util.StringTokenizer;
0045:        import java.util.TreeMap;
0046:
0047:        /**
0048:         * JDBC Interface to Mysql functions
0049:         * <p>
0050:         * This class provides information about the database as a whole.
0051:         * </p>
0052:         * <p>
0053:         * Many of the methods here return lists of information in ResultSets. You can
0054:         * use the normal ResultSet methods such as getString and getInt to retrieve the
0055:         * data from these ResultSets. If a given form of metadata is not available,
0056:         * these methods show throw a SQLException.
0057:         * </p>
0058:         * <p>
0059:         * Some of these methods take arguments that are String patterns. These methods
0060:         * all have names such as fooPattern. Within a pattern String "%" means match
0061:         * any substring of 0 or more characters and "_" means match any one character.
0062:         * </p>
0063:         * 
0064:         * @author Mark Matthews
0065:         * @version $Id: DatabaseMetaData.java,v 1.27.4.66 2005/05/03 18:40:39 mmatthews
0066:         *          Exp $
0067:         */
0068:        public class DatabaseMetaData implements  java.sql.DatabaseMetaData {
0069:            protected abstract class IterateBlock {
0070:                IteratorWithCleanup iterator;
0071:
0072:                IterateBlock(IteratorWithCleanup i) {
0073:                    iterator = i;
0074:                }
0075:
0076:                public void doForAll() throws SQLException {
0077:                    try {
0078:                        while (iterator.hasNext()) {
0079:                            forEach(iterator.next());
0080:                        }
0081:                    } finally {
0082:                        iterator.close();
0083:                    }
0084:                }
0085:
0086:                abstract void forEach(Object each) throws SQLException;
0087:            }
0088:
0089:            protected abstract class IteratorWithCleanup {
0090:                abstract void close() throws SQLException;
0091:
0092:                abstract boolean hasNext() throws SQLException;
0093:
0094:                abstract Object next() throws SQLException;
0095:            }
0096:
0097:            class LocalAndReferencedColumns {
0098:                String constraintName;
0099:
0100:                List localColumnsList;
0101:
0102:                String referencedCatalog;
0103:
0104:                List referencedColumnsList;
0105:
0106:                String referencedTable;
0107:
0108:                LocalAndReferencedColumns(List localColumns, List refColumns,
0109:                        String constName, String refCatalog, String refTable) {
0110:                    this .localColumnsList = localColumns;
0111:                    this .referencedColumnsList = refColumns;
0112:                    this .constraintName = constName;
0113:                    this .referencedTable = refTable;
0114:                    this .referencedCatalog = refCatalog;
0115:                }
0116:            }
0117:
0118:            protected class ResultSetIterator extends IteratorWithCleanup {
0119:                int colIndex;
0120:
0121:                ResultSet resultSet;
0122:
0123:                ResultSetIterator(ResultSet rs, int index) {
0124:                    resultSet = rs;
0125:                    colIndex = index;
0126:                }
0127:
0128:                void close() throws SQLException {
0129:                    resultSet.close();
0130:                }
0131:
0132:                boolean hasNext() throws SQLException {
0133:                    return resultSet.next();
0134:                }
0135:
0136:                Object next() throws SQLException {
0137:                    return resultSet.getObject(colIndex);
0138:                }
0139:            }
0140:
0141:            protected class SingleStringIterator extends IteratorWithCleanup {
0142:                boolean onFirst = true;
0143:
0144:                String value;
0145:
0146:                SingleStringIterator(String s) {
0147:                    value = s;
0148:                }
0149:
0150:                void close() throws SQLException {
0151:                    // not needed
0152:
0153:                }
0154:
0155:                boolean hasNext() throws SQLException {
0156:                    return onFirst;
0157:                }
0158:
0159:                Object next() throws SQLException {
0160:                    onFirst = false;
0161:                    return value;
0162:                }
0163:            }
0164:
0165:            /**
0166:             * Parses and represents common data type information used by various
0167:             * column/parameter methods.
0168:             */
0169:            class TypeDescriptor {
0170:                int bufferLength;
0171:
0172:                int charOctetLength;
0173:
0174:                Integer columnSize;
0175:
0176:                short dataType;
0177:
0178:                Integer decimalDigits;
0179:
0180:                String isNullable;
0181:
0182:                int nullability;
0183:
0184:                int numPrecRadix = 10;
0185:
0186:                String typeName;
0187:
0188:                TypeDescriptor(String typeInfo, String nullabilityInfo)
0189:                        throws SQLException {
0190:                    if (typeInfo == null) {
0191:                        throw SQLError.createSQLException(
0192:                                "NULL typeinfo not supported.",
0193:                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
0194:                    }
0195:
0196:                    String mysqlType = "";
0197:                    String fullMysqlType = null;
0198:
0199:                    if (typeInfo.indexOf("(") != -1) {
0200:                        mysqlType = typeInfo
0201:                                .substring(0, typeInfo.indexOf("("));
0202:                    } else {
0203:                        mysqlType = typeInfo;
0204:                    }
0205:
0206:                    int indexOfUnsignedInMysqlType = StringUtils
0207:                            .indexOfIgnoreCase(mysqlType, "unsigned");
0208:
0209:                    if (indexOfUnsignedInMysqlType != -1) {
0210:                        mysqlType = mysqlType.substring(0,
0211:                                (indexOfUnsignedInMysqlType - 1));
0212:                    }
0213:
0214:                    // Add unsigned to typename reported to enduser as 'native type', if
0215:                    // present
0216:
0217:                    if (StringUtils.indexOfIgnoreCase(typeInfo, "unsigned") != -1) {
0218:                        fullMysqlType = mysqlType + " unsigned";
0219:                    } else {
0220:                        fullMysqlType = mysqlType;
0221:                    }
0222:
0223:                    if (conn.getCapitalizeTypeNames()) {
0224:                        fullMysqlType = fullMysqlType
0225:                                .toUpperCase(Locale.ENGLISH);
0226:                    }
0227:
0228:                    this .dataType = (short) MysqlDefs
0229:                            .mysqlToJavaType(mysqlType);
0230:
0231:                    this .typeName = fullMysqlType;
0232:
0233:                    // Figure Out the Size
0234:
0235:                    if (StringUtils.startsWithIgnoreCase(typeInfo, "enum")) {
0236:                        String temp = typeInfo.substring(typeInfo.indexOf("("),
0237:                                typeInfo.lastIndexOf(")"));
0238:                        java.util.StringTokenizer tokenizer = new java.util.StringTokenizer(
0239:                                temp, ",");
0240:                        int maxLength = 0;
0241:
0242:                        while (tokenizer.hasMoreTokens()) {
0243:                            maxLength = Math.max(maxLength, (tokenizer
0244:                                    .nextToken().length() - 2));
0245:                        }
0246:
0247:                        this .columnSize = Constants.integerValueOf(maxLength);
0248:                        this .decimalDigits = null;
0249:                    } else if (StringUtils
0250:                            .startsWithIgnoreCase(typeInfo, "set")) {
0251:                        String temp = typeInfo.substring(typeInfo.indexOf("("),
0252:                                typeInfo.lastIndexOf(")"));
0253:                        java.util.StringTokenizer tokenizer = new java.util.StringTokenizer(
0254:                                temp, ",");
0255:                        int maxLength = 0;
0256:
0257:                        while (tokenizer.hasMoreTokens()) {
0258:                            String setMember = tokenizer.nextToken().trim();
0259:
0260:                            if (setMember.startsWith("'")
0261:                                    && setMember.endsWith("'")) {
0262:                                maxLength += setMember.length() - 2;
0263:                            } else {
0264:                                maxLength += setMember.length();
0265:                            }
0266:                        }
0267:
0268:                        this .columnSize = Constants.integerValueOf(maxLength);
0269:                        this .decimalDigits = null;
0270:                    } else if (typeInfo.indexOf(",") != -1) {
0271:                        // Numeric with decimals
0272:                        this .columnSize = Integer.valueOf(typeInfo.substring(
0273:                                (typeInfo.indexOf("(") + 1),
0274:                                (typeInfo.indexOf(","))).trim());
0275:                        this .decimalDigits = Integer.valueOf(typeInfo
0276:                                .substring((typeInfo.indexOf(",") + 1),
0277:                                        (typeInfo.indexOf(")"))).trim());
0278:                    } else {
0279:                        this .columnSize = null;
0280:                        this .decimalDigits = null;
0281:
0282:                        /* If the size is specified with the DDL, use that */
0283:                        if ((StringUtils.indexOfIgnoreCase(typeInfo, "char") != -1
0284:                                || StringUtils.indexOfIgnoreCase(typeInfo,
0285:                                        "text") != -1
0286:                                || StringUtils.indexOfIgnoreCase(typeInfo,
0287:                                        "blob") != -1
0288:                                || StringUtils.indexOfIgnoreCase(typeInfo,
0289:                                        "binary") != -1 || StringUtils
0290:                                .indexOfIgnoreCase(typeInfo, "bit") != -1)
0291:                                && typeInfo.indexOf("(") != -1) {
0292:                            int endParenIndex = typeInfo.indexOf(")");
0293:
0294:                            if (endParenIndex == -1) {
0295:                                endParenIndex = typeInfo.length();
0296:                            }
0297:
0298:                            this .columnSize = Integer.valueOf(typeInfo
0299:                                    .substring((typeInfo.indexOf("(") + 1),
0300:                                            endParenIndex).trim());
0301:
0302:                            // Adjust for pseudo-boolean
0303:                            if (conn.getTinyInt1isBit()
0304:                                    && this .columnSize.intValue() == 1
0305:                                    && StringUtils.startsWithIgnoreCase(
0306:                                            typeInfo, 0, "tinyint")) {
0307:                                if (conn.getTransformedBitIsBoolean()) {
0308:                                    this .dataType = Types.BOOLEAN;
0309:                                    this .typeName = "BOOLEAN";
0310:                                } else {
0311:                                    this .dataType = Types.BIT;
0312:                                    this .typeName = "BIT";
0313:                                }
0314:                            }
0315:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0316:                                typeInfo, "tinyint")) {
0317:                            if (conn.getTinyInt1isBit()
0318:                                    && typeInfo.indexOf("(1)") != -1) {
0319:                                if (conn.getTransformedBitIsBoolean()) {
0320:                                    this .dataType = Types.BOOLEAN;
0321:                                    this .typeName = "BOOLEAN";
0322:                                } else {
0323:                                    this .dataType = Types.BIT;
0324:                                    this .typeName = "BIT";
0325:                                }
0326:                            } else {
0327:                                this .columnSize = Constants.integerValueOf(3);
0328:                                this .decimalDigits = Constants
0329:                                        .integerValueOf(0);
0330:                            }
0331:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0332:                                typeInfo, "smallint")) {
0333:                            this .columnSize = Constants.integerValueOf(5);
0334:                            this .decimalDigits = Constants.integerValueOf(0);
0335:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0336:                                typeInfo, "mediumint")) {
0337:                            this .columnSize = Constants.integerValueOf(7);
0338:                            this .decimalDigits = Constants.integerValueOf(0);
0339:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0340:                                typeInfo, "int")) {
0341:                            this .columnSize = Constants.integerValueOf(10);
0342:                            this .decimalDigits = Constants.integerValueOf(0);
0343:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0344:                                typeInfo, "integer")) {
0345:                            this .columnSize = Constants.integerValueOf(10);
0346:                            this .decimalDigits = Constants.integerValueOf(0);
0347:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0348:                                typeInfo, "bigint")) {
0349:                            this .columnSize = Constants.integerValueOf(19);
0350:                            this .decimalDigits = Constants.integerValueOf(0);
0351:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0352:                                typeInfo, "int24")) {
0353:                            this .columnSize = Constants.integerValueOf(19);
0354:                            this .decimalDigits = Constants.integerValueOf(0);
0355:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0356:                                typeInfo, "real")) {
0357:                            this .columnSize = Constants.integerValueOf(12);
0358:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0359:                                typeInfo, "float")) {
0360:                            this .columnSize = Constants.integerValueOf(12);
0361:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0362:                                typeInfo, "decimal")) {
0363:                            this .columnSize = Constants.integerValueOf(12);
0364:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0365:                                typeInfo, "numeric")) {
0366:                            this .columnSize = Constants.integerValueOf(12);
0367:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0368:                                typeInfo, "double")) {
0369:                            this .columnSize = Constants.integerValueOf(22);
0370:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0371:                                typeInfo, "char")) {
0372:                            this .columnSize = Constants.integerValueOf(1);
0373:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0374:                                typeInfo, "varchar")) {
0375:                            this .columnSize = Constants.integerValueOf(255);
0376:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0377:                                typeInfo, "date")) {
0378:                            this .columnSize = null;
0379:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0380:                                typeInfo, "time")) {
0381:                            this .columnSize = null;
0382:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0383:                                typeInfo, "timestamp")) {
0384:                            this .columnSize = null;
0385:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0386:                                typeInfo, "datetime")) {
0387:                            this .columnSize = null;
0388:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0389:                                typeInfo, "tinyblob")) {
0390:                            this .columnSize = Constants.integerValueOf(255);
0391:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0392:                                typeInfo, "blob")) {
0393:                            this .columnSize = Constants.integerValueOf(65535);
0394:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0395:                                typeInfo, "mediumblob")) {
0396:                            this .columnSize = Constants
0397:                                    .integerValueOf(16777215);
0398:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0399:                                typeInfo, "longblob")) {
0400:                            this .columnSize = Constants
0401:                                    .integerValueOf(Integer.MAX_VALUE);
0402:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0403:                                typeInfo, "tinytext")) {
0404:                            this .columnSize = Constants.integerValueOf(255);
0405:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0406:                                typeInfo, "text")) {
0407:                            this .columnSize = Constants.integerValueOf(65535);
0408:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0409:                                typeInfo, "mediumtext")) {
0410:                            this .columnSize = Constants
0411:                                    .integerValueOf(16777215);
0412:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0413:                                typeInfo, "longtext")) {
0414:                            this .columnSize = Constants
0415:                                    .integerValueOf(Integer.MAX_VALUE);
0416:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0417:                                typeInfo, "enum")) {
0418:                            this .columnSize = Constants.integerValueOf(255);
0419:                        } else if (StringUtils.startsWithIgnoreCaseAndWs(
0420:                                typeInfo, "set")) {
0421:                            this .columnSize = Constants.integerValueOf(255);
0422:                        }
0423:
0424:                    }
0425:
0426:                    // BUFFER_LENGTH
0427:                    this .bufferLength = MysqlIO.getMaxBuf();
0428:
0429:                    // NUM_PREC_RADIX (is this right for char?)
0430:                    this .numPrecRadix = 10;
0431:
0432:                    // Nullable?
0433:                    if (nullabilityInfo != null) {
0434:                        if (nullabilityInfo.equals("YES")) {
0435:                            this .nullability = java.sql.DatabaseMetaData.columnNullable;
0436:                            this .isNullable = "YES";
0437:
0438:                            // IS_NULLABLE
0439:                        } else {
0440:                            this .nullability = java.sql.DatabaseMetaData.columnNoNulls;
0441:                            this .isNullable = "NO";
0442:                        }
0443:                    } else {
0444:                        this .nullability = java.sql.DatabaseMetaData.columnNoNulls;
0445:                        this .isNullable = "NO";
0446:                    }
0447:                }
0448:            }
0449:
0450:            private static String mysqlKeywordsThatArentSQL92;
0451:
0452:            protected static final int MAX_IDENTIFIER_LENGTH = 64;
0453:
0454:            private static final int DEFERRABILITY = 13;
0455:
0456:            private static final int DELETE_RULE = 10;
0457:
0458:            private static final int FK_NAME = 11;
0459:
0460:            private static final int FKCOLUMN_NAME = 7;
0461:
0462:            private static final int FKTABLE_CAT = 4;
0463:
0464:            private static final int FKTABLE_NAME = 6;
0465:
0466:            private static final int FKTABLE_SCHEM = 5;
0467:
0468:            private static final int KEY_SEQ = 8;
0469:
0470:            private static final int PK_NAME = 12;
0471:
0472:            private static final int PKCOLUMN_NAME = 3;
0473:
0474:            //
0475:            // Column indexes used by all DBMD foreign key
0476:            // ResultSets
0477:            //
0478:            private static final int PKTABLE_CAT = 0;
0479:
0480:            private static final int PKTABLE_NAME = 2;
0481:
0482:            private static final int PKTABLE_SCHEM = 1;
0483:
0484:            /** The table type for generic tables that support foreign keys. */
0485:            private static final String SUPPORTS_FK = "SUPPORTS_FK";
0486:
0487:            private static final byte[] TABLE_AS_BYTES = "TABLE".getBytes();
0488:
0489:            private static final int UPDATE_RULE = 9;
0490:
0491:            private static final byte[] VIEW_AS_BYTES = "VIEW".getBytes();
0492:
0493:            private static final Constructor JDBC_4_DBMD_SHOW_CTOR;
0494:
0495:            private static final Constructor JDBC_4_DBMD_IS_CTOR;
0496:
0497:            static {
0498:                if (Util.isJdbc4()) {
0499:                    try {
0500:                        JDBC_4_DBMD_SHOW_CTOR = Class
0501:                                .forName("com.mysql.jdbc.JDBC4DatabaseMetaData")
0502:                                .getConstructor(
0503:                                        new Class[] {
0504:                                                com.mysql.jdbc.ConnectionImpl.class,
0505:                                                String.class });
0506:                        JDBC_4_DBMD_IS_CTOR = Class
0507:                                .forName(
0508:                                        "com.mysql.jdbc.JDBC4DatabaseMetaDataUsingInfoSchema")
0509:                                .getConstructor(
0510:                                        new Class[] {
0511:                                                com.mysql.jdbc.ConnectionImpl.class,
0512:                                                String.class });
0513:                    } catch (SecurityException e) {
0514:                        throw new RuntimeException(e);
0515:                    } catch (NoSuchMethodException e) {
0516:                        throw new RuntimeException(e);
0517:                    } catch (ClassNotFoundException e) {
0518:                        throw new RuntimeException(e);
0519:                    }
0520:                } else {
0521:                    JDBC_4_DBMD_IS_CTOR = null;
0522:                    JDBC_4_DBMD_SHOW_CTOR = null;
0523:                }
0524:
0525:                // Current as-of MySQL-5.1.16
0526:                String[] allMySQLKeywords = new String[] { "ACCESSIBLE", "ADD",
0527:                        "ALL", "ALTER", "ANALYZE", "AND", "AS", "ASC",
0528:                        "ASENSITIVE", "BEFORE", "BETWEEN", "BIGINT", "BINARY",
0529:                        "BLOB", "BOTH", "BY", "CALL", "CASCADE", "CASE",
0530:                        "CHANGE", "CHAR", "CHARACTER", "CHECK", "COLLATE",
0531:                        "COLUMN", "CONDITION", "CONNECTION", "CONSTRAINT",
0532:                        "CONTINUE", "CONVERT", "CREATE", "CROSS",
0533:                        "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP",
0534:                        "CURRENT_USER", "CURSOR", "DATABASE", "DATABASES",
0535:                        "DAY_HOUR", "DAY_MICROSECOND", "DAY_MINUTE",
0536:                        "DAY_SECOND", "DEC", "DECIMAL", "DECLARE", "DEFAULT",
0537:                        "DELAYED", "DELETE", "DESC", "DESCRIBE",
0538:                        "DETERMINISTIC", "DISTINCT", "DISTINCTROW", "DIV",
0539:                        "DOUBLE", "DROP", "DUAL", "EACH", "ELSE", "ELSEIF",
0540:                        "ENCLOSED", "ESCAPED", "EXISTS", "EXIT", "EXPLAIN",
0541:                        "FALSE", "FETCH", "FLOAT", "FLOAT4", "FLOAT8", "FOR",
0542:                        "FORCE", "FOREIGN", "FROM", "FULLTEXT", "GRANT",
0543:                        "GROUP", "HAVING", "HIGH_PRIORITY", "HOUR_MICROSECOND",
0544:                        "HOUR_MINUTE", "HOUR_SECOND", "IF", "IGNORE", "IN",
0545:                        "INDEX", "INFILE", "INNER", "INOUT", "INSENSITIVE",
0546:                        "INSERT", "INT", "INT1", "INT2", "INT3", "INT4",
0547:                        "INT8", "INTEGER", "INTERVAL", "INTO", "IS", "ITERATE",
0548:                        "JOIN", "KEY", "KEYS", "KILL", "LEADING", "LEAVE",
0549:                        "LEFT", "LIKE", "LIMIT", "LINEAR", "LINES", "LOAD",
0550:                        "LOCALTIME", "LOCALTIMESTAMP", "LOCK", "LONG",
0551:                        "LONGBLOB", "LONGTEXT", "LOOP", "LOW_PRIORITY",
0552:                        "MATCH", "MEDIUMBLOB", "MEDIUMINT", "MEDIUMTEXT",
0553:                        "MIDDLEINT", "MINUTE_MICROSECOND", "MINUTE_SECOND",
0554:                        "MOD", "MODIFIES", "NATURAL", "NOT",
0555:                        "NO_WRITE_TO_BINLOG", "NULL", "NUMERIC", "ON",
0556:                        "OPTIMIZE", "OPTION", "OPTIONALLY", "OR", "ORDER",
0557:                        "OUT", "OUTER", "OUTFILE", "PRECISION", "PRIMARY",
0558:                        "PROCEDURE", "PURGE", "RANGE", "READ", "READS",
0559:                        "READ_ONLY", "READ_WRITE", "REAL", "REFERENCES",
0560:                        "REGEXP", "RELEASE", "RENAME", "REPEAT", "REPLACE",
0561:                        "REQUIRE", "RESTRICT", "RETURN", "REVOKE", "RIGHT",
0562:                        "RLIKE", "SCHEMA", "SCHEMAS", "SECOND_MICROSECOND",
0563:                        "SELECT", "SENSITIVE", "SEPARATOR", "SET", "SHOW",
0564:                        "SMALLINT", "SPATIAL", "SPECIFIC", "SQL",
0565:                        "SQLEXCEPTION", "SQLSTATE", "SQLWARNING",
0566:                        "SQL_BIG_RESULT", "SQL_CALC_FOUND_ROWS",
0567:                        "SQL_SMALL_RESULT", "SSL", "STARTING", "STRAIGHT_JOIN",
0568:                        "TABLE", "TERMINATED", "THEN", "TINYBLOB", "TINYINT",
0569:                        "TINYTEXT", "TO", "TRAILING", "TRIGGER", "TRUE",
0570:                        "UNDO", "UNION", "UNIQUE", "UNLOCK", "UNSIGNED",
0571:                        "UPDATE", "USAGE", "USE", "USING", "UTC_DATE",
0572:                        "UTC_TIME", "UTC_TIMESTAMP", "VALUES", "VARBINARY",
0573:                        "VARCHAR", "VARCHARACTER", "VARYING", "WHEN", "WHERE",
0574:                        "WHILE", "WITH", "WRITE", "X509", "XOR", "YEAR_MONTH",
0575:                        "ZEROFILL" };
0576:
0577:                String[] sql92Keywords = new String[] { "ABSOLUTE", "EXEC",
0578:                        "OVERLAPS", "ACTION", "EXECUTE", "PAD", "ADA",
0579:                        "EXISTS", "PARTIAL", "ADD", "EXTERNAL", "PASCAL",
0580:                        "ALL", "EXTRACT", "POSITION", "ALLOCATE", "FALSE",
0581:                        "PRECISION", "ALTER", "FETCH", "PREPARE", "AND",
0582:                        "FIRST", "PRESERVE", "ANY", "FLOAT", "PRIMARY", "ARE",
0583:                        "FOR", "PRIOR", "AS", "FOREIGN", "PRIVILEGES", "ASC",
0584:                        "FORTRAN", "PROCEDURE", "ASSERTION", "FOUND", "PUBLIC",
0585:                        "AT", "FROM", "READ", "AUTHORIZATION", "FULL", "REAL",
0586:                        "AVG", "GET", "REFERENCES", "BEGIN", "GLOBAL",
0587:                        "RELATIVE", "BETWEEN", "GO", "RESTRICT", "BIT", "GOTO",
0588:                        "REVOKE", "BIT_LENGTH", "GRANT", "RIGHT", "BOTH",
0589:                        "GROUP", "ROLLBACK", "BY", "HAVING", "ROWS", "CASCADE",
0590:                        "HOUR", "SCHEMA", "CASCADED", "IDENTITY", "SCROLL",
0591:                        "CASE", "IMMEDIATE", "SECOND", "CAST", "IN", "SECTION",
0592:                        "CATALOG", "INCLUDE", "SELECT", "CHAR", "INDEX",
0593:                        "SESSION", "CHAR_LENGTH", "INDICATOR", "SESSION_USER",
0594:                        "CHARACTER", "INITIALLY", "SET", "CHARACTER_LENGTH",
0595:                        "INNER", "SIZE", "CHECK", "INPUT", "SMALLINT", "CLOSE",
0596:                        "INSENSITIVE", "SOME", "COALESCE", "INSERT", "SPACE",
0597:                        "COLLATE", "INT", "SQL", "COLLATION", "INTEGER",
0598:                        "SQLCA", "COLUMN", "INTERSECT", "SQLCODE", "COMMIT",
0599:                        "INTERVAL", "SQLERROR", "CONNECT", "INTO", "SQLSTATE",
0600:                        "CONNECTION", "IS", "SQLWARNING", "CONSTRAINT",
0601:                        "ISOLATION", "SUBSTRING", "CONSTRAINTS", "JOIN", "SUM",
0602:                        "CONTINUE", "KEY", "SYSTEM_USER", "CONVERT",
0603:                        "LANGUAGE", "TABLE", "CORRESPONDING", "LAST",
0604:                        "TEMPORARY", "COUNT", "LEADING", "THEN", "CREATE",
0605:                        "LEFT", "TIME", "CROSS", "LEVEL", "TIMESTAMP",
0606:                        "CURRENT", "LIKE", "TIMEZONE_HOUR", "CURRENT_DATE",
0607:                        "LOCAL", "TIMEZONE_MINUTE", "CURRENT_TIME", "LOWER",
0608:                        "TO", "CURRENT_TIMESTAMP", "MATCH", "TRAILING",
0609:                        "CURRENT_USER", "MAX", "TRANSACTION", "CURSOR", "MIN",
0610:                        "TRANSLATE", "DATE", "MINUTE", "TRANSLATION", "DAY",
0611:                        "MODULE", "TRIM", "DEALLOCATE", "MONTH", "TRUE", "DEC",
0612:                        "NAMES", "UNION", "DECIMAL", "NATIONAL", "UNIQUE",
0613:                        "DECLARE", "NATURAL", "UNKNOWN", "DEFAULT", "NCHAR",
0614:                        "UPDATE", "DEFERRABLE", "NEXT", "UPPER", "DEFERRED",
0615:                        "NO", "USAGE", "DELETE", "NONE", "USER", "DESC", "NOT",
0616:                        "USING", "DESCRIBE", "NULL", "VALUE", "DESCRIPTOR",
0617:                        "NULLIF", "VALUES", "DIAGNOSTICS", "NUMERIC",
0618:                        "VARCHAR", "DISCONNECT", "OCTET_LENGTH", "VARYING",
0619:                        "DISTINCT", "OF", "VIEW", "DOMAIN", "ON", "WHEN",
0620:                        "DOUBLE", "ONLY", "WHENEVER", "DROP", "OPEN", "WHERE",
0621:                        "ELSE", "OPTION", "WITH", "END", "OR", "WORK",
0622:                        "END-EXEC", "ORDER", "WRITE", "ESCAPE", "OUTER",
0623:                        "YEAR", "EXCEPT", "OUTPUT", "ZONE", "EXCEPTION" };
0624:
0625:                TreeMap mySQLKeywordMap = new TreeMap();
0626:
0627:                for (int i = 0; i < allMySQLKeywords.length; i++) {
0628:                    mySQLKeywordMap.put(allMySQLKeywords[i], null);
0629:                }
0630:
0631:                HashMap sql92KeywordMap = new HashMap(sql92Keywords.length);
0632:
0633:                for (int i = 0; i < sql92Keywords.length; i++) {
0634:                    sql92KeywordMap.put(sql92Keywords[i], null);
0635:                }
0636:
0637:                Iterator it = sql92KeywordMap.keySet().iterator();
0638:
0639:                while (it.hasNext()) {
0640:                    mySQLKeywordMap.remove(it.next());
0641:                }
0642:
0643:                StringBuffer keywordBuf = new StringBuffer();
0644:
0645:                it = mySQLKeywordMap.keySet().iterator();
0646:
0647:                if (it.hasNext()) {
0648:                    keywordBuf.append(it.next().toString());
0649:                }
0650:
0651:                while (it.hasNext()) {
0652:                    keywordBuf.append(",");
0653:                    keywordBuf.append(it.next().toString());
0654:                }
0655:
0656:                mysqlKeywordsThatArentSQL92 = keywordBuf.toString();
0657:            }
0658:
0659:            /** The connection to the database */
0660:            protected ConnectionImpl conn;
0661:
0662:            /** The 'current' database name being used */
0663:            protected String database = null;
0664:
0665:            /** What character to use when quoting identifiers */
0666:            protected String quotedId = null;
0667:
0668:            // We need to provide factory-style methods so we can support both JDBC3 (and older)
0669:            // and JDBC4 runtimes, otherwise the class verifier complains...
0670:
0671:            protected static DatabaseMetaData getInstance(
0672:                    ConnectionImpl connToSet, String databaseToSet)
0673:                    throws SQLException {
0674:                if (!Util.isJdbc4()) {
0675:                    if (connToSet != null
0676:                            && connToSet.getUseInformationSchema()
0677:                            && connToSet.versionMeetsMinimum(5, 0, 7)) {
0678:                        return new DatabaseMetaDataUsingInfoSchema(connToSet,
0679:                                databaseToSet);
0680:                    }
0681:
0682:                    return new DatabaseMetaData(connToSet, databaseToSet);
0683:                }
0684:
0685:                if (connToSet != null && connToSet.getUseInformationSchema()
0686:                        && connToSet.versionMeetsMinimum(5, 0, 7)) {
0687:
0688:                    return (DatabaseMetaData) Util.handleNewInstance(
0689:                            JDBC_4_DBMD_IS_CTOR, new Object[] { connToSet,
0690:                                    databaseToSet });
0691:                }
0692:
0693:                return (DatabaseMetaData) Util.handleNewInstance(
0694:                        JDBC_4_DBMD_SHOW_CTOR, new Object[] { connToSet,
0695:                                databaseToSet });
0696:            }
0697:
0698:            /**
0699:             * Creates a new DatabaseMetaData object.
0700:             * 
0701:             * @param connToSet
0702:             *            DOCUMENT ME!
0703:             * @param databaseToSet
0704:             *            DOCUMENT ME!
0705:             */
0706:            protected DatabaseMetaData(ConnectionImpl connToSet,
0707:                    String databaseToSet) {
0708:                this .conn = connToSet;
0709:                this .database = databaseToSet;
0710:
0711:                try {
0712:                    this .quotedId = this .conn.supportsQuotedIdentifiers() ? getIdentifierQuoteString()
0713:                            : "";
0714:                } catch (SQLException sqlEx) {
0715:                    // Forced by API, never thrown from getIdentifierQuoteString() in
0716:                    // this
0717:                    // implementation.
0718:                    AssertionFailedException.shouldNotHappen(sqlEx);
0719:                }
0720:            }
0721:
0722:            /**
0723:             * Can all the procedures returned by getProcedures be called by the current
0724:             * user?
0725:             * 
0726:             * @return true if so
0727:             * @throws SQLException
0728:             *             DOCUMENT ME!
0729:             */
0730:            public boolean allProceduresAreCallable() throws SQLException {
0731:                return false;
0732:            }
0733:
0734:            /**
0735:             * Can all the tables returned by getTable be SELECTed by the current user?
0736:             * 
0737:             * @return true if so
0738:             * @throws SQLException
0739:             *             DOCUMENT ME!
0740:             */
0741:            public boolean allTablesAreSelectable() throws SQLException {
0742:                return false;
0743:            }
0744:
0745:            private java.sql.ResultSet buildResultSet(
0746:                    com.mysql.jdbc.Field[] fields, java.util.ArrayList rows)
0747:                    throws SQLException {
0748:                return buildResultSet(fields, rows, this .conn);
0749:            }
0750:
0751:            static java.sql.ResultSet buildResultSet(
0752:                    com.mysql.jdbc.Field[] fields, java.util.ArrayList rows,
0753:                    ConnectionImpl c) throws SQLException {
0754:                int fieldsLength = fields.length;
0755:
0756:                for (int i = 0; i < fieldsLength; i++) {
0757:                    fields[i].setConnection(c);
0758:                    fields[i].setUseOldNameMetadata(true);
0759:                }
0760:
0761:                return com.mysql.jdbc.ResultSetImpl.getInstance(c.getCatalog(),
0762:                        fields, new RowDataStatic(rows), c, null, false);
0763:            }
0764:
0765:            private void convertToJdbcFunctionList(String catalog,
0766:                    ResultSet proceduresRs, boolean needsClientFiltering,
0767:                    String db, Map procedureRowsOrderedByName, int nameIndex,
0768:                    Field[] fields) throws SQLException {
0769:                while (proceduresRs.next()) {
0770:                    boolean shouldAdd = true;
0771:
0772:                    if (needsClientFiltering) {
0773:                        shouldAdd = false;
0774:
0775:                        String procDb = proceduresRs.getString(1);
0776:
0777:                        if (db == null && procDb == null) {
0778:                            shouldAdd = true;
0779:                        } else if (db != null && db.equals(procDb)) {
0780:                            shouldAdd = true;
0781:                        }
0782:                    }
0783:
0784:                    if (shouldAdd) {
0785:                        String functionName = proceduresRs.getString(nameIndex);
0786:
0787:                        byte[][] rowData = null;
0788:
0789:                        if (fields != null && fields.length == 8) {
0790:
0791:                            rowData = new byte[8][];
0792:                            rowData[0] = catalog == null ? null : s2b(catalog); // PROCEDURE_CAT
0793:                            rowData[1] = null; // PROCEDURE_SCHEM
0794:                            rowData[2] = s2b(functionName); // PROCEDURE_NAME
0795:                            rowData[3] = null; // reserved1
0796:                            rowData[4] = null; // reserved2
0797:                            rowData[5] = null; // reserved3
0798:                            rowData[6] = s2b(proceduresRs.getString("comment")); // REMARKS
0799:                            rowData[7] = s2b(Integer
0800:                                    .toString(procedureReturnsResult)); // PROCEDURE_TYPE
0801:                        } else {
0802:
0803:                            rowData = new byte[6][];
0804:
0805:                            rowData[0] = catalog == null ? null : s2b(catalog); // FUNCTION_CAT
0806:                            rowData[1] = null; // FUNCTION_SCHEM
0807:                            rowData[2] = s2b(functionName); // FUNCTION_NAME
0808:                            rowData[3] = s2b(proceduresRs.getString("comment")); // REMARKS
0809:                            rowData[4] = s2b(Integer
0810:                                    .toString(getJDBC4FunctionNoTableConstant())); // FUNCTION_TYPE
0811:                            rowData[5] = s2b(functionName); // SPECFIC NAME
0812:                        }
0813:
0814:                        procedureRowsOrderedByName.put(functionName,
0815:                                new ByteArrayRow(rowData));
0816:                    }
0817:                }
0818:            }
0819:
0820:            protected int getJDBC4FunctionNoTableConstant() {
0821:                return 0;
0822:            }
0823:
0824:            private void convertToJdbcProcedureList(boolean fromSelect,
0825:                    String catalog, ResultSet proceduresRs,
0826:                    boolean needsClientFiltering, String db,
0827:                    Map procedureRowsOrderedByName, int nameIndex)
0828:                    throws SQLException {
0829:                while (proceduresRs.next()) {
0830:                    boolean shouldAdd = true;
0831:
0832:                    if (needsClientFiltering) {
0833:                        shouldAdd = false;
0834:
0835:                        String procDb = proceduresRs.getString(1);
0836:
0837:                        if (db == null && procDb == null) {
0838:                            shouldAdd = true;
0839:                        } else if (db != null && db.equals(procDb)) {
0840:                            shouldAdd = true;
0841:                        }
0842:                    }
0843:
0844:                    if (shouldAdd) {
0845:                        String procedureName = proceduresRs
0846:                                .getString(nameIndex);
0847:                        byte[][] rowData = new byte[8][];
0848:                        rowData[0] = catalog == null ? null : s2b(catalog);
0849:                        rowData[1] = null;
0850:                        rowData[2] = s2b(procedureName);
0851:                        rowData[3] = null;
0852:                        rowData[4] = null;
0853:                        rowData[5] = null;
0854:                        rowData[6] = null;
0855:
0856:                        boolean isFunction = fromSelect ? "FUNCTION"
0857:                                .equalsIgnoreCase(proceduresRs
0858:                                        .getString("type")) : false;
0859:                        rowData[7] = s2b(isFunction ? Integer
0860:                                .toString(procedureReturnsResult) : Integer
0861:                                .toString(procedureResultUnknown));
0862:
0863:                        procedureRowsOrderedByName.put(procedureName,
0864:                                new ByteArrayRow(rowData));
0865:                    }
0866:                }
0867:            }
0868:
0869:            private ResultSetRow convertTypeDescriptorToProcedureRow(
0870:                    byte[] procNameAsBytes, String paramName,
0871:                    boolean isOutParam, boolean isInParam,
0872:                    boolean isReturnParam, TypeDescriptor typeDesc,
0873:                    boolean forGetFunctionColumns, int ordinal)
0874:                    throws SQLException {
0875:                byte[][] row = forGetFunctionColumns ? new byte[17][]
0876:                        : new byte[14][];
0877:                row[0] = null; // PROCEDURE_CAT
0878:                row[1] = null; // PROCEDURE_SCHEM
0879:                row[2] = procNameAsBytes; // PROCEDURE/NAME
0880:                row[3] = s2b(paramName); // COLUMN_NAME
0881:                // COLUMN_TYPE
0882:
0883:                // NOTE: For JDBC-4.0, we luck out here for functions
0884:                // because the values are the same for functionColumn....
0885:                // and they're not using Enumerations....
0886:
0887:                if (isInParam && isOutParam) {
0888:                    row[4] = s2b(String.valueOf(procedureColumnInOut));
0889:                } else if (isInParam) {
0890:                    row[4] = s2b(String.valueOf(procedureColumnIn));
0891:                } else if (isOutParam) {
0892:                    row[4] = s2b(String.valueOf(procedureColumnOut));
0893:                } else if (isReturnParam) {
0894:                    row[4] = s2b(String.valueOf(procedureColumnReturn));
0895:                } else {
0896:                    row[4] = s2b(String.valueOf(procedureColumnUnknown));
0897:                }
0898:                row[5] = s2b(Short.toString(typeDesc.dataType)); // DATA_TYPE
0899:                row[6] = s2b(typeDesc.typeName); // TYPE_NAME
0900:                row[7] = typeDesc.columnSize == null ? null
0901:                        : s2b(typeDesc.columnSize.toString()); // PRECISION
0902:                row[8] = s2b(Integer.toString(typeDesc.bufferLength)); // LENGTH
0903:                row[9] = typeDesc.decimalDigits == null ? null
0904:                        : s2b(typeDesc.decimalDigits.toString()); // SCALE
0905:                row[10] = s2b(Integer.toString(typeDesc.numPrecRadix)); // RADIX
0906:                // Map 'column****' to 'procedure****'
0907:                switch (typeDesc.nullability) {
0908:                case columnNoNulls:
0909:                    row[11] = s2b(String.valueOf(procedureNoNulls)); // NULLABLE
0910:
0911:                    break;
0912:
0913:                case columnNullable:
0914:                    row[11] = s2b(String.valueOf(procedureNullable)); // NULLABLE
0915:
0916:                    break;
0917:
0918:                case columnNullableUnknown:
0919:                    row[11] = s2b(String.valueOf(procedureNullableUnknown)); // nullable
0920:
0921:                    break;
0922:
0923:                default:
0924:                    throw SQLError
0925:                            .createSQLException(
0926:                                    "Internal error while parsing callable statement metadata (unknown nullability value fount)",
0927:                                    SQLError.SQL_STATE_GENERAL_ERROR);
0928:                }
0929:
0930:                row[12] = null;
0931:
0932:                if (forGetFunctionColumns) {
0933:                    // CHAR_OCTECT_LENGTH
0934:                    row[13] = null;
0935:
0936:                    // ORDINAL_POSITION
0937:                    row[14] = s2b(String.valueOf(ordinal));
0938:
0939:                    // IS_NULLABLE
0940:                    row[15] = Constants.EMPTY_BYTE_ARRAY;
0941:
0942:                    row[16] = s2b(paramName);
0943:                }
0944:
0945:                return new ByteArrayRow(row);
0946:            }
0947:
0948:            /**
0949:             * Does a data definition statement within a transaction force the
0950:             * transaction to commit?
0951:             * 
0952:             * @return true if so
0953:             * @throws SQLException
0954:             *             DOCUMENT ME!
0955:             */
0956:            public boolean dataDefinitionCausesTransactionCommit()
0957:                    throws SQLException {
0958:                return true;
0959:            }
0960:
0961:            /**
0962:             * Is a data definition statement within a transaction ignored?
0963:             * 
0964:             * @return true if so
0965:             * @throws SQLException
0966:             *             DOCUMENT ME!
0967:             */
0968:            public boolean dataDefinitionIgnoredInTransactions()
0969:                    throws SQLException {
0970:                return false;
0971:            }
0972:
0973:            /**
0974:             * JDBC 2.0 Determine whether or not a visible row delete can be detected by
0975:             * calling ResultSet.rowDeleted(). If deletesAreDetected() returns false,
0976:             * then deleted rows are removed from the result set.
0977:             * 
0978:             * @param type
0979:             *            set type, i.e. ResultSet.TYPE_XXX
0980:             * @return true if changes are detected by the resultset type
0981:             * @exception SQLException
0982:             *                if a database-access error occurs.
0983:             */
0984:            public boolean deletesAreDetected(int type) throws SQLException {
0985:                return false;
0986:            }
0987:
0988:            // ----------------------------------------------------------------------
0989:
0990:            /**
0991:             * Did getMaxRowSize() include LONGVARCHAR and LONGVARBINARY blobs?
0992:             * 
0993:             * @return true if so
0994:             * @throws SQLException
0995:             *             DOCUMENT ME!
0996:             */
0997:            public boolean doesMaxRowSizeIncludeBlobs() throws SQLException {
0998:                return true;
0999:            }
1000:
1001:            /**
1002:             * Extracts foreign key info for one table.
1003:             * 
1004:             * @param rows
1005:             *            the list of rows to add to
1006:             * @param rs
1007:             *            the result set from 'SHOW CREATE TABLE'
1008:             * @param catalog
1009:             *            the database name
1010:             * @return the list of rows with new rows added
1011:             * @throws SQLException
1012:             *             if a database access error occurs
1013:             */
1014:            public List extractForeignKeyForTable(ArrayList rows,
1015:                    java.sql.ResultSet rs, String catalog) throws SQLException {
1016:                byte[][] row = new byte[3][];
1017:                row[0] = rs.getBytes(1);
1018:                row[1] = s2b(SUPPORTS_FK);
1019:
1020:                String createTableString = rs.getString(2);
1021:                StringTokenizer lineTokenizer = new StringTokenizer(
1022:                        createTableString, "\n");
1023:                StringBuffer commentBuf = new StringBuffer("comment; ");
1024:                boolean firstTime = true;
1025:
1026:                String quoteChar = getIdentifierQuoteString();
1027:
1028:                if (quoteChar == null) {
1029:                    quoteChar = "`";
1030:                }
1031:
1032:                while (lineTokenizer.hasMoreTokens()) {
1033:                    String line = lineTokenizer.nextToken().trim();
1034:
1035:                    String constraintName = null;
1036:
1037:                    if (StringUtils.startsWithIgnoreCase(line, "CONSTRAINT")) {
1038:                        boolean usingBackTicks = true;
1039:                        int beginPos = line.indexOf(quoteChar);
1040:
1041:                        if (beginPos == -1) {
1042:                            beginPos = line.indexOf("\"");
1043:                            usingBackTicks = false;
1044:                        }
1045:
1046:                        if (beginPos != -1) {
1047:                            int endPos = -1;
1048:
1049:                            if (usingBackTicks) {
1050:                                endPos = line.indexOf(quoteChar, beginPos + 1);
1051:                            } else {
1052:                                endPos = line.indexOf("\"", beginPos + 1);
1053:                            }
1054:
1055:                            if (endPos != -1) {
1056:                                constraintName = line.substring(beginPos + 1,
1057:                                        endPos);
1058:                                line = line
1059:                                        .substring(endPos + 1, line.length())
1060:                                        .trim();
1061:                            }
1062:                        }
1063:                    }
1064:
1065:                    if (line.startsWith("FOREIGN KEY")) {
1066:                        if (line.endsWith(",")) {
1067:                            line = line.substring(0, line.length() - 1);
1068:                        }
1069:
1070:                        char quote = this .quotedId.charAt(0);
1071:
1072:                        int indexOfFK = line.indexOf("FOREIGN KEY");
1073:
1074:                        String localColumnName = null;
1075:                        String referencedCatalogName = this .quotedId + catalog
1076:                                + this .quotedId;
1077:                        String referencedTableName = null;
1078:                        String referencedColumnName = null;
1079:
1080:                        if (indexOfFK != -1) {
1081:                            int afterFk = indexOfFK + "FOREIGN KEY".length();
1082:
1083:                            int indexOfRef = StringUtils
1084:                                    .indexOfIgnoreCaseRespectQuotes(afterFk,
1085:                                            line, "REFERENCES", quote, true);
1086:
1087:                            if (indexOfRef != -1) {
1088:
1089:                                int indexOfParenOpen = line.indexOf('(',
1090:                                        afterFk);
1091:                                int indexOfParenClose = StringUtils
1092:                                        .indexOfIgnoreCaseRespectQuotes(
1093:                                                indexOfParenOpen, line, ")",
1094:                                                quote, true);
1095:
1096:                                if (indexOfParenOpen == -1
1097:                                        || indexOfParenClose == -1) {
1098:                                    // throw SQLError.createSQLException();
1099:                                }
1100:
1101:                                localColumnName = line
1102:                                        .substring(indexOfParenOpen + 1,
1103:                                                indexOfParenClose);
1104:
1105:                                int afterRef = indexOfRef
1106:                                        + "REFERENCES".length();
1107:
1108:                                int referencedColumnBegin = StringUtils
1109:                                        .indexOfIgnoreCaseRespectQuotes(
1110:                                                afterRef, line, "(", quote,
1111:                                                true);
1112:
1113:                                if (referencedColumnBegin != -1) {
1114:                                    referencedTableName = line.substring(
1115:                                            afterRef, referencedColumnBegin);
1116:
1117:                                    int referencedColumnEnd = StringUtils
1118:                                            .indexOfIgnoreCaseRespectQuotes(
1119:                                                    referencedColumnBegin + 1,
1120:                                                    line, ")", quote, true);
1121:
1122:                                    if (referencedColumnEnd != -1) {
1123:                                        referencedColumnName = line.substring(
1124:                                                referencedColumnBegin + 1,
1125:                                                referencedColumnEnd);
1126:                                    }
1127:
1128:                                    int indexOfCatalogSep = StringUtils
1129:                                            .indexOfIgnoreCaseRespectQuotes(0,
1130:                                                    referencedTableName, ".",
1131:                                                    quote, true);
1132:
1133:                                    if (indexOfCatalogSep != -1) {
1134:                                        referencedCatalogName = referencedTableName
1135:                                                .substring(0, indexOfCatalogSep);
1136:                                        referencedTableName = referencedTableName
1137:                                                .substring(indexOfCatalogSep + 1);
1138:                                    }
1139:                                }
1140:                            }
1141:                        }
1142:
1143:                        if (!firstTime) {
1144:                            commentBuf.append("; ");
1145:                        } else {
1146:                            firstTime = false;
1147:                        }
1148:
1149:                        if (constraintName != null) {
1150:                            commentBuf.append(constraintName);
1151:                        } else {
1152:                            commentBuf.append("not_available");
1153:                        }
1154:
1155:                        commentBuf.append("(");
1156:                        commentBuf.append(localColumnName);
1157:                        commentBuf.append(") REFER ");
1158:                        commentBuf.append(referencedCatalogName);
1159:                        commentBuf.append("/");
1160:                        commentBuf.append(referencedTableName);
1161:                        commentBuf.append("(");
1162:                        commentBuf.append(referencedColumnName);
1163:                        commentBuf.append(")");
1164:
1165:                        int lastParenIndex = line.lastIndexOf(")");
1166:
1167:                        if (lastParenIndex != (line.length() - 1)) {
1168:                            String cascadeOptions = cascadeOptions = line
1169:                                    .substring(lastParenIndex + 1);
1170:                            commentBuf.append(" ");
1171:                            commentBuf.append(cascadeOptions);
1172:                        }
1173:                    }
1174:                }
1175:
1176:                row[2] = s2b(commentBuf.toString());
1177:                rows.add(new ByteArrayRow(row));
1178:
1179:                return rows;
1180:            }
1181:
1182:            /**
1183:             * Creates a result set similar enough to 'SHOW TABLE STATUS' to allow the
1184:             * same code to work on extracting the foreign key data
1185:             * 
1186:             * @param connToUse
1187:             *            the database connection to use
1188:             * @param metadata
1189:             *            the DatabaseMetaData instance calling this method
1190:             * @param catalog
1191:             *            the database name to extract foreign key info for
1192:             * @param tableName
1193:             *            the table to extract foreign key info for
1194:             * @return A result set that has the structure of 'show table status'
1195:             * @throws SQLException
1196:             *             if a database access error occurs.
1197:             */
1198:            public ResultSet extractForeignKeyFromCreateTable(String catalog,
1199:                    String tableName) throws SQLException {
1200:                ArrayList tableList = new ArrayList();
1201:                java.sql.ResultSet rs = null;
1202:                java.sql.Statement stmt = null;
1203:
1204:                if (tableName != null) {
1205:                    tableList.add(tableName);
1206:                } else {
1207:                    try {
1208:                        rs = getTables(catalog, "", "%",
1209:                                new String[] { "TABLE" });
1210:
1211:                        while (rs.next()) {
1212:                            tableList.add(rs.getString("TABLE_NAME"));
1213:                        }
1214:                    } finally {
1215:                        if (rs != null) {
1216:                            rs.close();
1217:                        }
1218:
1219:                        rs = null;
1220:                    }
1221:                }
1222:
1223:                ArrayList rows = new ArrayList();
1224:                Field[] fields = new Field[3];
1225:                fields[0] = new Field("", "Name", Types.CHAR, Integer.MAX_VALUE);
1226:                fields[1] = new Field("", "Type", Types.CHAR, 255);
1227:                fields[2] = new Field("", "Comment", Types.CHAR,
1228:                        Integer.MAX_VALUE);
1229:
1230:                int numTables = tableList.size();
1231:                stmt = this .conn.getMetadataSafeStatement();
1232:
1233:                String quoteChar = getIdentifierQuoteString();
1234:
1235:                if (quoteChar == null) {
1236:                    quoteChar = "`";
1237:                }
1238:
1239:                try {
1240:                    for (int i = 0; i < numTables; i++) {
1241:                        String tableToExtract = (String) tableList.get(i);
1242:
1243:                        String query = new StringBuffer("SHOW CREATE TABLE ")
1244:                                .append(quoteChar).append(catalog).append(
1245:                                        quoteChar).append(".")
1246:                                .append(quoteChar).append(tableToExtract)
1247:                                .append(quoteChar).toString();
1248:
1249:                        try {
1250:                            rs = stmt.executeQuery(query);
1251:                        } catch (SQLException sqlEx) {
1252:                            // Table might've disappeared on us, not really an error
1253:                            String sqlState = sqlEx.getSQLState();
1254:
1255:                            if (!"42S02".equals(sqlState)
1256:                                    && sqlEx.getErrorCode() != MysqlErrorNumbers.ER_NO_SUCH_TABLE) {
1257:                                throw sqlEx;
1258:                            }
1259:
1260:                            continue;
1261:                        }
1262:
1263:                        while (rs.next()) {
1264:                            extractForeignKeyForTable(rows, rs, catalog);
1265:                        }
1266:                    }
1267:                } finally {
1268:                    if (rs != null) {
1269:                        rs.close();
1270:                    }
1271:
1272:                    rs = null;
1273:
1274:                    if (stmt != null) {
1275:                        stmt.close();
1276:                    }
1277:
1278:                    stmt = null;
1279:                }
1280:
1281:                return buildResultSet(fields, rows);
1282:            }
1283:
1284:            /**
1285:             * @see DatabaseMetaData#getAttributes(String, String, String, String)
1286:             */
1287:            public java.sql.ResultSet getAttributes(String arg0, String arg1,
1288:                    String arg2, String arg3) throws SQLException {
1289:                Field[] fields = new Field[21];
1290:                fields[0] = new Field("", "TYPE_CAT", Types.CHAR, 32);
1291:                fields[1] = new Field("", "TYPE_SCHEM", Types.CHAR, 32);
1292:                fields[2] = new Field("", "TYPE_NAME", Types.CHAR, 32);
1293:                fields[3] = new Field("", "ATTR_NAME", Types.CHAR, 32);
1294:                fields[4] = new Field("", "DATA_TYPE", Types.SMALLINT, 32);
1295:                fields[5] = new Field("", "ATTR_TYPE_NAME", Types.CHAR, 32);
1296:                fields[6] = new Field("", "ATTR_SIZE", Types.INTEGER, 32);
1297:                fields[7] = new Field("", "DECIMAL_DIGITS", Types.INTEGER, 32);
1298:                fields[8] = new Field("", "NUM_PREC_RADIX", Types.INTEGER, 32);
1299:                fields[9] = new Field("", "NULLABLE ", Types.INTEGER, 32);
1300:                fields[10] = new Field("", "REMARKS", Types.CHAR, 32);
1301:                fields[11] = new Field("", "ATTR_DEF", Types.CHAR, 32);
1302:                fields[12] = new Field("", "SQL_DATA_TYPE", Types.INTEGER, 32);
1303:                fields[13] = new Field("", "SQL_DATETIME_SUB", Types.INTEGER,
1304:                        32);
1305:                fields[14] = new Field("", "CHAR_OCTET_LENGTH", Types.INTEGER,
1306:                        32);
1307:                fields[15] = new Field("", "ORDINAL_POSITION", Types.INTEGER,
1308:                        32);
1309:                fields[16] = new Field("", "IS_NULLABLE", Types.CHAR, 32);
1310:                fields[17] = new Field("", "SCOPE_CATALOG", Types.CHAR, 32);
1311:                fields[18] = new Field("", "SCOPE_SCHEMA", Types.CHAR, 32);
1312:                fields[19] = new Field("", "SCOPE_TABLE", Types.CHAR, 32);
1313:                fields[20] = new Field("", "SOURCE_DATA_TYPE", Types.SMALLINT,
1314:                        32);
1315:
1316:                return buildResultSet(fields, new ArrayList());
1317:            }
1318:
1319:            /**
1320:             * Get a description of a table's optimal set of columns that uniquely
1321:             * identifies a row. They are ordered by SCOPE.
1322:             * <P>
1323:             * Each column description has the following columns:
1324:             * <OL>
1325:             * <li> <B>SCOPE</B> short => actual scope of result
1326:             * <UL>
1327:             * <li> bestRowTemporary - very temporary, while using row </li>
1328:             * <li> bestRowTransaction - valid for remainder of current transaction
1329:             * </li>
1330:             * <li> bestRowSession - valid for remainder of current session </li>
1331:             * </ul>
1332:             * </li>
1333:             * <li> <B>COLUMN_NAME</B> String => column name </li>
1334:             * <li> <B>DATA_TYPE</B> short => SQL data type from java.sql.Types </li>
1335:             * <li> <B>TYPE_NAME</B> String => Data source dependent type name </li>
1336:             * <li> <B>COLUMN_SIZE</B> int => precision </li>
1337:             * <li> <B>BUFFER_LENGTH</B> int => not used </li>
1338:             * <li> <B>DECIMAL_DIGITS</B> short => scale </li>
1339:             * <li> <B>PSEUDO_COLUMN</B> short => is this a pseudo column like an
1340:             * Oracle ROWID
1341:             * <UL>
1342:             * <li> bestRowUnknown - may or may not be pseudo column </li>
1343:             * <li> bestRowNotPseudo - is NOT a pseudo column </li>
1344:             * <li> bestRowPseudo - is a pseudo column </li>
1345:             * </ul>
1346:             * </li>
1347:             * </ol>
1348:             * </p>
1349:             * 
1350:             * @param catalog
1351:             *            a catalog name; "" retrieves those without a catalog
1352:             * @param schema
1353:             *            a schema name; "" retrieves those without a schema
1354:             * @param table
1355:             *            a table name
1356:             * @param scope
1357:             *            the scope of interest; use same values as SCOPE
1358:             * @param nullable
1359:             *            include columns that are nullable?
1360:             * @return ResultSet each row is a column description
1361:             * @throws SQLException
1362:             *             DOCUMENT ME!
1363:             */
1364:            public java.sql.ResultSet getBestRowIdentifier(String catalog,
1365:                    String schema, final String table, int scope,
1366:                    boolean nullable) throws SQLException {
1367:                if (table == null) {
1368:                    throw SQLError.createSQLException("Table not specified.",
1369:                            SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
1370:                }
1371:
1372:                Field[] fields = new Field[8];
1373:                fields[0] = new Field("", "SCOPE", Types.SMALLINT, 5);
1374:                fields[1] = new Field("", "COLUMN_NAME", Types.CHAR, 32);
1375:                fields[2] = new Field("", "DATA_TYPE", Types.SMALLINT, 32);
1376:                fields[3] = new Field("", "TYPE_NAME", Types.CHAR, 32);
1377:                fields[4] = new Field("", "COLUMN_SIZE", Types.INTEGER, 10);
1378:                fields[5] = new Field("", "BUFFER_LENGTH", Types.INTEGER, 10);
1379:                fields[6] = new Field("", "DECIMAL_DIGITS", Types.INTEGER, 10);
1380:                fields[7] = new Field("", "PSEUDO_COLUMN", Types.SMALLINT, 5);
1381:
1382:                final ArrayList rows = new ArrayList();
1383:                final Statement stmt = this .conn.getMetadataSafeStatement();
1384:
1385:                try {
1386:
1387:                    new IterateBlock(getCatalogIterator(catalog)) {
1388:                        void forEach(Object catalogStr) throws SQLException {
1389:                            ResultSet results = null;
1390:
1391:                            try {
1392:                                StringBuffer queryBuf = new StringBuffer(
1393:                                        "SHOW COLUMNS FROM ");
1394:                                queryBuf.append(quotedId);
1395:                                queryBuf.append(table);
1396:                                queryBuf.append(quotedId);
1397:                                queryBuf.append(" FROM ");
1398:                                queryBuf.append(quotedId);
1399:                                queryBuf.append(catalogStr.toString());
1400:                                queryBuf.append(quotedId);
1401:
1402:                                results = stmt
1403:                                        .executeQuery(queryBuf.toString());
1404:
1405:                                while (results.next()) {
1406:                                    String keyType = results.getString("Key");
1407:
1408:                                    if (keyType != null) {
1409:                                        if (StringUtils.startsWithIgnoreCase(
1410:                                                keyType, "PRI")) {
1411:                                            byte[][] rowVal = new byte[8][];
1412:                                            rowVal[0] = Integer
1413:                                                    .toString(
1414:                                                            java.sql.DatabaseMetaData.bestRowSession)
1415:                                                    .getBytes();
1416:                                            rowVal[1] = results
1417:                                                    .getBytes("Field");
1418:
1419:                                            String type = results
1420:                                                    .getString("Type");
1421:                                            int size = MysqlIO.getMaxBuf();
1422:                                            int decimals = 0;
1423:
1424:                                            /*
1425:                                             * Parse the Type column from MySQL
1426:                                             */
1427:                                            if (type.indexOf("enum") != -1) {
1428:                                                String temp = type.substring(
1429:                                                        type.indexOf("("), type
1430:                                                                .indexOf(")"));
1431:                                                java.util.StringTokenizer tokenizer = new java.util.StringTokenizer(
1432:                                                        temp, ",");
1433:                                                int maxLength = 0;
1434:
1435:                                                while (tokenizer
1436:                                                        .hasMoreTokens()) {
1437:                                                    maxLength = Math
1438:                                                            .max(
1439:                                                                    maxLength,
1440:                                                                    (tokenizer
1441:                                                                            .nextToken()
1442:                                                                            .length() - 2));
1443:                                                }
1444:
1445:                                                size = maxLength;
1446:                                                decimals = 0;
1447:                                                type = "enum";
1448:                                            } else if (type.indexOf("(") != -1) {
1449:                                                if (type.indexOf(",") != -1) {
1450:                                                    size = Integer
1451:                                                            .parseInt(type
1452:                                                                    .substring(
1453:                                                                            type
1454:                                                                                    .indexOf("(") + 1,
1455:                                                                            type
1456:                                                                                    .indexOf(",")));
1457:                                                    decimals = Integer
1458:                                                            .parseInt(type
1459:                                                                    .substring(
1460:                                                                            type
1461:                                                                                    .indexOf(",") + 1,
1462:                                                                            type
1463:                                                                                    .indexOf(")")));
1464:                                                } else {
1465:                                                    size = Integer
1466:                                                            .parseInt(type
1467:                                                                    .substring(
1468:                                                                            type
1469:                                                                                    .indexOf("(") + 1,
1470:                                                                            type
1471:                                                                                    .indexOf(")")));
1472:                                                }
1473:
1474:                                                type = type.substring(0, type
1475:                                                        .indexOf("("));
1476:                                            }
1477:
1478:                                            rowVal[2] = s2b(String
1479:                                                    .valueOf(MysqlDefs
1480:                                                            .mysqlToJavaType(type)));
1481:                                            rowVal[3] = s2b(type);
1482:                                            rowVal[4] = Integer.toString(
1483:                                                    size + decimals).getBytes();
1484:                                            rowVal[5] = Integer.toString(
1485:                                                    size + decimals).getBytes();
1486:                                            rowVal[6] = Integer.toString(
1487:                                                    decimals).getBytes();
1488:                                            rowVal[7] = Integer
1489:                                                    .toString(
1490:                                                            java.sql.DatabaseMetaData.bestRowNotPseudo)
1491:                                                    .getBytes();
1492:
1493:                                            rows.add(new ByteArrayRow(rowVal));
1494:                                        }
1495:                                    }
1496:                                }
1497:
1498:                            } finally {
1499:                                if (results != null) {
1500:                                    try {
1501:                                        results.close();
1502:                                    } catch (Exception ex) {
1503:                                        ;
1504:                                    }
1505:
1506:                                    results = null;
1507:                                }
1508:                            }
1509:                        }
1510:                    }.doForAll();
1511:                } finally {
1512:                    if (stmt != null) {
1513:                        stmt.close();
1514:                    }
1515:                }
1516:
1517:                java.sql.ResultSet results = buildResultSet(fields, rows);
1518:
1519:                return results;
1520:
1521:            }
1522:
1523:            /*
1524:             * * Each row in the ResultSet is a parameter desription or column
1525:             * description with the following fields: <OL> <li> <B>PROCEDURE_CAT</B>
1526:             * String => procedure catalog (may be null) </li> <li> <B>PROCEDURE_SCHEM</B>
1527:             * String => procedure schema (may be null) </li> <li> <B>PROCEDURE_NAME</B>
1528:             * String => procedure name </li> <li> <B>COLUMN_NAME</B> String =>
1529:             * column/parameter name </li> <li> <B>COLUMN_TYPE</B> Short => kind of
1530:             * column/parameter: <UL> <li> procedureColumnUnknown - nobody knows </li>
1531:             * <li> procedureColumnIn - IN parameter </li> <li> procedureColumnInOut -
1532:             * INOUT parameter </li> <li> procedureColumnOut - OUT parameter </li> <li>
1533:             * procedureColumnReturn - procedure return value </li> <li>
1534:             * procedureColumnResult - result column in ResultSet </li> </ul> </li> <li>
1535:             * <B>DATA_TYPE</B> short => SQL type from java.sql.Types </li> <li>
1536:             * <B>TYPE_NAME</B> String => SQL type name </li> <li> <B>PRECISION</B>
1537:             * int => precision </li> <li> <B>LENGTH</B> int => length in bytes of data
1538:             * </li> <li> <B>SCALE</B> short => scale </li> <li> <B>RADIX</B> short =>
1539:             * radix </li> <li> <B>NULLABLE</B> short => can it contain NULL? <UL> <li>
1540:             * procedureNoNulls - does not allow NULL values </li> <li>
1541:             * procedureNullable - allows NULL values </li> <li>
1542:             * procedureNullableUnknown - nullability unknown </li> </ul> </li> <li>
1543:             * <B>REMARKS</B> String => comment describing parameter/column </li> </ol>
1544:             * </p> <P> <B>Note:</B> Some databases may not return the column
1545:             * descriptions for a procedure. Additional columns beyond REMARKS can be
1546:             * defined by the database. </p> @param catalog a catalog name; "" retrieves
1547:             * those without a catalog @param schemaPattern a schema name pattern; ""
1548:             * retrieves those without a schema @param procedureNamePattern a procedure
1549:             * name pattern @param columnNamePattern a column name pattern @return
1550:             * ResultSet each row is a stored procedure parameter or column description
1551:             * @throws SQLException if a database access error occurs
1552:             * 
1553:             * @see #getSearchStringEscape
1554:             */
1555:            private void getCallStmtParameterTypes(String catalog,
1556:                    String procName, String parameterNamePattern,
1557:                    List resultRows) throws SQLException {
1558:                getCallStmtParameterTypes(catalog, procName,
1559:                        parameterNamePattern, resultRows, false);
1560:            }
1561:
1562:            private void getCallStmtParameterTypes(String catalog,
1563:                    String procName, String parameterNamePattern,
1564:                    List resultRows, boolean forGetFunctionColumns)
1565:                    throws SQLException {
1566:                java.sql.Statement paramRetrievalStmt = null;
1567:                java.sql.ResultSet paramRetrievalRs = null;
1568:
1569:                if (parameterNamePattern == null) {
1570:                    if (this .conn.getNullNamePatternMatchesAll()) {
1571:                        parameterNamePattern = "%";
1572:                    } else {
1573:                        throw SQLError
1574:                                .createSQLException(
1575:                                        "Parameter/Column name pattern can not be NULL or empty.",
1576:                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
1577:                    }
1578:                }
1579:
1580:                byte[] procNameAsBytes = null;
1581:
1582:                try {
1583:                    procNameAsBytes = procName.getBytes("UTF-8");
1584:                } catch (UnsupportedEncodingException ueEx) {
1585:                    procNameAsBytes = s2b(procName);
1586:
1587:                    // Set all fields to connection encoding
1588:                }
1589:
1590:                String quoteChar = getIdentifierQuoteString();
1591:
1592:                String parameterDef = null;
1593:
1594:                boolean isProcedureInAnsiMode = false;
1595:                String storageDefnDelims = null;
1596:                String storageDefnClosures = null;
1597:
1598:                try {
1599:                    paramRetrievalStmt = this .conn.getMetadataSafeStatement();
1600:
1601:                    if (this .conn.lowerCaseTableNames() && catalog != null
1602:                            && catalog.length() != 0) {
1603:                        // Workaround for bug in server wrt. to 
1604:                        // SHOW CREATE PROCEDURE not respecting
1605:                        // lower-case table names
1606:
1607:                        String oldCatalog = this .conn.getCatalog();
1608:                        ResultSet rs = null;
1609:
1610:                        try {
1611:                            this .conn.setCatalog(catalog);
1612:                            rs = paramRetrievalStmt
1613:                                    .executeQuery("SELECT DATABASE()");
1614:                            rs.next();
1615:
1616:                            catalog = rs.getString(1);
1617:
1618:                        } finally {
1619:
1620:                            this .conn.setCatalog(oldCatalog);
1621:
1622:                            if (rs != null) {
1623:                                rs.close();
1624:                            }
1625:                        }
1626:                    }
1627:
1628:                    if (paramRetrievalStmt.getMaxRows() != 0) {
1629:                        paramRetrievalStmt.setMaxRows(0);
1630:                    }
1631:
1632:                    int dotIndex = -1;
1633:
1634:                    if (!" ".equals(quoteChar)) {
1635:                        dotIndex = StringUtils.indexOfIgnoreCaseRespectQuotes(
1636:                                0, procName, ".", quoteChar.charAt(0),
1637:                                !this .conn.isNoBackslashEscapesSet());
1638:                    } else {
1639:                        dotIndex = procName.indexOf(".");
1640:                    }
1641:
1642:                    String dbName = null;
1643:
1644:                    if (dotIndex != -1 && (dotIndex + 1) < procName.length()) {
1645:                        dbName = procName.substring(0, dotIndex);
1646:                        procName = procName.substring(dotIndex + 1);
1647:                    } else {
1648:                        dbName = catalog;
1649:                    }
1650:
1651:                    StringBuffer procNameBuf = new StringBuffer();
1652:
1653:                    if (dbName != null) {
1654:                        if (!" ".equals(quoteChar)
1655:                                && !dbName.startsWith(quoteChar)) {
1656:                            procNameBuf.append(quoteChar);
1657:                        }
1658:
1659:                        procNameBuf.append(dbName);
1660:
1661:                        if (!" ".equals(quoteChar)
1662:                                && !dbName.startsWith(quoteChar)) {
1663:                            procNameBuf.append(quoteChar);
1664:                        }
1665:
1666:                        procNameBuf.append(".");
1667:                    }
1668:
1669:                    boolean procNameIsNotQuoted = !procName
1670:                            .startsWith(quoteChar);
1671:
1672:                    if (!" ".equals(quoteChar) && procNameIsNotQuoted) {
1673:                        procNameBuf.append(quoteChar);
1674:                    }
1675:
1676:                    procNameBuf.append(procName);
1677:
1678:                    if (!" ".equals(quoteChar) && procNameIsNotQuoted) {
1679:                        procNameBuf.append(quoteChar);
1680:                    }
1681:
1682:                    boolean parsingFunction = false;
1683:
1684:                    try {
1685:                        paramRetrievalRs = paramRetrievalStmt
1686:                                .executeQuery("SHOW CREATE PROCEDURE "
1687:                                        + procNameBuf.toString());
1688:                        parsingFunction = false;
1689:                    } catch (SQLException sqlEx) {
1690:                        paramRetrievalRs = paramRetrievalStmt
1691:                                .executeQuery("SHOW CREATE FUNCTION "
1692:                                        + procNameBuf.toString());
1693:                        parsingFunction = true;
1694:                    }
1695:
1696:                    if (paramRetrievalRs.next()) {
1697:                        String procedureDef = parsingFunction ? paramRetrievalRs
1698:                                .getString("Create Function")
1699:                                : paramRetrievalRs
1700:                                        .getString("Create Procedure");
1701:
1702:                        if (procedureDef == null || procedureDef.length() == 0) {
1703:                            throw SQLError
1704:                                    .createSQLException(
1705:                                            "User does not have access to metadata required to determine "
1706:                                                    + "stored procedure parameter types. If rights can not be granted, configure connection with \"noAccessToProcedureBodies=true\" "
1707:                                                    + "to have driver generate parameters that represent INOUT strings irregardless of actual parameter types.",
1708:                                            SQLError.SQL_STATE_GENERAL_ERROR);
1709:                        }
1710:
1711:                        try {
1712:                            String sqlMode = paramRetrievalRs
1713:                                    .getString("sql_mode");
1714:
1715:                            if (StringUtils.indexOfIgnoreCase(sqlMode, "ANSI") != -1) {
1716:                                isProcedureInAnsiMode = true;
1717:                            }
1718:                        } catch (SQLException sqlEx) {
1719:                            // doesn't exist
1720:                        }
1721:
1722:                        String identifierMarkers = isProcedureInAnsiMode ? "`\""
1723:                                : "`";
1724:                        String identifierAndStringMarkers = "'"
1725:                                + identifierMarkers;
1726:                        storageDefnDelims = "(" + identifierMarkers;
1727:                        storageDefnClosures = ")" + identifierMarkers;
1728:
1729:                        // sanitize/normalize by stripping out comments
1730:                        procedureDef = StringUtils.stripComments(procedureDef,
1731:                                identifierAndStringMarkers,
1732:                                identifierAndStringMarkers, true, false, true,
1733:                                true);
1734:
1735:                        int openParenIndex = StringUtils
1736:                                .indexOfIgnoreCaseRespectQuotes(0,
1737:                                        procedureDef, "(", quoteChar.charAt(0),
1738:                                        !this .conn.isNoBackslashEscapesSet());
1739:                        int endOfParamDeclarationIndex = 0;
1740:
1741:                        endOfParamDeclarationIndex = endPositionOfParameterDeclaration(
1742:                                openParenIndex, procedureDef, quoteChar);
1743:
1744:                        if (parsingFunction) {
1745:
1746:                            // Grab the return column since it needs
1747:                            // to go first in the output result set
1748:                            int returnsIndex = StringUtils
1749:                                    .indexOfIgnoreCaseRespectQuotes(0,
1750:                                            procedureDef, " RETURNS ",
1751:                                            quoteChar.charAt(0), !this .conn
1752:                                                    .isNoBackslashEscapesSet());
1753:
1754:                            int endReturnsDef = findEndOfReturnsClause(
1755:                                    procedureDef, quoteChar, returnsIndex);
1756:
1757:                            // Trim off whitespace after "RETURNS"
1758:
1759:                            int declarationStart = returnsIndex
1760:                                    + "RETURNS ".length();
1761:
1762:                            while (declarationStart < procedureDef.length()) {
1763:                                if (Character.isWhitespace(procedureDef
1764:                                        .charAt(declarationStart))) {
1765:                                    declarationStart++;
1766:                                } else {
1767:                                    break;
1768:                                }
1769:                            }
1770:
1771:                            String returnsDefn = procedureDef.substring(
1772:                                    declarationStart, endReturnsDef).trim();
1773:                            TypeDescriptor returnDescriptor = new TypeDescriptor(
1774:                                    returnsDefn, null);
1775:
1776:                            resultRows
1777:                                    .add(convertTypeDescriptorToProcedureRow(
1778:                                            procNameAsBytes, "", false, false,
1779:                                            true, returnDescriptor,
1780:                                            forGetFunctionColumns, 0));
1781:                        }
1782:
1783:                        if ((openParenIndex == -1)
1784:                                || (endOfParamDeclarationIndex == -1)) {
1785:                            // parse error?
1786:                            throw SQLError
1787:                                    .createSQLException(
1788:                                            "Internal error when parsing callable statement metadata",
1789:                                            SQLError.SQL_STATE_GENERAL_ERROR);
1790:                        }
1791:
1792:                        parameterDef = procedureDef.substring(
1793:                                openParenIndex + 1, endOfParamDeclarationIndex);
1794:                    }
1795:                } finally {
1796:                    SQLException sqlExRethrow = null;
1797:
1798:                    if (paramRetrievalRs != null) {
1799:                        try {
1800:                            paramRetrievalRs.close();
1801:                        } catch (SQLException sqlEx) {
1802:                            sqlExRethrow = sqlEx;
1803:                        }
1804:
1805:                        paramRetrievalRs = null;
1806:                    }
1807:
1808:                    if (paramRetrievalStmt != null) {
1809:                        try {
1810:                            paramRetrievalStmt.close();
1811:                        } catch (SQLException sqlEx) {
1812:                            sqlExRethrow = sqlEx;
1813:                        }
1814:
1815:                        paramRetrievalStmt = null;
1816:                    }
1817:
1818:                    if (sqlExRethrow != null) {
1819:                        throw sqlExRethrow;
1820:                    }
1821:                }
1822:
1823:                if (parameterDef != null) {
1824:                    int ordinal = 1;
1825:
1826:                    List parseList = StringUtils.split(parameterDef, ",",
1827:                            storageDefnDelims, storageDefnClosures, true);
1828:
1829:                    int parseListLen = parseList.size();
1830:
1831:                    for (int i = 0; i < parseListLen; i++) {
1832:                        String declaration = (String) parseList.get(i);
1833:
1834:                        if (declaration.trim().length() == 0) {
1835:                            break; // no parameters actually declared, but whitespace spans lines
1836:                        }
1837:
1838:                        StringTokenizer declarationTok = new StringTokenizer(
1839:                                declaration, " \t");
1840:
1841:                        String paramName = null;
1842:                        boolean isOutParam = false;
1843:                        boolean isInParam = false;
1844:
1845:                        if (declarationTok.hasMoreTokens()) {
1846:                            String possibleParamName = declarationTok
1847:                                    .nextToken();
1848:
1849:                            if (possibleParamName.equalsIgnoreCase("OUT")) {
1850:                                isOutParam = true;
1851:
1852:                                if (declarationTok.hasMoreTokens()) {
1853:                                    paramName = declarationTok.nextToken();
1854:                                } else {
1855:                                    throw SQLError
1856:                                            .createSQLException(
1857:                                                    "Internal error when parsing callable statement metadata (missing parameter name)",
1858:                                                    SQLError.SQL_STATE_GENERAL_ERROR);
1859:                                }
1860:                            } else if (possibleParamName
1861:                                    .equalsIgnoreCase("INOUT")) {
1862:                                isOutParam = true;
1863:                                isInParam = true;
1864:
1865:                                if (declarationTok.hasMoreTokens()) {
1866:                                    paramName = declarationTok.nextToken();
1867:                                } else {
1868:                                    throw SQLError
1869:                                            .createSQLException(
1870:                                                    "Internal error when parsing callable statement metadata (missing parameter name)",
1871:                                                    SQLError.SQL_STATE_GENERAL_ERROR);
1872:                                }
1873:                            } else if (possibleParamName.equalsIgnoreCase("IN")) {
1874:                                isOutParam = false;
1875:                                isInParam = true;
1876:
1877:                                if (declarationTok.hasMoreTokens()) {
1878:                                    paramName = declarationTok.nextToken();
1879:                                } else {
1880:                                    throw SQLError
1881:                                            .createSQLException(
1882:                                                    "Internal error when parsing callable statement metadata (missing parameter name)",
1883:                                                    SQLError.SQL_STATE_GENERAL_ERROR);
1884:                                }
1885:                            } else {
1886:                                isOutParam = false;
1887:                                isInParam = true;
1888:
1889:                                paramName = possibleParamName;
1890:                            }
1891:
1892:                            TypeDescriptor typeDesc = null;
1893:
1894:                            if (declarationTok.hasMoreTokens()) {
1895:                                StringBuffer typeInfoBuf = new StringBuffer(
1896:                                        declarationTok.nextToken());
1897:
1898:                                while (declarationTok.hasMoreTokens()) {
1899:                                    typeInfoBuf.append(" ");
1900:                                    typeInfoBuf.append(declarationTok
1901:                                            .nextToken());
1902:                                }
1903:
1904:                                String typeInfo = typeInfoBuf.toString();
1905:
1906:                                typeDesc = new TypeDescriptor(typeInfo, null);
1907:                            } else {
1908:                                throw SQLError
1909:                                        .createSQLException(
1910:                                                "Internal error when parsing callable statement metadata (missing parameter type)",
1911:                                                SQLError.SQL_STATE_GENERAL_ERROR);
1912:                            }
1913:
1914:                            if ((paramName.startsWith("`") && paramName
1915:                                    .endsWith("`"))
1916:                                    || (isProcedureInAnsiMode
1917:                                            && paramName.startsWith("\"") && paramName
1918:                                            .endsWith("\""))) {
1919:                                paramName = paramName.substring(1, paramName
1920:                                        .length() - 1);
1921:                            }
1922:
1923:                            int wildCompareRes = StringUtils.wildCompare(
1924:                                    paramName, parameterNamePattern);
1925:
1926:                            if (wildCompareRes != StringUtils.WILD_COMPARE_NO_MATCH) {
1927:                                ResultSetRow row = convertTypeDescriptorToProcedureRow(
1928:                                        procNameAsBytes, paramName, isOutParam,
1929:                                        isInParam, false, typeDesc,
1930:                                        forGetFunctionColumns, ordinal++);
1931:
1932:                                resultRows.add(row);
1933:                            }
1934:                        } else {
1935:                            throw SQLError
1936:                                    .createSQLException(
1937:                                            "Internal error when parsing callable statement metadata (unknown output from 'SHOW CREATE PROCEDURE')",
1938:                                            SQLError.SQL_STATE_GENERAL_ERROR);
1939:                        }
1940:                    }
1941:                } else {
1942:                    // Is this an error? JDBC spec doesn't make it clear if stored
1943:                    // procedure doesn't
1944:                    // exist, is it an error....
1945:                }
1946:            }
1947:
1948:            /**
1949:             * Finds the end of the parameter declaration from the output of "SHOW
1950:             * CREATE PROCEDURE".
1951:             * 
1952:             * @param beginIndex
1953:             *            should be the index of the procedure body that contains the
1954:             *            first "(".
1955:             * @param procedureDef
1956:             *            the procedure body
1957:             * @param quoteChar
1958:             *            the identifier quote character in use
1959:             * @return the ending index of the parameter declaration, not including the
1960:             *         closing ")"
1961:             * @throws SQLException
1962:             *             if a parse error occurs.
1963:             */
1964:            private int endPositionOfParameterDeclaration(int beginIndex,
1965:                    String procedureDef, String quoteChar) throws SQLException {
1966:                int currentPos = beginIndex + 1;
1967:                int parenDepth = 1; // counting the first openParen
1968:
1969:                while (parenDepth > 0 && currentPos < procedureDef.length()) {
1970:                    int closedParenIndex = StringUtils
1971:                            .indexOfIgnoreCaseRespectQuotes(currentPos,
1972:                                    procedureDef, ")", quoteChar.charAt(0),
1973:                                    !this .conn.isNoBackslashEscapesSet());
1974:
1975:                    if (closedParenIndex != -1) {
1976:                        int nextOpenParenIndex = StringUtils
1977:                                .indexOfIgnoreCaseRespectQuotes(currentPos,
1978:                                        procedureDef, "(", quoteChar.charAt(0),
1979:                                        !this .conn.isNoBackslashEscapesSet());
1980:
1981:                        if (nextOpenParenIndex != -1
1982:                                && nextOpenParenIndex < closedParenIndex) {
1983:                            parenDepth++;
1984:                            currentPos = closedParenIndex + 1; // set after closed
1985:                            // paren that increases
1986:                            // depth
1987:                        } else {
1988:                            parenDepth--;
1989:                            currentPos = closedParenIndex; // start search from same
1990:                            // position
1991:                        }
1992:                    } else {
1993:                        // we should always get closed paren of some sort
1994:                        throw SQLError
1995:                                .createSQLException(
1996:                                        "Internal error when parsing callable statement metadata",
1997:                                        SQLError.SQL_STATE_GENERAL_ERROR);
1998:                    }
1999:                }
2000:
2001:                return currentPos;
2002:            }
2003:
2004:            /**
2005:             * Finds the end of the RETURNS clause for SQL Functions by using any of the
2006:             * keywords allowed after the RETURNS clause, or a label.
2007:             * 
2008:             * @param procedureDefn
2009:             *            the function body containing the definition of the function
2010:             * @param quoteChar
2011:             *            the identifier quote string in use
2012:             * @param positionOfReturnKeyword
2013:             *            the position of "RETRUNS" in the definition
2014:             * @return the end of the returns clause
2015:             * @throws SQLException
2016:             *             if a parse error occurs
2017:             */
2018:            private int findEndOfReturnsClause(String procedureDefn,
2019:                    String quoteChar, int positionOfReturnKeyword)
2020:                    throws SQLException {
2021:                /*
2022:                 * characteristic: LANGUAGE SQL | [NOT] DETERMINISTIC | { CONTAINS SQL |
2023:                 * NO SQL | READS SQL DATA | MODIFIES SQL DATA } | SQL SECURITY {
2024:                 * DEFINER | INVOKER } | COMMENT 'string'
2025:                 */
2026:
2027:                String[] tokens = new String[] { "LANGUAGE", "NOT",
2028:                        "DETERMINISTIC", "CONTAINS", "NO", "READ", "MODIFIES",
2029:                        "SQL", "COMMENT", "BEGIN", "RETURN" };
2030:
2031:                int startLookingAt = positionOfReturnKeyword
2032:                        + "RETURNS".length() + 1;
2033:
2034:                for (int i = 0; i < tokens.length; i++) {
2035:                    int endOfReturn = StringUtils
2036:                            .indexOfIgnoreCaseRespectQuotes(startLookingAt,
2037:                                    procedureDefn, tokens[i], quoteChar
2038:                                            .charAt(0), !this .conn
2039:                                            .isNoBackslashEscapesSet());
2040:
2041:                    if (endOfReturn != -1) {
2042:                        return endOfReturn;
2043:                    }
2044:                }
2045:
2046:                // Label?
2047:                int endOfReturn = StringUtils.indexOfIgnoreCaseRespectQuotes(
2048:                        startLookingAt, procedureDefn, ":",
2049:                        quoteChar.charAt(0), !this .conn
2050:                                .isNoBackslashEscapesSet());
2051:
2052:                if (endOfReturn != -1) {
2053:                    // seek back until whitespace
2054:                    for (int i = endOfReturn; i > 0; i--) {
2055:                        if (Character.isWhitespace(procedureDefn.charAt(i))) {
2056:                            return i;
2057:                        }
2058:                    }
2059:                }
2060:
2061:                // We can't parse it.
2062:
2063:                throw SQLError
2064:                        .createSQLException(
2065:                                "Internal error when parsing callable statement metadata",
2066:                                SQLError.SQL_STATE_GENERAL_ERROR);
2067:            }
2068:
2069:            /**
2070:             * Parses the cascade option string and returns the DBMD constant that
2071:             * represents it (for deletes)
2072:             * 
2073:             * @param cascadeOptions
2074:             *            the comment from 'SHOW TABLE STATUS'
2075:             * @return the DBMD constant that represents the cascade option
2076:             */
2077:            private int getCascadeDeleteOption(String cascadeOptions) {
2078:                int onDeletePos = cascadeOptions.indexOf("ON DELETE");
2079:
2080:                if (onDeletePos != -1) {
2081:                    String deleteOptions = cascadeOptions.substring(
2082:                            onDeletePos, cascadeOptions.length());
2083:
2084:                    if (deleteOptions.startsWith("ON DELETE CASCADE")) {
2085:                        return java.sql.DatabaseMetaData.importedKeyCascade;
2086:                    } else if (deleteOptions.startsWith("ON DELETE SET NULL")) {
2087:                        return java.sql.DatabaseMetaData.importedKeySetNull;
2088:                    } else if (deleteOptions.startsWith("ON DELETE RESTRICT")) {
2089:                        return java.sql.DatabaseMetaData.importedKeyRestrict;
2090:                    } else if (deleteOptions.startsWith("ON DELETE NO ACTION")) {
2091:                        return java.sql.DatabaseMetaData.importedKeyNoAction;
2092:                    }
2093:                }
2094:
2095:                return java.sql.DatabaseMetaData.importedKeyNoAction;
2096:            }
2097:
2098:            /**
2099:             * Parses the cascade option string and returns the DBMD constant that
2100:             * represents it (for Updates)
2101:             * 
2102:             * @param cascadeOptions
2103:             *            the comment from 'SHOW TABLE STATUS'
2104:             * @return the DBMD constant that represents the cascade option
2105:             */
2106:            private int getCascadeUpdateOption(String cascadeOptions) {
2107:                int onUpdatePos = cascadeOptions.indexOf("ON UPDATE");
2108:
2109:                if (onUpdatePos != -1) {
2110:                    String updateOptions = cascadeOptions.substring(
2111:                            onUpdatePos, cascadeOptions.length());
2112:
2113:                    if (updateOptions.startsWith("ON UPDATE CASCADE")) {
2114:                        return java.sql.DatabaseMetaData.importedKeyCascade;
2115:                    } else if (updateOptions.startsWith("ON UPDATE SET NULL")) {
2116:                        return java.sql.DatabaseMetaData.importedKeySetNull;
2117:                    } else if (updateOptions.startsWith("ON UPDATE RESTRICT")) {
2118:                        return java.sql.DatabaseMetaData.importedKeyRestrict;
2119:                    } else if (updateOptions.startsWith("ON UPDATE NO ACTION")) {
2120:                        return java.sql.DatabaseMetaData.importedKeyNoAction;
2121:                    }
2122:                }
2123:
2124:                return java.sql.DatabaseMetaData.importedKeyNoAction;
2125:            }
2126:
2127:            protected IteratorWithCleanup getCatalogIterator(String catalogSpec)
2128:                    throws SQLException {
2129:                IteratorWithCleanup allCatalogsIter;
2130:                if (catalogSpec != null) {
2131:                    if (!catalogSpec.equals("")) {
2132:                        allCatalogsIter = new SingleStringIterator(catalogSpec);
2133:                    } else {
2134:                        // legacy mode of operation
2135:                        allCatalogsIter = new SingleStringIterator(
2136:                                this .database);
2137:                    }
2138:                } else if (this .conn.getNullCatalogMeansCurrent()) {
2139:                    allCatalogsIter = new SingleStringIterator(this .database);
2140:                } else {
2141:                    allCatalogsIter = new ResultSetIterator(getCatalogs(), 1);
2142:                }
2143:
2144:                return allCatalogsIter;
2145:            }
2146:
2147:            /**
2148:             * Get the catalog names available in this database. The results are ordered
2149:             * by catalog name.
2150:             * <P>
2151:             * The catalog column is:
2152:             * <OL>
2153:             * <li> <B>TABLE_CAT</B> String => catalog name </li>
2154:             * </ol>
2155:             * </p>
2156:             * 
2157:             * @return ResultSet each row has a single String column that is a catalog
2158:             *         name
2159:             * @throws SQLException
2160:             *             DOCUMENT ME!
2161:             */
2162:            public java.sql.ResultSet getCatalogs() throws SQLException {
2163:                java.sql.ResultSet results = null;
2164:                java.sql.Statement stmt = null;
2165:
2166:                try {
2167:                    stmt = this .conn.createStatement();
2168:                    stmt.setEscapeProcessing(false);
2169:                    results = stmt.executeQuery("SHOW DATABASES");
2170:
2171:                    java.sql.ResultSetMetaData resultsMD = results
2172:                            .getMetaData();
2173:                    Field[] fields = new Field[1];
2174:                    fields[0] = new Field("", "TABLE_CAT", Types.VARCHAR,
2175:                            resultsMD.getColumnDisplaySize(1));
2176:
2177:                    ArrayList tuples = new ArrayList();
2178:
2179:                    while (results.next()) {
2180:                        byte[][] rowVal = new byte[1][];
2181:                        rowVal[0] = results.getBytes(1);
2182:                        tuples.add(new ByteArrayRow(rowVal));
2183:                    }
2184:
2185:                    return buildResultSet(fields, tuples);
2186:                } finally {
2187:                    if (results != null) {
2188:                        try {
2189:                            results.close();
2190:                        } catch (SQLException sqlEx) {
2191:                            AssertionFailedException.shouldNotHappen(sqlEx);
2192:                        }
2193:
2194:                        results = null;
2195:                    }
2196:
2197:                    if (stmt != null) {
2198:                        try {
2199:                            stmt.close();
2200:                        } catch (SQLException sqlEx) {
2201:                            AssertionFailedException.shouldNotHappen(sqlEx);
2202:                        }
2203:
2204:                        stmt = null;
2205:                    }
2206:                }
2207:            }
2208:
2209:            /**
2210:             * What's the separator between catalog and table name?
2211:             * 
2212:             * @return the separator string
2213:             * @throws SQLException
2214:             *             DOCUMENT ME!
2215:             */
2216:            public String getCatalogSeparator() throws SQLException {
2217:                return ".";
2218:            }
2219:
2220:            // ----------------------------------------------------------------------
2221:            // The following group of methods exposes various limitations
2222:            // based on the target database with the current driver.
2223:            // Unless otherwise specified, a result of zero means there is no
2224:            // limit, or the limit is not known.
2225:
2226:            /**
2227:             * What's the database vendor's preferred term for "catalog"?
2228:             * 
2229:             * @return the vendor term
2230:             * @throws SQLException
2231:             *             DOCUMENT ME!
2232:             */
2233:            public String getCatalogTerm() throws SQLException {
2234:                return "database";
2235:            }
2236:
2237:            /**
2238:             * Get a description of the access rights for a table's columns.
2239:             * <P>
2240:             * Only privileges matching the column name criteria are returned. They are
2241:             * ordered by COLUMN_NAME and PRIVILEGE.
2242:             * </p>
2243:             * <P>
2244:             * Each privilige description has the following columns:
2245:             * <OL>
2246:             * <li> <B>TABLE_CAT</B> String => table catalog (may be null) </li>
2247:             * <li> <B>TABLE_SCHEM</B> String => table schema (may be null) </li>
2248:             * <li> <B>TABLE_NAME</B> String => table name </li>
2249:             * <li> <B>COLUMN_NAME</B> String => column name </li>
2250:             * <li> <B>GRANTOR</B> => grantor of access (may be null) </li>
2251:             * <li> <B>GRANTEE</B> String => grantee of access </li>
2252:             * <li> <B>PRIVILEGE</B> String => name of access (SELECT, INSERT, UPDATE,
2253:             * REFRENCES, ...) </li>
2254:             * <li> <B>IS_GRANTABLE</B> String => "YES" if grantee is permitted to
2255:             * grant to others; "NO" if not; null if unknown </li>
2256:             * </ol>
2257:             * </p>
2258:             * 
2259:             * @param catalog
2260:             *            a catalog name; "" retrieves those without a catalog
2261:             * @param schema
2262:             *            a schema name; "" retrieves those without a schema
2263:             * @param table
2264:             *            a table name
2265:             * @param columnNamePattern
2266:             *            a column name pattern
2267:             * @return ResultSet each row is a column privilege description
2268:             * @throws SQLException
2269:             *             if a database access error occurs
2270:             * @see #getSearchStringEscape
2271:             */
2272:            public java.sql.ResultSet getColumnPrivileges(String catalog,
2273:                    String schema, String table, String columnNamePattern)
2274:                    throws SQLException {
2275:                Field[] fields = new Field[8];
2276:                fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 64);
2277:                fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 1);
2278:                fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 64);
2279:                fields[3] = new Field("", "COLUMN_NAME", Types.CHAR, 64);
2280:                fields[4] = new Field("", "GRANTOR", Types.CHAR, 77);
2281:                fields[5] = new Field("", "GRANTEE", Types.CHAR, 77);
2282:                fields[6] = new Field("", "PRIVILEGE", Types.CHAR, 64);
2283:                fields[7] = new Field("", "IS_GRANTABLE", Types.CHAR, 3);
2284:
2285:                StringBuffer grantQuery = new StringBuffer(
2286:                        "SELECT c.host, c.db, t.grantor, c.user, "
2287:                                + "c.table_name, c.column_name, c.column_priv "
2288:                                + "from mysql.columns_priv c, mysql.tables_priv t "
2289:                                + "where c.host = t.host and c.db = t.db and "
2290:                                + "c.table_name = t.table_name ");
2291:
2292:                if ((catalog != null) && (catalog.length() != 0)) {
2293:                    grantQuery.append(" AND c.db='");
2294:                    grantQuery.append(catalog);
2295:                    grantQuery.append("' ");
2296:                    ;
2297:                }
2298:
2299:                grantQuery.append(" AND c.table_name ='");
2300:                grantQuery.append(table);
2301:                grantQuery.append("' AND c.column_name like '");
2302:                grantQuery.append(columnNamePattern);
2303:                grantQuery.append("'");
2304:
2305:                Statement stmt = null;
2306:                ResultSet results = null;
2307:                ArrayList grantRows = new ArrayList();
2308:
2309:                try {
2310:                    stmt = this .conn.createStatement();
2311:                    stmt.setEscapeProcessing(false);
2312:                    results = stmt.executeQuery(grantQuery.toString());
2313:
2314:                    while (results.next()) {
2315:                        String host = results.getString(1);
2316:                        String db = results.getString(2);
2317:                        String grantor = results.getString(3);
2318:                        String user = results.getString(4);
2319:
2320:                        if ((user == null) || (user.length() == 0)) {
2321:                            user = "%";
2322:                        }
2323:
2324:                        StringBuffer fullUser = new StringBuffer(user);
2325:
2326:                        if ((host != null)
2327:                                && this .conn.getUseHostsInPrivileges()) {
2328:                            fullUser.append("@");
2329:                            fullUser.append(host);
2330:                        }
2331:
2332:                        String columnName = results.getString(6);
2333:                        String allPrivileges = results.getString(7);
2334:
2335:                        if (allPrivileges != null) {
2336:                            allPrivileges = allPrivileges
2337:                                    .toUpperCase(Locale.ENGLISH);
2338:
2339:                            StringTokenizer st = new StringTokenizer(
2340:                                    allPrivileges, ",");
2341:
2342:                            while (st.hasMoreTokens()) {
2343:                                String privilege = st.nextToken().trim();
2344:                                byte[][] tuple = new byte[8][];
2345:                                tuple[0] = s2b(db);
2346:                                tuple[1] = null;
2347:                                tuple[2] = s2b(table);
2348:                                tuple[3] = s2b(columnName);
2349:
2350:                                if (grantor != null) {
2351:                                    tuple[4] = s2b(grantor);
2352:                                } else {
2353:                                    tuple[4] = null;
2354:                                }
2355:
2356:                                tuple[5] = s2b(fullUser.toString());
2357:                                tuple[6] = s2b(privilege);
2358:                                tuple[7] = null;
2359:                                grantRows.add(new ByteArrayRow(tuple));
2360:                            }
2361:                        }
2362:                    }
2363:                } finally {
2364:                    if (results != null) {
2365:                        try {
2366:                            results.close();
2367:                        } catch (Exception ex) {
2368:                            ;
2369:                        }
2370:
2371:                        results = null;
2372:                    }
2373:
2374:                    if (stmt != null) {
2375:                        try {
2376:                            stmt.close();
2377:                        } catch (Exception ex) {
2378:                            ;
2379:                        }
2380:
2381:                        stmt = null;
2382:                    }
2383:                }
2384:
2385:                return buildResultSet(fields, grantRows);
2386:            }
2387:
2388:            /**
2389:             * Get a description of table columns available in a catalog.
2390:             * <P>
2391:             * Only column descriptions matching the catalog, schema, table and column
2392:             * name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME
2393:             * and ORDINAL_POSITION.
2394:             * </p>
2395:             * <P>
2396:             * Each column description has the following columns:
2397:             * <OL>
2398:             * <li> <B>TABLE_CAT</B> String => table catalog (may be null) </li>
2399:             * <li> <B>TABLE_SCHEM</B> String => table schema (may be null) </li>
2400:             * <li> <B>TABLE_NAME</B> String => table name </li>
2401:             * <li> <B>COLUMN_NAME</B> String => column name </li>
2402:             * <li> <B>DATA_TYPE</B> short => SQL type from java.sql.Types </li>
2403:             * <li> <B>TYPE_NAME</B> String => Data source dependent type name </li>
2404:             * <li> <B>COLUMN_SIZE</B> int => column size. For char or date types this
2405:             * is the maximum number of characters, for numeric or decimal types this is
2406:             * precision. </li>
2407:             * <li> <B>BUFFER_LENGTH</B> is not used. </li>
2408:             * <li> <B>DECIMAL_DIGITS</B> int => the number of fractional digits </li>
2409:             * <li> <B>NUM_PREC_RADIX</B> int => Radix (typically either 10 or 2) </li>
2410:             * <li> <B>NULLABLE</B> int => is NULL allowed?
2411:             * <UL>
2412:             * <li> columnNoNulls - might not allow NULL values </li>
2413:             * <li> columnNullable - definitely allows NULL values </li>
2414:             * <li> columnNullableUnknown - nullability unknown </li>
2415:             * </ul>
2416:             * </li>
2417:             * <li> <B>REMARKS</B> String => comment describing column (may be null)
2418:             * </li>
2419:             * <li> <B>COLUMN_DEF</B> String => default value (may be null) </li>
2420:             * <li> <B>SQL_DATA_TYPE</B> int => unused </li>
2421:             * <li> <B>SQL_DATETIME_SUB</B> int => unused </li>
2422:             * <li> <B>CHAR_OCTET_LENGTH</B> int => for char types the maximum number
2423:             * of bytes in the column </li>
2424:             * <li> <B>ORDINAL_POSITION</B> int => index of column in table (starting
2425:             * at 1) </li>
2426:             * <li> <B>IS_NULLABLE</B> String => "NO" means column definitely does not
2427:             * allow NULL values; "YES" means the column might allow NULL values. An
2428:             * empty string means nobody knows. </li>
2429:             * </ol>
2430:             * </p>
2431:             * 
2432:             * @param catalog
2433:             *            a catalog name; "" retrieves those without a catalog
2434:             * @param schemaPattern
2435:             *            a schema name pattern; "" retrieves those without a schema
2436:             * @param tableNamePattern
2437:             *            a table name pattern
2438:             * @param columnNamePattern
2439:             *            a column name pattern
2440:             * @return ResultSet each row is a column description
2441:             * @throws SQLException
2442:             *             if a database access error occurs
2443:             * @see #getSearchStringEscape
2444:             */
2445:            public java.sql.ResultSet getColumns(final String catalog,
2446:                    final String schemaPattern, final String tableNamePattern,
2447:                    String columnNamePattern) throws SQLException {
2448:
2449:                if (columnNamePattern == null) {
2450:                    if (this .conn.getNullNamePatternMatchesAll()) {
2451:                        columnNamePattern = "%";
2452:                    } else {
2453:                        throw SQLError
2454:                                .createSQLException(
2455:                                        "Column name pattern can not be NULL or empty.",
2456:                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2457:                    }
2458:                }
2459:
2460:                final String colPattern = columnNamePattern;
2461:
2462:                Field[] fields = new Field[23];
2463:                fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 255);
2464:                fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 0);
2465:                fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 255);
2466:                fields[3] = new Field("", "COLUMN_NAME", Types.CHAR, 32);
2467:                fields[4] = new Field("", "DATA_TYPE", Types.SMALLINT, 5);
2468:                fields[5] = new Field("", "TYPE_NAME", Types.CHAR, 16);
2469:                fields[6] = new Field("", "COLUMN_SIZE", Types.INTEGER, Integer
2470:                        .toString(Integer.MAX_VALUE).length());
2471:                fields[7] = new Field("", "BUFFER_LENGTH", Types.INTEGER, 10);
2472:                fields[8] = new Field("", "DECIMAL_DIGITS", Types.INTEGER, 10);
2473:                fields[9] = new Field("", "NUM_PREC_RADIX", Types.INTEGER, 10);
2474:                fields[10] = new Field("", "NULLABLE", Types.INTEGER, 10);
2475:                fields[11] = new Field("", "REMARKS", Types.CHAR, 0);
2476:                fields[12] = new Field("", "COLUMN_DEF", Types.CHAR, 0);
2477:                fields[13] = new Field("", "SQL_DATA_TYPE", Types.INTEGER, 10);
2478:                fields[14] = new Field("", "SQL_DATETIME_SUB", Types.INTEGER,
2479:                        10);
2480:                fields[15] = new Field("", "CHAR_OCTET_LENGTH", Types.INTEGER,
2481:                        Integer.toString(Integer.MAX_VALUE).length());
2482:                fields[16] = new Field("", "ORDINAL_POSITION", Types.INTEGER,
2483:                        10);
2484:                fields[17] = new Field("", "IS_NULLABLE", Types.CHAR, 3);
2485:                fields[18] = new Field("", "SCOPE_CATALOG", Types.CHAR, 255);
2486:                fields[19] = new Field("", "SCOPE_SCHEMA", Types.CHAR, 255);
2487:                fields[20] = new Field("", "SCOPE_TABLE", Types.CHAR, 255);
2488:                fields[21] = new Field("", "SOURCE_DATA_TYPE", Types.SMALLINT,
2489:                        10);
2490:                fields[22] = new Field("", "IS_AUTOINCREMENT", Types.CHAR, 3);
2491:
2492:                final ArrayList rows = new ArrayList();
2493:                final Statement stmt = this .conn.getMetadataSafeStatement();
2494:
2495:                try {
2496:
2497:                    new IterateBlock(getCatalogIterator(catalog)) {
2498:                        void forEach(Object catalogStr) throws SQLException {
2499:
2500:                            ArrayList tableNameList = new ArrayList();
2501:
2502:                            if (tableNamePattern == null) {
2503:                                // Select from all tables
2504:                                java.sql.ResultSet tables = null;
2505:
2506:                                try {
2507:                                    tables = getTables(catalog, schemaPattern,
2508:                                            "%", new String[0]);
2509:
2510:                                    while (tables.next()) {
2511:                                        String tableNameFromList = tables
2512:                                                .getString("TABLE_NAME");
2513:                                        tableNameList.add(tableNameFromList);
2514:                                    }
2515:                                } finally {
2516:                                    if (tables != null) {
2517:                                        try {
2518:                                            tables.close();
2519:                                        } catch (Exception sqlEx) {
2520:                                            AssertionFailedException
2521:                                                    .shouldNotHappen(sqlEx);
2522:                                        }
2523:
2524:                                        tables = null;
2525:                                    }
2526:                                }
2527:                            } else {
2528:                                java.sql.ResultSet tables = null;
2529:
2530:                                try {
2531:                                    tables = getTables(catalog, schemaPattern,
2532:                                            tableNamePattern, new String[0]);
2533:
2534:                                    while (tables.next()) {
2535:                                        String tableNameFromList = tables
2536:                                                .getString("TABLE_NAME");
2537:                                        tableNameList.add(tableNameFromList);
2538:                                    }
2539:                                } finally {
2540:                                    if (tables != null) {
2541:                                        try {
2542:                                            tables.close();
2543:                                        } catch (SQLException sqlEx) {
2544:                                            AssertionFailedException
2545:                                                    .shouldNotHappen(sqlEx);
2546:                                        }
2547:
2548:                                        tables = null;
2549:                                    }
2550:                                }
2551:                            }
2552:
2553:                            java.util.Iterator tableNames = tableNameList
2554:                                    .iterator();
2555:
2556:                            while (tableNames.hasNext()) {
2557:                                String tableName = (String) tableNames.next();
2558:
2559:                                ResultSet results = null;
2560:
2561:                                try {
2562:                                    StringBuffer queryBuf = new StringBuffer(
2563:                                            "SHOW ");
2564:
2565:                                    if (conn.versionMeetsMinimum(4, 1, 0)) {
2566:                                        queryBuf.append("FULL ");
2567:                                    }
2568:
2569:                                    queryBuf.append("COLUMNS FROM ");
2570:                                    queryBuf.append(quotedId);
2571:                                    queryBuf.append(tableName);
2572:                                    queryBuf.append(quotedId);
2573:                                    queryBuf.append(" FROM ");
2574:                                    queryBuf.append(quotedId);
2575:                                    queryBuf.append(catalogStr.toString());
2576:                                    queryBuf.append(quotedId);
2577:                                    queryBuf.append(" LIKE '");
2578:                                    queryBuf.append(colPattern);
2579:                                    queryBuf.append("'");
2580:
2581:                                    // Return correct ordinals if column name pattern is
2582:                                    // not '%'
2583:                                    // Currently, MySQL doesn't show enough data to do
2584:                                    // this, so we do it the 'hard' way...Once _SYSTEM
2585:                                    // tables are in, this should be much easier
2586:                                    boolean fixUpOrdinalsRequired = false;
2587:                                    Map ordinalFixUpMap = null;
2588:
2589:                                    if (!colPattern.equals("%")) {
2590:                                        fixUpOrdinalsRequired = true;
2591:
2592:                                        StringBuffer fullColumnQueryBuf = new StringBuffer(
2593:                                                "SHOW ");
2594:
2595:                                        if (conn.versionMeetsMinimum(4, 1, 0)) {
2596:                                            fullColumnQueryBuf.append("FULL ");
2597:                                        }
2598:
2599:                                        fullColumnQueryBuf
2600:                                                .append("COLUMNS FROM ");
2601:                                        fullColumnQueryBuf.append(quotedId);
2602:                                        fullColumnQueryBuf.append(tableName);
2603:                                        fullColumnQueryBuf.append(quotedId);
2604:                                        fullColumnQueryBuf.append(" FROM ");
2605:                                        fullColumnQueryBuf.append(quotedId);
2606:                                        fullColumnQueryBuf.append(catalogStr
2607:                                                .toString());
2608:                                        fullColumnQueryBuf.append(quotedId);
2609:
2610:                                        results = stmt
2611:                                                .executeQuery(fullColumnQueryBuf
2612:                                                        .toString());
2613:
2614:                                        ordinalFixUpMap = new HashMap();
2615:
2616:                                        int fullOrdinalPos = 1;
2617:
2618:                                        while (results.next()) {
2619:                                            String fullOrdColName = results
2620:                                                    .getString("Field");
2621:
2622:                                            ordinalFixUpMap
2623:                                                    .put(
2624:                                                            fullOrdColName,
2625:                                                            Constants
2626:                                                                    .integerValueOf(fullOrdinalPos++));
2627:                                        }
2628:                                    }
2629:
2630:                                    results = stmt.executeQuery(queryBuf
2631:                                            .toString());
2632:
2633:                                    int ordPos = 1;
2634:
2635:                                    while (results.next()) {
2636:                                        byte[][] rowVal = new byte[23][];
2637:                                        rowVal[0] = s2b(catalog); // TABLE_CAT
2638:                                        rowVal[1] = null; // TABLE_SCHEM (No schemas
2639:                                        // in MySQL)
2640:
2641:                                        rowVal[2] = s2b(tableName); // TABLE_NAME
2642:                                        rowVal[3] = results.getBytes("Field");
2643:
2644:                                        TypeDescriptor typeDesc = new TypeDescriptor(
2645:                                                results.getString("Type"),
2646:                                                results.getString("Null"));
2647:
2648:                                        rowVal[4] = Short.toString(
2649:                                                typeDesc.dataType).getBytes();
2650:
2651:                                        // DATA_TYPE (jdbc)
2652:                                        rowVal[5] = s2b(typeDesc.typeName); // TYPE_NAME
2653:                                        // (native)
2654:                                        rowVal[6] = typeDesc.columnSize == null ? null
2655:                                                : s2b(typeDesc.columnSize
2656:                                                        .toString());
2657:                                        rowVal[7] = s2b(Integer
2658:                                                .toString(typeDesc.bufferLength));
2659:                                        rowVal[8] = typeDesc.decimalDigits == null ? null
2660:                                                : s2b(typeDesc.decimalDigits
2661:                                                        .toString());
2662:                                        rowVal[9] = s2b(Integer
2663:                                                .toString(typeDesc.numPrecRadix));
2664:                                        rowVal[10] = s2b(Integer
2665:                                                .toString(typeDesc.nullability));
2666:
2667:                                        //
2668:                                        // Doesn't always have this field, depending on
2669:                                        // version
2670:                                        //
2671:                                        //
2672:                                        // REMARK column
2673:                                        //
2674:                                        try {
2675:                                            if (conn.versionMeetsMinimum(4, 1,
2676:                                                    0)) {
2677:                                                rowVal[11] = results
2678:                                                        .getBytes("Comment");
2679:                                            } else {
2680:                                                rowVal[11] = results
2681:                                                        .getBytes("Extra");
2682:                                            }
2683:                                        } catch (Exception E) {
2684:                                            rowVal[11] = new byte[0];
2685:                                        }
2686:
2687:                                        // COLUMN_DEF
2688:                                        rowVal[12] = results
2689:                                                .getBytes("Default");
2690:
2691:                                        rowVal[13] = new byte[] { (byte) '0' }; // SQL_DATA_TYPE
2692:                                        rowVal[14] = new byte[] { (byte) '0' }; // SQL_DATE_TIME_SUB
2693:
2694:                                        if (StringUtils.indexOfIgnoreCase(
2695:                                                typeDesc.typeName, "CHAR") != -1
2696:                                                || StringUtils
2697:                                                        .indexOfIgnoreCase(
2698:                                                                typeDesc.typeName,
2699:                                                                "BLOB") != -1
2700:                                                || StringUtils
2701:                                                        .indexOfIgnoreCase(
2702:                                                                typeDesc.typeName,
2703:                                                                "TEXT") != -1
2704:                                                || StringUtils
2705:                                                        .indexOfIgnoreCase(
2706:                                                                typeDesc.typeName,
2707:                                                                "BINARY") != -1) {
2708:                                            rowVal[15] = rowVal[6]; // CHAR_OCTET_LENGTH
2709:                                        } else {
2710:                                            rowVal[15] = null;
2711:                                        }
2712:
2713:                                        // ORDINAL_POSITION
2714:                                        if (!fixUpOrdinalsRequired) {
2715:                                            rowVal[16] = Integer.toString(
2716:                                                    ordPos++).getBytes();
2717:                                        } else {
2718:                                            String origColName = results
2719:                                                    .getString("Field");
2720:                                            Integer realOrdinal = (Integer) ordinalFixUpMap
2721:                                                    .get(origColName);
2722:
2723:                                            if (realOrdinal != null) {
2724:                                                rowVal[16] = realOrdinal
2725:                                                        .toString().getBytes();
2726:                                            } else {
2727:                                                throw SQLError
2728:                                                        .createSQLException(
2729:                                                                "Can not find column in full column list to determine true ordinal position.",
2730:                                                                SQLError.SQL_STATE_GENERAL_ERROR);
2731:                                            }
2732:                                        }
2733:
2734:                                        rowVal[17] = s2b(typeDesc.isNullable);
2735:
2736:                                        // We don't support REF or DISTINCT types
2737:                                        rowVal[18] = null;
2738:                                        rowVal[19] = null;
2739:                                        rowVal[20] = null;
2740:                                        rowVal[21] = null;
2741:
2742:                                        rowVal[22] = s2b("");
2743:
2744:                                        String extra = results
2745:                                                .getString("Extra");
2746:
2747:                                        if (extra != null) {
2748:                                            rowVal[22] = s2b(StringUtils
2749:                                                    .indexOfIgnoreCase(extra,
2750:                                                            "auto_increment") != -1 ? "YES"
2751:                                                    : "NO");
2752:                                        }
2753:
2754:                                        rows.add(new ByteArrayRow(rowVal));
2755:                                    }
2756:                                } finally {
2757:                                    if (results != null) {
2758:                                        try {
2759:                                            results.close();
2760:                                        } catch (Exception ex) {
2761:                                            ;
2762:                                        }
2763:
2764:                                        results = null;
2765:                                    }
2766:                                }
2767:                            }
2768:                        }
2769:                    }.doForAll();
2770:                } finally {
2771:                    if (stmt != null) {
2772:                        stmt.close();
2773:                    }
2774:                }
2775:
2776:                java.sql.ResultSet results = buildResultSet(fields, rows);
2777:
2778:                return results;
2779:            }
2780:
2781:            /**
2782:             * JDBC 2.0 Return the connection that produced this metadata object.
2783:             * 
2784:             * @return the connection that produced this metadata object.
2785:             * @throws SQLException
2786:             *             if a database error occurs
2787:             */
2788:            public java.sql.Connection getConnection() throws SQLException {
2789:                return this .conn;
2790:            }
2791:
2792:            /**
2793:             * Get a description of the foreign key columns in the foreign key table
2794:             * that reference the primary key columns of the primary key table (describe
2795:             * how one table imports another's key.) This should normally return a
2796:             * single foreign key/primary key pair (most tables only import a foreign
2797:             * key from a table once.) They are ordered by FKTABLE_CAT, FKTABLE_SCHEM,
2798:             * FKTABLE_NAME, and KEY_SEQ.
2799:             * <P>
2800:             * Each foreign key column description has the following columns:
2801:             * <OL>
2802:             * <li> <B>PKTABLE_CAT</B> String => primary key table catalog (may be
2803:             * null) </li>
2804:             * <li> <B>PKTABLE_SCHEM</B> String => primary key table schema (may be
2805:             * null) </li>
2806:             * <li> <B>PKTABLE_NAME</B> String => primary key table name </li>
2807:             * <li> <B>PKCOLUMN_NAME</B> String => primary key column name </li>
2808:             * <li> <B>FKTABLE_CAT</B> String => foreign key table catalog (may be
2809:             * null) being exported (may be null) </li>
2810:             * <li> <B>FKTABLE_SCHEM</B> String => foreign key table schema (may be
2811:             * null) being exported (may be null) </li>
2812:             * <li> <B>FKTABLE_NAME</B> String => foreign key table name being exported
2813:             * </li>
2814:             * <li> <B>FKCOLUMN_NAME</B> String => foreign key column name being
2815:             * exported </li>
2816:             * <li> <B>KEY_SEQ</B> short => sequence number within foreign key </li>
2817:             * <li> <B>UPDATE_RULE</B> short => What happens to foreign key when
2818:             * primary is updated:
2819:             * <UL>
2820:             * <li> importedKeyCascade - change imported key to agree with primary key
2821:             * update </li>
2822:             * <li> importedKeyRestrict - do not allow update of primary key if it has
2823:             * been imported </li>
2824:             * <li> importedKeySetNull - change imported key to NULL if its primary key
2825:             * has been updated </li>
2826:             * </ul>
2827:             * </li>
2828:             * <li> <B>DELETE_RULE</B> short => What happens to the foreign key when
2829:             * primary is deleted.
2830:             * <UL>
2831:             * <li> importedKeyCascade - delete rows that import a deleted key </li>
2832:             * <li> importedKeyRestrict - do not allow delete of primary key if it has
2833:             * been imported </li>
2834:             * <li> importedKeySetNull - change imported key to NULL if its primary key
2835:             * has been deleted </li>
2836:             * </ul>
2837:             * </li>
2838:             * <li> <B>FK_NAME</B> String => foreign key identifier (may be null) </li>
2839:             * <li> <B>PK_NAME</B> String => primary key identifier (may be null) </li>
2840:             * </ol>
2841:             * </p>
2842:             * 
2843:             * @param primaryCatalog
2844:             *            a catalog name; "" retrieves those without a catalog
2845:             * @param primarySchema
2846:             *            a schema name pattern; "" retrieves those without a schema
2847:             * @param primaryTable
2848:             *            a table name
2849:             * @param foreignCatalog
2850:             *            a catalog name; "" retrieves those without a catalog
2851:             * @param foreignSchema
2852:             *            a schema name pattern; "" retrieves those without a schema
2853:             * @param foreignTable
2854:             *            a table name
2855:             * @return ResultSet each row is a foreign key column description
2856:             * @throws SQLException
2857:             *             if a database access error occurs
2858:             */
2859:            public java.sql.ResultSet getCrossReference(
2860:                    final String primaryCatalog, final String primarySchema,
2861:                    final String primaryTable, final String foreignCatalog,
2862:                    final String foreignSchema, final String foreignTable)
2863:                    throws SQLException {
2864:                if (primaryTable == null) {
2865:                    throw SQLError.createSQLException("Table not specified.",
2866:                            SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2867:                }
2868:
2869:                Field[] fields = new Field[14];
2870:                fields[0] = new Field("", "PKTABLE_CAT", Types.CHAR, 255);
2871:                fields[1] = new Field("", "PKTABLE_SCHEM", Types.CHAR, 0);
2872:                fields[2] = new Field("", "PKTABLE_NAME", Types.CHAR, 255);
2873:                fields[3] = new Field("", "PKCOLUMN_NAME", Types.CHAR, 32);
2874:                fields[4] = new Field("", "FKTABLE_CAT", Types.CHAR, 255);
2875:                fields[5] = new Field("", "FKTABLE_SCHEM", Types.CHAR, 0);
2876:                fields[6] = new Field("", "FKTABLE_NAME", Types.CHAR, 255);
2877:                fields[7] = new Field("", "FKCOLUMN_NAME", Types.CHAR, 32);
2878:                fields[8] = new Field("", "KEY_SEQ", Types.SMALLINT, 2);
2879:                fields[9] = new Field("", "UPDATE_RULE", Types.SMALLINT, 2);
2880:                fields[10] = new Field("", "DELETE_RULE", Types.SMALLINT, 2);
2881:                fields[11] = new Field("", "FK_NAME", Types.CHAR, 0);
2882:                fields[12] = new Field("", "PK_NAME", Types.CHAR, 0);
2883:                fields[13] = new Field("", "DEFERRABILITY", Types.INTEGER, 2);
2884:
2885:                final ArrayList tuples = new ArrayList();
2886:
2887:                if (this .conn.versionMeetsMinimum(3, 23, 0)) {
2888:
2889:                    final Statement stmt = this .conn.getMetadataSafeStatement();
2890:
2891:                    try {
2892:
2893:                        new IterateBlock(getCatalogIterator(foreignCatalog)) {
2894:                            void forEach(Object catalogStr) throws SQLException {
2895:
2896:                                ResultSet fkresults = null;
2897:
2898:                                try {
2899:
2900:                                    /*
2901:                                     * Get foreign key information for table
2902:                                     */
2903:                                    if (conn.versionMeetsMinimum(3, 23, 50)) {
2904:                                        fkresults = extractForeignKeyFromCreateTable(
2905:                                                catalogStr.toString(), null);
2906:                                    } else {
2907:                                        StringBuffer queryBuf = new StringBuffer(
2908:                                                "SHOW TABLE STATUS FROM ");
2909:                                        queryBuf.append(quotedId);
2910:                                        queryBuf.append(catalogStr.toString());
2911:                                        queryBuf.append(quotedId);
2912:
2913:                                        fkresults = stmt.executeQuery(queryBuf
2914:                                                .toString());
2915:                                    }
2916:
2917:                                    String foreignTableWithCase = getTableNameWithCase(foreignTable);
2918:                                    String primaryTableWithCase = getTableNameWithCase(primaryTable);
2919:
2920:                                    /*
2921:                                     * Parse imported foreign key information
2922:                                     */
2923:
2924:                                    String dummy;
2925:
2926:                                    while (fkresults.next()) {
2927:                                        String tableType = fkresults
2928:                                                .getString("Type");
2929:
2930:                                        if ((tableType != null)
2931:                                                && (tableType
2932:                                                        .equalsIgnoreCase("innodb") || tableType
2933:                                                        .equalsIgnoreCase(SUPPORTS_FK))) {
2934:                                            String comment = fkresults
2935:                                                    .getString("Comment")
2936:                                                    .trim();
2937:
2938:                                            if (comment != null) {
2939:                                                StringTokenizer commentTokens = new StringTokenizer(
2940:                                                        comment, ";", false);
2941:
2942:                                                if (commentTokens
2943:                                                        .hasMoreTokens()) {
2944:                                                    dummy = commentTokens
2945:                                                            .nextToken();
2946:
2947:                                                    // Skip InnoDB comment
2948:                                                }
2949:
2950:                                                while (commentTokens
2951:                                                        .hasMoreTokens()) {
2952:                                                    String keys = commentTokens
2953:                                                            .nextToken();
2954:                                                    LocalAndReferencedColumns parsedInfo = parseTableStatusIntoLocalAndReferencedColumns(keys);
2955:
2956:                                                    int keySeq = 0;
2957:
2958:                                                    Iterator referencingColumns = parsedInfo.localColumnsList
2959:                                                            .iterator();
2960:                                                    Iterator referencedColumns = parsedInfo.referencedColumnsList
2961:                                                            .iterator();
2962:
2963:                                                    while (referencingColumns
2964:                                                            .hasNext()) {
2965:                                                        String referencingColumn = removeQuotedId(referencingColumns
2966:                                                                .next()
2967:                                                                .toString());
2968:
2969:                                                        // one tuple for each table
2970:                                                        // between
2971:                                                        // parenthesis
2972:                                                        byte[][] tuple = new byte[14][];
2973:                                                        tuple[4] = ((foreignCatalog == null) ? null
2974:                                                                : s2b(foreignCatalog));
2975:                                                        tuple[5] = ((foreignSchema == null) ? null
2976:                                                                : s2b(foreignSchema));
2977:                                                        dummy = fkresults
2978:                                                                .getString("Name"); // FKTABLE_NAME
2979:
2980:                                                        if (dummy
2981:                                                                .compareTo(foreignTableWithCase) != 0) {
2982:                                                            continue;
2983:                                                        }
2984:
2985:                                                        tuple[6] = s2b(dummy);
2986:
2987:                                                        tuple[7] = s2b(referencingColumn); // FKCOLUMN_NAME
2988:                                                        tuple[0] = ((primaryCatalog == null) ? null
2989:                                                                : s2b(primaryCatalog));
2990:                                                        tuple[1] = ((primarySchema == null) ? null
2991:                                                                : s2b(primarySchema));
2992:
2993:                                                        // Skip foreign key if it
2994:                                                        // doesn't refer to
2995:                                                        // the right table
2996:                                                        if (parsedInfo.referencedTable
2997:                                                                .compareTo(primaryTableWithCase) != 0) {
2998:                                                            continue;
2999:                                                        }
3000:
3001:                                                        tuple[2] = s2b(parsedInfo.referencedTable); // PKTABLE_NAME
3002:                                                        tuple[3] = s2b(removeQuotedId(referencedColumns
3003:                                                                .next()
3004:                                                                .toString())); // PKCOLUMN_NAME
3005:                                                        tuple[8] = Integer
3006:                                                                .toString(
3007:                                                                        keySeq)
3008:                                                                .getBytes(); // KEY_SEQ
3009:
3010:                                                        int[] actions = getForeignKeyActions(keys);
3011:
3012:                                                        tuple[9] = Integer
3013:                                                                .toString(
3014:                                                                        actions[1])
3015:                                                                .getBytes();
3016:                                                        tuple[10] = Integer
3017:                                                                .toString(
3018:                                                                        actions[0])
3019:                                                                .getBytes();
3020:                                                        tuple[11] = null; // FK_NAME
3021:                                                        tuple[12] = null; // PK_NAME
3022:                                                        tuple[13] = Integer
3023:                                                                .toString(
3024:                                                                        java.sql.DatabaseMetaData.importedKeyNotDeferrable)
3025:                                                                .getBytes();
3026:                                                        tuples
3027:                                                                .add(new ByteArrayRow(
3028:                                                                        tuple));
3029:                                                        keySeq++;
3030:                                                    }
3031:                                                }
3032:                                            }
3033:                                        }
3034:                                    }
3035:
3036:                                } finally {
3037:                                    if (fkresults != null) {
3038:                                        try {
3039:                                            fkresults.close();
3040:                                        } catch (Exception sqlEx) {
3041:                                            AssertionFailedException
3042:                                                    .shouldNotHappen(sqlEx);
3043:                                        }
3044:
3045:                                        fkresults = null;
3046:                                    }
3047:                                }
3048:                            }
3049:                        }.doForAll();
3050:                    } finally {
3051:                        if (stmt != null) {
3052:                            stmt.close();
3053:                        }
3054:                    }
3055:                }
3056:
3057:                java.sql.ResultSet results = buildResultSet(fields, tuples);
3058:
3059:                return results;
3060:            }
3061:
3062:            /**
3063:             * @see DatabaseMetaData#getDatabaseMajorVersion()
3064:             */
3065:            public int getDatabaseMajorVersion() throws SQLException {
3066:                return this .conn.getServerMajorVersion();
3067:            }
3068:
3069:            /**
3070:             * @see DatabaseMetaData#getDatabaseMinorVersion()
3071:             */
3072:            public int getDatabaseMinorVersion() throws SQLException {
3073:                return this .conn.getServerMinorVersion();
3074:            }
3075:
3076:            /**
3077:             * What's the name of this database product?
3078:             * 
3079:             * @return database product name
3080:             * @throws SQLException
3081:             *             DOCUMENT ME!
3082:             */
3083:            public String getDatabaseProductName() throws SQLException {
3084:                return "MySQL";
3085:            }
3086:
3087:            /**
3088:             * What's the version of this database product?
3089:             * 
3090:             * @return database version
3091:             * @throws SQLException
3092:             *             DOCUMENT ME!
3093:             */
3094:            public String getDatabaseProductVersion() throws SQLException {
3095:                return this .conn.getServerVersion();
3096:            }
3097:
3098:            /**
3099:             * What's the database's default transaction isolation level? The values are
3100:             * defined in java.sql.Connection.
3101:             * 
3102:             * @return the default isolation level
3103:             * @throws SQLException
3104:             *             if a database access error occurs
3105:             * @see Connection
3106:             */
3107:            public int getDefaultTransactionIsolation() throws SQLException {
3108:                if (this .conn.supportsIsolationLevel()) {
3109:                    return java.sql.Connection.TRANSACTION_READ_COMMITTED;
3110:                }
3111:
3112:                return java.sql.Connection.TRANSACTION_NONE;
3113:            }
3114:
3115:            /**
3116:             * What's this JDBC driver's major version number?
3117:             * 
3118:             * @return JDBC driver major version
3119:             */
3120:            public int getDriverMajorVersion() {
3121:                return NonRegisteringDriver.getMajorVersionInternal();
3122:            }
3123:
3124:            /**
3125:             * What's this JDBC driver's minor version number?
3126:             * 
3127:             * @return JDBC driver minor version number
3128:             */
3129:            public int getDriverMinorVersion() {
3130:                return NonRegisteringDriver.getMinorVersionInternal();
3131:            }
3132:
3133:            /**
3134:             * What's the name of this JDBC driver?
3135:             * 
3136:             * @return JDBC driver name
3137:             * @throws SQLException
3138:             *             DOCUMENT ME!
3139:             */
3140:            public String getDriverName() throws SQLException {
3141:                return "MySQL-AB JDBC Driver";
3142:            }
3143:
3144:            /**
3145:             * What's the version of this JDBC driver?
3146:             * 
3147:             * @return JDBC driver version
3148:             * @throws java.sql.SQLException
3149:             *             DOCUMENT ME!
3150:             */
3151:            public String getDriverVersion() throws java.sql.SQLException {
3152:                return "@MYSQL_CJ_FULL_PROD_NAME@ ( Revision: @MYSQL_CJ_REVISION@ )";
3153:            }
3154:
3155:            /**
3156:             * Get a description of a foreign key columns that reference a table's
3157:             * primary key columns (the foreign keys exported by a table). They are
3158:             * ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.
3159:             * <P>
3160:             * Each foreign key column description has the following columns:
3161:             * <OL>
3162:             * <li> <B>PKTABLE_CAT</B> String => primary key table catalog (may be
3163:             * null) </li>
3164:             * <li> <B>PKTABLE_SCHEM</B> String => primary key table schema (may be
3165:             * null) </li>
3166:             * <li> <B>PKTABLE_NAME</B> String => primary key table name </li>
3167:             * <li> <B>PKCOLUMN_NAME</B> String => primary key column name </li>
3168:             * <li> <B>FKTABLE_CAT</B> String => foreign key table catalog (may be
3169:             * null) being exported (may be null) </li>
3170:             * <li> <B>FKTABLE_SCHEM</B> String => foreign key table schema (may be
3171:             * null) being exported (may be null) </li>
3172:             * <li> <B>FKTABLE_NAME</B> String => foreign key table name being exported
3173:             * </li>
3174:             * <li> <B>FKCOLUMN_NAME</B> String => foreign key column name being
3175:             * exported </li>
3176:             * <li> <B>KEY_SEQ</B> short => sequence number within foreign key </li>
3177:             * <li> <B>UPDATE_RULE</B> short => What happens to foreign key when
3178:             * primary is updated:
3179:             * <UL>
3180:             * <li> importedKeyCascade - change imported key to agree with primary key
3181:             * update </li>
3182:             * <li> importedKeyRestrict - do not allow update of primary key if it has
3183:             * been imported </li>
3184:             * <li> importedKeySetNull - change imported key to NULL if its primary key
3185:             * has been updated </li>
3186:             * </ul>
3187:             * </li>
3188:             * <li> <B>DELETE_RULE</B> short => What happens to the foreign key when
3189:             * primary is deleted.
3190:             * <UL>
3191:             * <li> importedKeyCascade - delete rows that import a deleted key </li>
3192:             * <li> importedKeyRestrict - do not allow delete of primary key if it has
3193:             * been imported </li>
3194:             * <li> importedKeySetNull - change imported key to NULL if its primary key
3195:             * has been deleted </li>
3196:             * </ul>
3197:             * </li>
3198:             * <li> <B>FK_NAME</B> String => foreign key identifier (may be null) </li>
3199:             * <li> <B>PK_NAME</B> String => primary key identifier (may be null) </li>
3200:             * </ol>
3201:             * </p>
3202:             * 
3203:             * @param catalog
3204:             *            a catalog name; "" retrieves those without a catalog
3205:             * @param schema
3206:             *            a schema name pattern; "" retrieves those without a schema
3207:             * @param table
3208:             *            a table name
3209:             * @return ResultSet each row is a foreign key column description
3210:             * @throws SQLException
3211:             *             if a database access error occurs
3212:             * @see #getImportedKeys
3213:             */
3214:            public java.sql.ResultSet getExportedKeys(String catalog,
3215:                    String schema, final String table) throws SQLException {
3216:                if (table == null) {
3217:                    throw SQLError.createSQLException("Table not specified.",
3218:                            SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
3219:                }
3220:
3221:                Field[] fields = new Field[14];
3222:                fields[0] = new Field("", "PKTABLE_CAT", Types.CHAR, 255);
3223:                fields[1] = new Field("", "PKTABLE_SCHEM", Types.CHAR, 0);
3224:                fields[2] = new Field("", "PKTABLE_NAME", Types.CHAR, 255);
3225:                fields[3] = new Field("", "PKCOLUMN_NAME", Types.CHAR, 32);
3226:                fields[4] = new Field("", "FKTABLE_CAT", Types.CHAR, 255);
3227:                fields[5] = new Field("", "FKTABLE_SCHEM", Types.CHAR, 0);
3228:                fields[6] = new Field("", "FKTABLE_NAME", Types.CHAR, 255);
3229:                fields[7] = new Field("", "FKCOLUMN_NAME", Types.CHAR, 32);
3230:                fields[8] = new Field("", "KEY_SEQ", Types.SMALLINT, 2);
3231:                fields[9] = new Field("", "UPDATE_RULE", Types.SMALLINT, 2);
3232:                fields[10] = new Field("", "DELETE_RULE", Types.SMALLINT, 2);
3233:                fields[11] = new Field("", "FK_NAME", Types.CHAR, 255);
3234:                fields[12] = new Field("", "PK_NAME", Types.CHAR, 0);
3235:                fields[13] = new Field("", "DEFERRABILITY", Types.INTEGER, 2);
3236:
3237:                final ArrayList rows = new ArrayList();
3238:
3239:                if (this .conn.versionMeetsMinimum(3, 23, 0)) {
3240:
3241:                    final Statement stmt = this .conn.getMetadataSafeStatement();
3242:
3243:                    try {
3244:
3245:                        new IterateBlock(getCatalogIterator(catalog)) {
3246:                            void forEach(Object catalogStr) throws SQLException {
3247:                                ResultSet fkresults = null;
3248:
3249:                                try {
3250:
3251:                                    /*
3252:                                     * Get foreign key information for table
3253:                                     */
3254:                                    if (conn.versionMeetsMinimum(3, 23, 50)) {
3255:                                        // we can use 'SHOW CREATE TABLE'
3256:
3257:                                        fkresults = extractForeignKeyFromCreateTable(
3258:                                                catalogStr.toString(), null);
3259:                                    } else {
3260:                                        StringBuffer queryBuf = new StringBuffer(
3261:                                                "SHOW TABLE STATUS FROM ");
3262:                                        queryBuf.append(quotedId);
3263:                                        queryBuf.append(catalogStr.toString());
3264:                                        queryBuf.append(quotedId);
3265:
3266:                                        fkresults = stmt.executeQuery(queryBuf
3267:                                                .toString());
3268:                                    }
3269:
3270:                                    // lower-case table name might be turned on
3271:                                    String tableNameWithCase = getTableNameWithCase(table);
3272:
3273:                                    /*
3274:                                     * Parse imported foreign key information
3275:                                     */
3276:
3277:                                    while (fkresults.next()) {
3278:                                        String tableType = fkresults
3279:                                                .getString("Type");
3280:
3281:                                        if ((tableType != null)
3282:                                                && (tableType
3283:                                                        .equalsIgnoreCase("innodb") || tableType
3284:                                                        .equalsIgnoreCase(SUPPORTS_FK))) {
3285:                                            String comment = fkresults
3286:                                                    .getString("Comment")
3287:                                                    .trim();
3288:
3289:                                            if (comment != null) {
3290:                                                StringTokenizer commentTokens = new StringTokenizer(
3291:                                                        comment, ";", false);
3292:
3293:                                                if (commentTokens
3294:                                                        .hasMoreTokens()) {
3295:                                                    commentTokens.nextToken(); // Skip
3296:                                                    // InnoDB
3297:                                                    // comment
3298:
3299:                                                    while (commentTokens
3300:                                                            .hasMoreTokens()) {
3301:                                                        String keys = commentTokens
3302:                                                                .nextToken();
3303:                                                        getExportKeyResults(
3304:                                                                catalogStr
3305:                                                                        .toString(),
3306:                                                                tableNameWithCase,
3307:                                                                keys,
3308:                                                                rows,
3309:                                                                fkresults
3310:                                                                        .getString("Name"));
3311:                                                    }
3312:                                                }
3313:                                            }
3314:                                        }
3315:                                    }
3316:
3317:                                } finally {
3318:                                    if (fkresults != null) {
3319:                                        try {
3320:                                            fkresults.close();
3321:                                        } catch (SQLException sqlEx) {
3322:                                            AssertionFailedException
3323:                                                    .shouldNotHappen(sqlEx);
3324:                                        }
3325:
3326:                                        fkresults = null;
3327:                                    }
3328:                                }
3329:                            }
3330:                        }.doForAll();
3331:                    } finally {
3332:                        if (stmt != null) {
3333:                            stmt.close();
3334:                        }
3335:                    }
3336:                }
3337:
3338:                java.sql.ResultSet results = buildResultSet(fields, rows);
3339:
3340:                return results;
3341:            }
3342:
3343:            /**
3344:             * Adds to the tuples list the exported keys of exportingTable based on the
3345:             * keysComment from the 'show table status' sql command. KeysComment is that
3346:             * part of the comment field that follows the "InnoDB free ...;" prefix.
3347:             * 
3348:             * @param catalog
3349:             *            the database to use
3350:             * @param exportingTable
3351:             *            the table keys are being exported from
3352:             * @param keysComment
3353:             *            the comment from 'show table status'
3354:             * @param tuples
3355:             *            the rows to add results to
3356:             * @param fkTableName
3357:             *            the foreign key table name
3358:             * @throws SQLException
3359:             *             if a database access error occurs
3360:             */
3361:            private void getExportKeyResults(String catalog,
3362:                    String exportingTable, String keysComment, List tuples,
3363:                    String fkTableName) throws SQLException {
3364:                getResultsImpl(catalog, exportingTable, keysComment, tuples,
3365:                        fkTableName, true);
3366:            }
3367:
3368:            /**
3369:             * Get all the "extra" characters that can be used in unquoted identifier
3370:             * names (those beyond a-z, 0-9 and _).
3371:             * 
3372:             * @return the string containing the extra characters
3373:             * @throws SQLException
3374:             *             DOCUMENT ME!
3375:             */
3376:            public String getExtraNameCharacters() throws SQLException {
3377:                return "#@";
3378:            }
3379:
3380:            /**
3381:             * Returns the DELETE and UPDATE foreign key actions from the given 'SHOW
3382:             * TABLE STATUS' string, with the DELETE action being the first item in the
3383:             * array, and the UPDATE action being the second.
3384:             * 
3385:             * @param commentString
3386:             *            the comment from 'SHOW TABLE STATUS'
3387:             * @return int[] [0] = delete action, [1] = update action
3388:             */
3389:            private int[] getForeignKeyActions(String commentString) {
3390:                int[] actions = new int[] {
3391:                        java.sql.DatabaseMetaData.importedKeyNoAction,
3392:                        java.sql.DatabaseMetaData.importedKeyNoAction };
3393:
3394:                int lastParenIndex = commentString.lastIndexOf(")");
3395:
3396:                if (lastParenIndex != (commentString.length() - 1)) {
3397:                    String cascadeOptions = commentString.substring(
3398:                            lastParenIndex + 1).trim().toUpperCase(
3399:                            Locale.ENGLISH);
3400:
3401:                    actions[0] = getCascadeDeleteOption(cascadeOptions);
3402:                    actions[1] = getCascadeUpdateOption(cascadeOptions);
3403:                }
3404:
3405:                return actions;
3406:            }
3407:
3408:            /**
3409:             * What's the string used to quote SQL identifiers? This returns a space " "
3410:             * if identifier quoting isn't supported. A JDBC compliant driver always
3411:             * uses a double quote character.
3412:             * 
3413:             * @return the quoting string
3414:             * @throws SQLException
3415:             *             DOCUMENT ME!
3416:             */
3417:            public String getIdentifierQuoteString() throws SQLException {
3418:                if (this .conn.supportsQuotedIdentifiers()) {
3419:                    if (!this .conn.useAnsiQuotedIdentifiers()) {
3420:                        return "`";
3421:                    }
3422:
3423:                    return "\"";
3424:                }
3425:
3426:                return " ";
3427:            }
3428:
3429:            /**
3430:             * Get a description of the primary key columns that are referenced by a
3431:             * table's foreign key columns (the primary keys imported by a table). They
3432:             * are ordered by PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.
3433:             * <P>
3434:             * Each primary key column description has the following columns:
3435:             * <OL>
3436:             * <li> <B>PKTABLE_CAT</B> String => primary key table catalog being
3437:             * imported (may be null) </li>
3438:             * <li> <B>PKTABLE_SCHEM</B> String => primary key table schema being
3439:             * imported (may be null) </li>
3440:             * <li> <B>PKTABLE_NAME</B> String => primary key table name being imported
3441:             * </li>
3442:             * <li> <B>PKCOLUMN_NAME</B> String => primary key column name being
3443:             * imported </li>
3444:             * <li> <B>FKTABLE_CAT</B> String => foreign key table catalog (may be
3445:             * null) </li>
3446:             * <li> <B>FKTABLE_SCHEM</B> String => foreign key table schema (may be
3447:             * null) </li>
3448:             * <li> <B>FKTABLE_NAME</B> String => foreign key table name </li>
3449:             * <li> <B>FKCOLUMN_NAME</B> String => foreign key column name </li>
3450:             * <li> <B>KEY_SEQ</B> short => sequence number within foreign key </li>
3451:             * <li> <B>UPDATE_RULE</B> short => What happens to foreign key when
3452:             * primary is updated:
3453:             * <UL>
3454:             * <li> importedKeyCascade - change imported key to agree with primary key
3455:             * update </li>
3456:             * <li> importedKeyRestrict - do not allow update of primary key if it has
3457:             * been imported </li>
3458:             * <li> importedKeySetNull - change imported key to NULL if its primary key
3459:             * has been updated </li>
3460:             * </ul>
3461:             * </li>
3462:             * <li> <B>DELETE_RULE</B> short => What happens to the foreign key when
3463:             * primary is deleted.
3464:             * <UL>
3465:             * <li> importedKeyCascade - delete rows that import a deleted key </li>
3466:             * <li> importedKeyRestrict - do not allow delete of primary key if it has
3467:             * been imported </li>
3468:             * <li> importedKeySetNull - change imported key to NULL if its primary key
3469:             * has been deleted </li>
3470:             * </ul>
3471:             * </li>
3472:             * <li> <B>FK_NAME</B> String => foreign key name (may be null) </li>
3473:             * <li> <B>PK_NAME</B> String => primary key name (may be null) </li>
3474:             * </ol>
3475:             * </p>
3476:             * 
3477:             * @param catalog
3478:             *            a catalog name; "" retrieves those without a catalog
3479:             * @param schema
3480:             *            a schema name pattern; "" retrieves those without a schema
3481:             * @param table
3482:             *            a table name
3483:             * @return ResultSet each row is a primary key column description
3484:             * @throws SQLException
3485:             *             if a database access error occurs
3486:             * @see #getExportedKeys
3487:             */
3488:            public java.sql.ResultSet getImportedKeys(String catalog,
3489:                    String schema, final String table) throws SQLException {
3490:                if (table == null) {
3491:                    throw SQLError.createSQLException("Table not specified.",
3492:                            SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
3493:                }
3494:
3495:                Field[] fields = new Field[14];
3496:                fields[0] = new Field("", "PKTABLE_CAT", Types.CHAR, 255);
3497:                fields[1] = new Field("", "PKTABLE_SCHEM", Types.CHAR, 0);
3498:                fields[2] = new Field("", "PKTABLE_NAME", Types.CHAR, 255);
3499:                fields[3] = new Field("", "PKCOLUMN_NAME", Types.CHAR, 32);
3500:                fields[4] = new Field("", "FKTABLE_CAT", Types.CHAR, 255);
3501:                fields[5] = new Field("", "FKTABLE_SCHEM", Types.CHAR, 0);
3502:                fields[6] = new Field("", "FKTABLE_NAME", Types.CHAR, 255);
3503:                fields[7] = new Field("", "FKCOLUMN_NAME", Types.CHAR, 32);
3504:                fields[8] = new Field("", "KEY_SEQ", Types.SMALLINT, 2);
3505:                fields[9] = new Field("", "UPDATE_RULE", Types.SMALLINT, 2);
3506:                fields[10] = new Field("", "DELETE_RULE", Types.SMALLINT, 2);
3507:                fields[11] = new Field("", "FK_NAME", Types.CHAR, 255);
3508:                fields[12] = new Field("", "PK_NAME", Types.CHAR, 0);
3509:                fields[13] = new Field("", "DEFERRABILITY", Types.INTEGER, 2);
3510:
3511:                final ArrayList rows = new ArrayList();
3512:
3513:                if (this .conn.versionMeetsMinimum(3, 23, 0)) {
3514:
3515:                    final Statement stmt = this .conn.getMetadataSafeStatement();
3516:
3517:                    try {
3518:
3519:                        new IterateBlock(getCatalogIterator(catalog)) {
3520:                            void forEach(Object catalogStr) throws SQLException {
3521:                                ResultSet fkresults = null;
3522:
3523:                                try {
3524:
3525:                                    /*
3526:                                     * Get foreign key information for table
3527:                                     */
3528:                                    if (conn.versionMeetsMinimum(3, 23, 50)) {
3529:                                        // we can use 'SHOW CREATE TABLE'
3530:
3531:                                        fkresults = extractForeignKeyFromCreateTable(
3532:                                                catalogStr.toString(), table);
3533:                                    } else {
3534:                                        StringBuffer queryBuf = new StringBuffer(
3535:                                                "SHOW TABLE STATUS ");
3536:                                        queryBuf.append(" FROM ");
3537:                                        queryBuf.append(quotedId);
3538:                                        queryBuf.append(catalogStr.toString());
3539:                                        queryBuf.append(quotedId);
3540:                                        queryBuf.append(" LIKE '");
3541:                                        queryBuf.append(table);
3542:                                        queryBuf.append("'");
3543:
3544:                                        fkresults = stmt.executeQuery(queryBuf
3545:                                                .toString());
3546:                                    }
3547:
3548:                                    /*
3549:                                     * Parse imported foreign key information
3550:                                     */
3551:
3552:                                    while (fkresults.next()) {
3553:                                        String tableType = fkresults
3554:                                                .getString("Type");
3555:
3556:                                        if ((tableType != null)
3557:                                                && (tableType
3558:                                                        .equalsIgnoreCase("innodb") || tableType
3559:                                                        .equalsIgnoreCase(SUPPORTS_FK))) {
3560:                                            String comment = fkresults
3561:                                                    .getString("Comment")
3562:                                                    .trim();
3563:
3564:                                            if (comment != null) {
3565:                                                StringTokenizer commentTokens = new StringTokenizer(
3566:                                                        comment, ";", false);
3567:
3568:                                                if (commentTokens
3569:                                                        .hasMoreTokens()) {
3570:                                                    commentTokens.nextToken(); // Skip
3571:                                                    // InnoDB
3572:                                                    // comment
3573:
3574:                                                    while (commentTokens
3575:                                                            .hasMoreTokens()) {
3576:                                                        String keys = commentTokens
3577:                                                                .nextToken();
3578:                                                        getImportKeyResults(
3579:                                                                catalogStr
3580:                                                                        .toString(),
3581:                                                                table, keys,
3582:                                                                rows);
3583:                                                    }
3584:                                                }
3585:                                            }
3586:                                        }
3587:                                    }
3588:                                } finally {
3589:                                    if (fkresults != null) {
3590:                                        try {
3591:                                            fkresults.close();
3592:                                        } catch (SQLException sqlEx) {
3593:                                            AssertionFailedException
3594:                                                    .shouldNotHappen(sqlEx);
3595:                                        }
3596:
3597:                                        fkresults = null;
3598:                                    }
3599:                                }
3600:                            }
3601:                        }.doForAll();
3602:                    } finally {
3603:                        if (stmt != null) {
3604:                            stmt.close();
3605:                        }
3606:                    }
3607:                }
3608:
3609:                java.sql.ResultSet results = buildResultSet(fields, rows);
3610:
3611:                return results;
3612:            }
3613:
3614:            /**
3615:             * Populates the tuples list with the imported keys of importingTable based
3616:             * on the keysComment from the 'show table status' sql command. KeysComment
3617:             * is that part of the comment field that follows the "InnoDB free ...;"
3618:             * prefix.
3619:             * 
3620:             * @param catalog
3621:             *            the database to use
3622:             * @param importingTable
3623:             *            the table keys are being imported to
3624:             * @param keysComment
3625:             *            the comment from 'show table status'
3626:             * @param tuples
3627:             *            the rows to add results to
3628:             * @throws SQLException
3629:             *             if a database access error occurs
3630:             */
3631:            private void getImportKeyResults(String catalog,
3632:                    String importingTable, String keysComment, List tuples)
3633:                    throws SQLException {
3634:                getResultsImpl(catalog, importingTable, keysComment, tuples,
3635:                        null, false);
3636:            }
3637:
3638:            /**
3639:             * Get a description of a table's indices and statistics. They are ordered
3640:             * by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.
3641:             * <P>
3642:             * Each index column description has the following columns:
3643:             * <OL>
3644:             * <li> <B>TABLE_CAT</B> String => table catalog (may be null) </li>
3645:             * <li> <B>TABLE_SCHEM</B> String => table schema (may be null) </li>
3646:             * <li> <B>TABLE_NAME</B> String => table name </li>
3647:             * <li> <B>NON_UNIQUE</B> boolean => Can index values be non-unique? false
3648:             * when TYPE is tableIndexStatistic </li>
3649:             * <li> <B>INDEX_QUALIFIER</B> String => index catalog (may be null); null
3650:             * when TYPE is tableIndexStatistic </li>
3651:             * <li> <B>INDEX_NAME</B> String => index name; null when TYPE is
3652:             * tableIndexStatistic </li>
3653:             * <li> <B>TYPE</B> short => index type:
3654:             * <UL>
3655:             * <li> tableIndexStatistic - this identifies table statistics that are
3656:             * returned in conjuction with a table's index descriptions </li>
3657:             * <li> tableIndexClustered - this is a clustered index </li>
3658:             * <li> tableIndexHashed - this is a hashed index </li>
3659:             * <li> tableIndexOther - this is some other style of index </li>
3660:             * </ul>
3661:             * </li>
3662:             * <li> <B>ORDINAL_POSITION</B> short => column sequence number within
3663:             * index; zero when TYPE is tableIndexStatistic </li>
3664:             * <li> <B>COLUMN_NAME</B> String => column name; null when TYPE is
3665:             * tableIndexStatistic </li>
3666:             * <li> <B>ASC_OR_DESC</B> String => column sort sequence, "A" =>
3667:             * ascending, "D" => descending, may be null if sort sequence is not
3668:             * supported; null when TYPE is tableIndexStatistic </li>
3669:             * <li> <B>CARDINALITY</B> int => When TYPE is tableIndexStatisic then this
3670:             * is the number of rows in the table; otherwise it is the number of unique
3671:             * values in the index. </li>
3672:             * <li> <B>PAGES</B> int => When TYPE is tableIndexStatisic then this is
3673:             * the number of pages used for the table, otherwise it is the number of
3674:             * pages used for the current index. </li>
3675:             * <li> <B>FILTER_CONDITION</B> String => Filter condition, if any. (may be
3676:             * null) </li>
3677:             * </ol>
3678:             * </p>
3679:             * 
3680:             * @param catalog
3681:             *            a catalog name; "" retrieves those without a catalog
3682:             * @param schema
3683:             *            a schema name pattern; "" retrieves those without a schema
3684:             * @param table
3685:             *            a table name
3686:             * @param unique
3687:             *            when true, return only indices for unique values; when false,
3688:             *            return indices regardless of whether unique or not
3689:             * @param approximate
3690:             *            when true, result is allowed to reflect approximate or out of
3691:             *            data values; when false, results are requested to be accurate
3692:             * @return ResultSet each row is an index column description
3693:             * @throws SQLException
3694:             *             DOCUMENT ME!
3695:             */
3696:            public java.sql.ResultSet getIndexInfo(String catalog,
3697:                    String schema, final String table, final boolean unique,
3698:                    boolean approximate) throws SQLException {
3699:                /*
3700:                 * MySQL stores index information in the following fields: Table
3701:                 * Non_unique Key_name Seq_in_index Column_name Collation Cardinality
3702:                 * Sub_part
3703:                 */
3704:
3705:                Field[] fields = new Field[13];
3706:                fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 255);
3707:                fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 0);
3708:                fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 255);
3709:                fields[3] = new Field("", "NON_UNIQUE", Types.CHAR, 4);
3710:                fields[4] = new Field("", "INDEX_QUALIFIER", Types.CHAR, 1);
3711:                fields[5] = new Field("", "INDEX_NAME", Types.CHAR, 32);
3712:                fields[6] = new Field("", "TYPE", Types.CHAR, 32);
3713:                fields[7] = new Field("", "ORDINAL_POSITION", Types.SMALLINT, 5);
3714:                fields[8] = new Field("", "COLUMN_NAME", Types.CHAR, 32);
3715:                fields[9] = new Field("", "ASC_OR_DESC", Types.CHAR, 1);
3716:                fields[10] = new Field("", "CARDINALITY", Types.INTEGER, 10);
3717:                fields[11] = new Field("", "PAGES", Types.INTEGER, 10);
3718:                fields[12] = new Field("", "FILTER_CONDITION", Types.CHAR, 32);
3719:
3720:                final ArrayList rows = new ArrayList();
3721:                final Statement stmt = this .conn.getMetadataSafeStatement();
3722:
3723:                try {
3724:
3725:                    new IterateBlock(getCatalogIterator(catalog)) {
3726:                        void forEach(Object catalogStr) throws SQLException {
3727:
3728:                            ResultSet results = null;
3729:
3730:                            try {
3731:                                StringBuffer queryBuf = new StringBuffer(
3732:                                        "SHOW INDEX FROM ");
3733:                                queryBuf.append(quotedId);
3734:                                queryBuf.append(table);
3735:                                queryBuf.append(quotedId);
3736:                                queryBuf.append(" FROM ");
3737:                                queryBuf.append(quotedId);
3738:                                queryBuf.append(catalogStr.toString());
3739:                                queryBuf.append(quotedId);
3740:
3741:                                try {
3742:                                    results = stmt.executeQuery(queryBuf
3743:                                            .toString());
3744:                                } catch (SQLException sqlEx) {
3745:                                    int errorCode = sqlEx.getErrorCode();
3746:
3747:                                    // If SQLState is 42S02, ignore this SQLException
3748:                                    // it means the table doesn't exist....
3749:                                    if (!"42S02".equals(sqlEx.getSQLState())) {
3750:                                        // Sometimes not mapped correctly for pre-4.1
3751:                                        // so use error code instead.
3752:                                        if (errorCode != MysqlErrorNumbers.ER_NO_SUCH_TABLE) {
3753:                                            throw sqlEx;
3754:                                        }
3755:                                    }
3756:                                }
3757:
3758:                                while (results != null && results.next()) {
3759:                                    byte[][] row = new byte[14][];
3760:                                    row[0] = ((catalogStr.toString() == null) ? new byte[0]
3761:                                            : s2b(catalogStr.toString()));
3762:                                    ;
3763:                                    row[1] = null;
3764:                                    row[2] = results.getBytes("Table");
3765:
3766:                                    boolean indexIsUnique = results
3767:                                            .getInt("Non_unique") == 0;
3768:
3769:                                    row[3] = (!indexIsUnique ? s2b("true")
3770:                                            : s2b("false"));
3771:                                    row[4] = new byte[0];
3772:                                    row[5] = results.getBytes("Key_name");
3773:                                    row[6] = Integer
3774:                                            .toString(
3775:                                                    java.sql.DatabaseMetaData.tableIndexOther)
3776:                                            .getBytes();
3777:                                    row[7] = results.getBytes("Seq_in_index");
3778:                                    row[8] = results.getBytes("Column_name");
3779:                                    row[9] = results.getBytes("Collation");
3780:                                    row[10] = results.getBytes("Cardinality");
3781:                                    row[11] = s2b("0");
3782:                                    row[12] = null;
3783:
3784:                                    if (unique) {
3785:                                        if (indexIsUnique) {
3786:                                            rows.add(new ByteArrayRow(row));
3787:                                        }
3788:                                    } else {
3789:                                        // All rows match
3790:                                        rows.add(new ByteArrayRow(row));
3791:                                    }
3792:                                }
3793:                            } finally {
3794:                                if (results != null) {
3795:                                    try {
3796:                                        results.close();
3797:                                    } catch (Exception ex) {
3798:                                        ;
3799:                                    }
3800:
3801:                                    results = null;
3802:                                }
3803:                            }
3804:                        }
3805:                    }.doForAll();
3806:
3807:                    java.sql.ResultSet indexInfo = buildResultSet(fields, rows);
3808:
3809:                    return indexInfo;
3810:                } finally {
3811:                    if (stmt != null) {
3812:                        stmt.close();
3813:                    }
3814:                }
3815:            }
3816:
3817:            /**
3818:             * @see DatabaseMetaData#getJDBCMajorVersion()
3819:             */
3820:            public int getJDBCMajorVersion() throws SQLException {
3821:                return 3;
3822:            }
3823:
3824:            /**
3825:             * @see DatabaseMetaData#getJDBCMinorVersion()
3826:             */
3827:            public int getJDBCMinorVersion() throws SQLException {
3828:                return 0;
3829:            }
3830:
3831:            /**
3832:             * How many hex characters can you have in an inline binary literal?
3833:             * 
3834:             * @return max literal length
3835:             * @throws SQLException
3836:             *             DOCUMENT ME!
3837:             */
3838:            public int getMaxBinaryLiteralLength() throws SQLException {
3839:                return 16777208;
3840:            }
3841:
3842:            /**
3843:             * What's the maximum length of a catalog name?
3844:             * 
3845:             * @return max name length in bytes
3846:             * @throws SQLException
3847:             *             DOCUMENT ME!
3848:             */
3849:            public int getMaxCatalogNameLength() throws SQLException {
3850:                return 32;
3851:            }
3852:
3853:            /**
3854:             * What's the max length for a character literal?
3855:             * 
3856:             * @return max literal length
3857:             * @throws SQLException
3858:             *             DOCUMENT ME!
3859:             */
3860:            public int getMaxCharLiteralLength() throws SQLException {
3861:                return 16777208;
3862:            }
3863:
3864:            /**
3865:             * What's the limit on column name length?
3866:             * 
3867:             * @return max literal length
3868:             * @throws SQLException
3869:             *             DOCUMENT ME!
3870:             */
3871:            public int getMaxColumnNameLength() throws SQLException {
3872:                return 64;
3873:            }
3874:
3875:            /**
3876:             * What's the maximum number of columns in a "GROUP BY" clause?
3877:             * 
3878:             * @return max number of columns
3879:             * @throws SQLException
3880:             *             DOCUMENT ME!
3881:             */
3882:            public int getMaxColumnsInGroupBy() throws SQLException {
3883:                return 64;
3884:            }
3885:
3886:            /**
3887:             * What's the maximum number of columns allowed in an index?
3888:             * 
3889:             * @return max columns
3890:             * @throws SQLException
3891:             *             DOCUMENT ME!
3892:             */
3893:            public int getMaxColumnsInIndex() throws SQLException {
3894:                return 16;
3895:            }
3896:
3897:            /**
3898:             * What's the maximum number of columns in an "ORDER BY" clause?
3899:             * 
3900:             * @return max columns
3901:             * @throws SQLException
3902:             *             DOCUMENT ME!
3903:             */
3904:            public int getMaxColumnsInOrderBy() throws SQLException {
3905:                return 64;
3906:            }
3907:
3908:            /**
3909:             * What's the maximum number of columns in a "SELECT" list?
3910:             * 
3911:             * @return max columns
3912:             * @throws SQLException
3913:             *             DOCUMENT ME!
3914:             */
3915:            public int getMaxColumnsInSelect() throws SQLException {
3916:                return 256;
3917:            }
3918:
3919:            /**
3920:             * What's maximum number of columns in a table?
3921:             * 
3922:             * @return max columns
3923:             * @throws SQLException
3924:             *             DOCUMENT ME!
3925:             */
3926:            public int getMaxColumnsInTable() throws SQLException {
3927:                return 512;
3928:            }
3929:
3930:            /**
3931:             * How many active connections can we have at a time to this database?
3932:             * 
3933:             * @return max connections
3934:             * @throws SQLException
3935:             *             DOCUMENT ME!
3936:             */
3937:            public int getMaxConnections() throws SQLException {
3938:                return 0;
3939:            }
3940:
3941:            /**
3942:             * What's the maximum cursor name length?
3943:             * 
3944:             * @return max cursor name length in bytes
3945:             * @throws SQLException
3946:             *             DOCUMENT ME!
3947:             */
3948:            public int getMaxCursorNameLength() throws SQLException {
3949:                return 64;
3950:            }
3951:
3952:            /**
3953:             * What's the maximum length of an index (in bytes)?
3954:             * 
3955:             * @return max index length in bytes
3956:             * @throws SQLException
3957:             *             DOCUMENT ME!
3958:             */
3959:            public int getMaxIndexLength() throws SQLException {
3960:                return 256;
3961:            }
3962:
3963:            /**
3964:             * What's the maximum length of a procedure name?
3965:             * 
3966:             * @return max name length in bytes
3967:             * @throws SQLException
3968:             *             DOCUMENT ME!
3969:             */
3970:            public int getMaxProcedureNameLength() throws SQLException {
3971:                return 0;
3972:            }
3973:
3974:            /**
3975:             * What's the maximum length of a single row?
3976:             * 
3977:             * @return max row size in bytes
3978:             * @throws SQLException
3979:             *             DOCUMENT ME!
3980:             */
3981:            public int getMaxRowSize() throws SQLException {
3982:                return Integer.MAX_VALUE - 8; // Max buffer size - HEADER
3983:            }
3984:
3985:            /**
3986:             * What's the maximum length allowed for a schema name?
3987:             * 
3988:             * @return max name length in bytes
3989:             * @throws SQLException
3990:             *             DOCUMENT ME!
3991:             */
3992:            public int getMaxSchemaNameLength() throws SQLException {
3993:                return 0;
3994:            }
3995:
3996:            /**
3997:             * What's the maximum length of a SQL statement?
3998:             * 
3999:             * @return max length in bytes
4000:             * @throws SQLException
4001:             *             DOCUMENT ME!
4002:             */
4003:            public int getMaxStatementLength() throws SQLException {
4004:                return MysqlIO.getMaxBuf() - 4; // Max buffer - header
4005:            }
4006:
4007:            /**
4008:             * How many active statements can we have open at one time to this database?
4009:             * 
4010:             * @return the maximum
4011:             * @throws SQLException
4012:             *             DOCUMENT ME!
4013:             */
4014:            public int getMaxStatements() throws SQLException {
4015:                return 0;
4016:            }
4017:
4018:            /**
4019:             * What's the maximum length of a table name?
4020:             * 
4021:             * @return max name length in bytes
4022:             * @throws SQLException
4023:             *             DOCUMENT ME!
4024:             */
4025:            public int getMaxTableNameLength() throws SQLException {
4026:                return 64;
4027:            }
4028:
4029:            /**
4030:             * What's the maximum number of tables in a SELECT?
4031:             * 
4032:             * @return the maximum
4033:             * @throws SQLException
4034:             *             DOCUMENT ME!
4035:             */
4036:            public int getMaxTablesInSelect() throws SQLException {
4037:                return 256;
4038:            }
4039:
4040:            /**
4041:             * What's the maximum length of a user name?
4042:             * 
4043:             * @return max name length in bytes
4044:             * @throws SQLException
4045:             *             DOCUMENT ME!
4046:             */
4047:            public int getMaxUserNameLength() throws SQLException {
4048:                return 16;
4049:            }
4050:
4051:            /**
4052:             * Get a comma separated list of math functions.
4053:             * 
4054:             * @return the list
4055:             * @throws SQLException
4056:             *             DOCUMENT ME!
4057:             */
4058:            public String getNumericFunctions() throws SQLException {
4059:                return "ABS,ACOS,ASIN,ATAN,ATAN2,BIT_COUNT,CEILING,COS,"
4060:                        + "COT,DEGREES,EXP,FLOOR,LOG,LOG10,MAX,MIN,MOD,PI,POW,"
4061:                        + "POWER,RADIANS,RAND,ROUND,SIN,SQRT,TAN,TRUNCATE";
4062:            }
4063:
4064:            /**
4065:             * Get a description of a table's primary key columns. They are ordered by
4066:             * COLUMN_NAME.
4067:             * <P>
4068:             * Each column description has the following columns:
4069:             * <OL>
4070:             * <li> <B>TABLE_CAT</B> String => table catalog (may be null) </li>
4071:             * <li> <B>TABLE_SCHEM</B> String => table schema (may be null) </li>
4072:             * <li> <B>TABLE_NAME</B> String => table name </li>
4073:             * <li> <B>COLUMN_NAME</B> String => column name </li>
4074:             * <li> <B>KEY_SEQ</B> short => sequence number within primary key </li>
4075:             * <li> <B>PK_NAME</B> String => primary key name (may be null) </li>
4076:             * </ol>
4077:             * </p>
4078:             * 
4079:             * @param catalog
4080:             *            a catalog name; "" retrieves those without a catalog
4081:             * @param schema
4082:             *            a schema name pattern; "" retrieves those without a schema
4083:             * @param table
4084:             *            a table name
4085:             * @return ResultSet each row is a primary key column description
4086:             * @throws SQLException
4087:             *             DOCUMENT ME!
4088:             */
4089:            public java.sql.ResultSet getPrimaryKeys(String catalog,
4090:                    String schema, final String table) throws SQLException {
4091:                Field[] fields = new Field[6];
4092:                fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 255);
4093:                fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 0);
4094:                fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 255);
4095:                fields[3] = new Field("", "COLUMN_NAME", Types.CHAR, 32);
4096:                fields[4] = new Field("", "KEY_SEQ", Types.SMALLINT, 5);
4097:                fields[5] = new Field("", "PK_NAME", Types.CHAR, 32);
4098:
4099:                if (table == null) {
4100:                    throw SQLError.createSQLException("Table not specified.",
4101:                            SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
4102:                }
4103:
4104:                final ArrayList rows = new ArrayList();
4105:                final Statement stmt = this .conn.getMetadataSafeStatement();
4106:
4107:                try {
4108:
4109:                    new IterateBlock(getCatalogIterator(catalog)) {
4110:                        void forEach(Object catalogStr) throws SQLException {
4111:                            ResultSet rs = null;
4112:
4113:                            try {
4114:
4115:                                StringBuffer queryBuf = new StringBuffer(
4116:                                        "SHOW KEYS FROM ");
4117:                                queryBuf.append(quotedId);
4118:                                queryBuf.append(table);
4119:                                queryBuf.append(quotedId);
4120:                                queryBuf.append(" FROM ");
4121:                                queryBuf.append(quotedId);
4122:                                queryBuf.append(catalogStr.toString());
4123:                                queryBuf.append(quotedId);
4124:
4125:                                rs = stmt.executeQuery(queryBuf.toString());
4126:
4127:                                TreeMap sortMap = new TreeMap();
4128:
4129:                                while (rs.next()) {
4130:                                    String keyType = rs.getString("Key_name");
4131:
4132:                                    if (keyType != null) {
4133:                                        if (keyType.equalsIgnoreCase("PRIMARY")
4134:                                                || keyType
4135:                                                        .equalsIgnoreCase("PRI")) {
4136:                                            byte[][] tuple = new byte[6][];
4137:                                            tuple[0] = ((catalogStr.toString() == null) ? new byte[0]
4138:                                                    : s2b(catalogStr.toString()));
4139:                                            tuple[1] = null;
4140:                                            tuple[2] = s2b(table);
4141:
4142:                                            String columnName = rs
4143:                                                    .getString("Column_name");
4144:                                            tuple[3] = s2b(columnName);
4145:                                            tuple[4] = s2b(rs
4146:                                                    .getString("Seq_in_index"));
4147:                                            tuple[5] = s2b(keyType);
4148:                                            sortMap.put(columnName, tuple);
4149:                                        }
4150:                                    }
4151:                                }
4152:
4153:                                // Now pull out in column name sorted order
4154:                                Iterator sortedIterator = sortMap.values()
4155:                                        .iterator();
4156:
4157:                                while (sortedIterator.hasNext()) {
4158:                                    rows.add(new ByteArrayRow(
4159:                                            (byte[][]) sortedIterator.next()));
4160:                                }
4161:
4162:                            } finally {
4163:                                if (rs != null) {
4164:                                    try {
4165:                                        rs.close();
4166:                                    } catch (Exception ex) {
4167:                                        ;
4168:                                    }
4169:
4170:                                    rs = null;
4171:                                }
4172:                            }
4173:                        }
4174:                    }.doForAll();
4175:                } finally {
4176:                    if (stmt != null) {
4177:                        stmt.close();
4178:                    }
4179:                }
4180:
4181:                java.sql.ResultSet results = buildResultSet(fields, rows);
4182:
4183:                return results;
4184:            }
4185:
4186:            /**
4187:             * Get a description of a catalog's stored procedure parameters and result
4188:             * columns.
4189:             * <P>
4190:             * Only descriptions matching the schema, procedure and parameter name
4191:             * criteria are returned. They are ordered by PROCEDURE_SCHEM and
4192:             * PROCEDURE_NAME. Within this, the return value, if any, is first. Next are
4193:             * the parameter descriptions in call order. The column descriptions follow
4194:             * in column number order.
4195:             * </p>
4196:             * <P>
4197:             * Each row in the ResultSet is a parameter desription or column description
4198:             * with the following fields:
4199:             * <OL>
4200:             * <li> <B>PROCEDURE_CAT</B> String => procedure catalog (may be null)
4201:             * </li>
4202:             * <li> <B>PROCEDURE_SCHEM</B> String => procedure schema (may be null)
4203:             * </li>
4204:             * <li> <B>PROCEDURE_NAME</B> String => procedure name </li>
4205:             * <li> <B>COLUMN_NAME</B> String => column/parameter name </li>
4206:             * <li> <B>COLUMN_TYPE</B> Short => kind of column/parameter:
4207:             * <UL>
4208:             * <li> procedureColumnUnknown - nobody knows </li>
4209:             * <li> procedureColumnIn - IN parameter </li>
4210:             * <li> procedureColumnInOut - INOUT parameter </li>
4211:             * <li> procedureColumnOut - OUT parameter </li>
4212:             * <li> procedureColumnReturn - procedure return value </li>
4213:             * <li> procedureColumnResult - result column in ResultSet </li>
4214:             * </ul>
4215:             * </li>
4216:             * <li> <B>DATA_TYPE</B> short => SQL type from java.sql.Types </li>
4217:             * <li> <B>TYPE_NAME</B> String => SQL type name </li>
4218:             * <li> <B>PRECISION</B> int => precision </li>
4219:             * <li> <B>LENGTH</B> int => length in bytes of data </li>
4220:             * <li> <B>SCALE</B> short => scale </li>
4221:             * <li> <B>RADIX</B> short => radix </li>
4222:             * <li> <B>NULLABLE</B> short => can it contain NULL?
4223:             * <UL>
4224:             * <li> procedureNoNulls - does not allow NULL values </li>
4225:             * <li> procedureNullable - allows NULL values </li>
4226:             * <li> procedureNullableUnknown - nullability unknown </li>
4227:             * </ul>
4228:             * </li>
4229:             * <li> <B>REMARKS</B> String => comment describing parameter/column </li>
4230:             * </ol>
4231:             * </p>
4232:             * <P>
4233:             * <B>Note:</B> Some databases may not return the column descriptions for a
4234:             * procedure. Additional columns beyond REMARKS can be defined by the
4235:             * database.
4236:             * </p>
4237:             * 
4238:             * @param catalog
4239:             *            a catalog name; "" retrieves those without a catalog
4240:             * @param schemaPattern
4241:             *            a schema name pattern; "" retrieves those without a schema
4242:             * @param procedureNamePattern
4243:             *            a procedure name pattern
4244:             * @param columnNamePattern
4245:             *            a column name pattern
4246:             * @return ResultSet each row is a stored procedure parameter or column
4247:             *         description
4248:             * @throws SQLException
4249:             *             if a database access error occurs
4250:             * @see #getSearchStringEscape
4251:             */
4252:            public java.sql.ResultSet getProcedureColumns(String catalog,
4253:                    String schemaPattern, String procedureNamePattern,
4254:                    String columnNamePattern) throws SQLException {
4255:                Field[] fields = new Field[13];
4256:
4257:                fields[0] = new Field("", "PROCEDURE_CAT", Types.CHAR, 0);
4258:                fields[1] = new Field("", "PROCEDURE_SCHEM", Types.CHAR, 0);
4259:                fields[2] = new Field("", "PROCEDURE_NAME", Types.CHAR, 0);
4260:                fields[3] = new Field("", "COLUMN_NAME", Types.CHAR, 0);
4261:                fields[4] = new Field("", "COLUMN_TYPE", Types.CHAR, 0);
4262:                fields[5] = new Field("", "DATA_TYPE", Types.SMALLINT, 0);
4263:                fields[6] = new Field("", "TYPE_NAME", Types.CHAR, 0);
4264:                fields[7] = new Field("", "PRECISION", Types.INTEGER, 0);
4265:                fields[8] = new Field("", "LENGTH", Types.INTEGER, 0);
4266:                fields[9] = new Field("", "SCALE", Types.SMALLINT, 0);
4267:                fields[10] = new Field("", "RADIX", Types.SMALLINT, 0);
4268:                fields[11] = new Field("", "NULLABLE", Types.SMALLINT, 0);
4269:                fields[12] = new Field("", "REMARKS", Types.CHAR, 0);
4270:
4271:                return getProcedureOrFunctionColumns(fields, catalog,
4272:                        schemaPattern, procedureNamePattern, columnNamePattern,
4273:                        true, true);
4274:            }
4275:
4276:            protected java.sql.ResultSet getProcedureOrFunctionColumns(
4277:                    Field[] fields, String catalog, String schemaPattern,
4278:                    String procedureOrFunctionNamePattern,
4279:                    String columnNamePattern, boolean returnProcedures,
4280:                    boolean returnFunctions) throws SQLException {
4281:
4282:                List proceduresToExtractList = new ArrayList();
4283:
4284:                if (supportsStoredProcedures()) {
4285:                    if ((procedureOrFunctionNamePattern.indexOf("%") == -1)
4286:                            && (procedureOrFunctionNamePattern.indexOf("?") == -1)) {
4287:                        proceduresToExtractList
4288:                                .add(procedureOrFunctionNamePattern);
4289:                    } else {
4290:
4291:                        ResultSet procedureNameRs = null;
4292:
4293:                        try {
4294:
4295:                            procedureNameRs = getProceduresAndOrFunctions(
4296:                                    createFieldMetadataForGetProcedures(),
4297:                                    catalog, schemaPattern,
4298:                                    procedureOrFunctionNamePattern,
4299:                                    returnProcedures, returnFunctions);
4300:
4301:                            while (procedureNameRs.next()) {
4302:                                proceduresToExtractList.add(procedureNameRs
4303:                                        .getString(3));
4304:                            }
4305:
4306:                            // Required to be sorted in name-order by JDBC spec,
4307:                            // in 'normal' case getProcedures takes care of this for us,
4308:                            // but if system tables are inaccessible, we need to sort...
4309:                            // so just do this to be safe...
4310:                            Collections.sort(proceduresToExtractList);
4311:                        } finally {
4312:                            SQLException rethrowSqlEx = null;
4313:
4314:                            if (procedureNameRs != null) {
4315:                                try {
4316:                                    procedureNameRs.close();
4317:                                } catch (SQLException sqlEx) {
4318:                                    rethrowSqlEx = sqlEx;
4319:                                }
4320:                            }
4321:
4322:                            if (rethrowSqlEx != null) {
4323:                                throw rethrowSqlEx;
4324:                            }
4325:                        }
4326:                    }
4327:                }
4328:
4329:                ArrayList resultRows = new ArrayList();
4330:
4331:                for (Iterator iter = proceduresToExtractList.iterator(); iter
4332:                        .hasNext();) {
4333:                    String procName = (String) iter.next();
4334:
4335:                    getCallStmtParameterTypes(catalog, procName,
4336:                            columnNamePattern, resultRows, fields.length == 17 /* for getFunctionColumns */);
4337:                }
4338:
4339:                return buildResultSet(fields, resultRows);
4340:            }
4341:
4342:            /**
4343:             * Get a description of stored procedures available in a catalog.
4344:             * <P>
4345:             * Only procedure descriptions matching the schema and procedure name
4346:             * criteria are returned. They are ordered by PROCEDURE_SCHEM, and
4347:             * PROCEDURE_NAME.
4348:             * </p>
4349:             * <P>
4350:             * Each procedure description has the the following columns:
4351:             * <OL>
4352:             * <li> <B>PROCEDURE_CAT</B> String => procedure catalog (may be null)
4353:             * </li>
4354:             * <li> <B>PROCEDURE_SCHEM</B> String => procedure schema (may be null)
4355:             * </li>
4356:             * <li> <B>PROCEDURE_NAME</B> String => procedure name </li>
4357:             * <li> reserved for future use </li>
4358:             * <li> reserved for future use </li>
4359:             * <li> reserved for future use </li>
4360:             * <li> <B>REMARKS</B> String => explanatory comment on the procedure </li>
4361:             * <li> <B>PROCEDURE_TYPE</B> short => kind of procedure:
4362:             * <UL>
4363:             * <li> procedureResultUnknown - May return a result </li>
4364:             * <li> procedureNoResult - Does not return a result </li>
4365:             * <li> procedureReturnsResult - Returns a result </li>
4366:             * </ul>
4367:             * </li>
4368:             * </ol>
4369:             * </p>
4370:             * 
4371:             * @param catalog
4372:             *            a catalog name; "" retrieves those without a catalog
4373:             * @param schemaPattern
4374:             *            a schema name pattern; "" retrieves those without a schema
4375:             * @param procedureNamePattern
4376:             *            a procedure name pattern
4377:             * @return ResultSet each row is a procedure description
4378:             * @throws SQLException
4379:             *             if a database access error occurs
4380:             * @see #getSearchStringEscape
4381:             */
4382:            public java.sql.ResultSet getProcedures(String catalog,
4383:                    String schemaPattern, String procedureNamePattern)
4384:                    throws SQLException {
4385:                Field[] fields = createFieldMetadataForGetProcedures();
4386:
4387:                return getProceduresAndOrFunctions(fields, catalog,
4388:                        schemaPattern, procedureNamePattern, true, true);
4389:            }
4390:
4391:            private Field[] createFieldMetadataForGetProcedures() {
4392:                Field[] fields = new Field[8];
4393:                fields[0] = new Field("", "PROCEDURE_CAT", Types.CHAR, 0);
4394:                fields[1] = new Field("", "PROCEDURE_SCHEM", Types.CHAR, 0);
4395:                fields[2] = new Field("", "PROCEDURE_NAME", Types.CHAR, 0);
4396:                fields[3] = new Field("", "reserved1", Types.CHAR, 0);
4397:                fields[4] = new Field("", "reserved2", Types.CHAR, 0);
4398:                fields[5] = new Field("", "reserved3", Types.CHAR, 0);
4399:                fields[6] = new Field("", "REMARKS", Types.CHAR, 0);
4400:                fields[7] = new Field("", "PROCEDURE_TYPE", Types.SMALLINT, 0);
4401:                return fields;
4402:            }
4403:
4404:            protected java.sql.ResultSet getProceduresAndOrFunctions(
4405:                    final Field[] fields, String catalog, String schemaPattern,
4406:                    String procedureNamePattern,
4407:                    final boolean returnProcedures,
4408:                    final boolean returnFunctions) throws SQLException {
4409:                if ((procedureNamePattern == null)
4410:                        || (procedureNamePattern.length() == 0)) {
4411:                    if (this .conn.getNullNamePatternMatchesAll()) {
4412:                        procedureNamePattern = "%";
4413:                    } else {
4414:                        throw SQLError
4415:                                .createSQLException(
4416:                                        "Procedure name pattern can not be NULL or empty.",
4417:                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
4418:                    }
4419:                }
4420:
4421:                final ArrayList procedureRows = new ArrayList();
4422:
4423:                if (supportsStoredProcedures()) {
4424:                    final String procNamePattern = procedureNamePattern;
4425:
4426:                    final Map procedureRowsOrderedByName = new TreeMap();
4427:
4428:                    new IterateBlock(getCatalogIterator(catalog)) {
4429:                        void forEach(Object catalogStr) throws SQLException {
4430:                            String db = catalogStr.toString();
4431:
4432:                            boolean fromSelect = false;
4433:                            ResultSet proceduresRs = null;
4434:                            boolean needsClientFiltering = true;
4435:                            PreparedStatement proceduresStmt = conn
4436:                                    .clientPrepareStatement("SELECT name, type, comment FROM mysql.proc WHERE name like ? and db <=> ? ORDER BY name");
4437:
4438:                            try {
4439:                                //
4440:                                // Try using system tables first, as this is a little
4441:                                // bit more efficient....
4442:                                //
4443:
4444:                                boolean hasTypeColumn = false;
4445:
4446:                                if (db != null) {
4447:                                    proceduresStmt.setString(2, db);
4448:                                } else {
4449:                                    proceduresStmt.setNull(2, Types.VARCHAR);
4450:                                }
4451:
4452:                                int nameIndex = 1;
4453:
4454:                                if (proceduresStmt.getMaxRows() != 0) {
4455:                                    proceduresStmt.setMaxRows(0);
4456:                                }
4457:
4458:                                proceduresStmt.setString(1, procNamePattern);
4459:
4460:                                try {
4461:                                    proceduresRs = proceduresStmt
4462:                                            .executeQuery();
4463:                                    fromSelect = true;
4464:                                    needsClientFiltering = false;
4465:                                    hasTypeColumn = true;
4466:                                } catch (SQLException sqlEx) {
4467:
4468:                                    //
4469:                                    // Okay, system tables aren't accessible, so use
4470:                                    // 'SHOW
4471:                                    // ....'....
4472:                                    //
4473:                                    proceduresStmt.close();
4474:
4475:                                    fromSelect = false;
4476:
4477:                                    if (conn.versionMeetsMinimum(5, 0, 1)) {
4478:                                        nameIndex = 2;
4479:                                    } else {
4480:                                        nameIndex = 1;
4481:                                    }
4482:
4483:                                    proceduresStmt = conn
4484:                                            .clientPrepareStatement("SHOW PROCEDURE STATUS LIKE ?");
4485:
4486:                                    if (proceduresStmt.getMaxRows() != 0) {
4487:                                        proceduresStmt.setMaxRows(0);
4488:                                    }
4489:
4490:                                    proceduresStmt
4491:                                            .setString(1, procNamePattern);
4492:
4493:                                    proceduresRs = proceduresStmt
4494:                                            .executeQuery();
4495:                                }
4496:
4497:                                if (returnProcedures) {
4498:                                    convertToJdbcProcedureList(fromSelect, db,
4499:                                            proceduresRs, needsClientFiltering,
4500:                                            db, procedureRowsOrderedByName,
4501:                                            nameIndex);
4502:                                }
4503:
4504:                                if (!hasTypeColumn) {
4505:                                    // need to go after functions too...
4506:                                    if (proceduresStmt != null) {
4507:                                        proceduresStmt.close();
4508:                                    }
4509:
4510:                                    proceduresStmt = conn
4511:                                            .clientPrepareStatement("SHOW FUNCTION STATUS LIKE ?");
4512:
4513:                                    if (proceduresStmt.getMaxRows() != 0) {
4514:                                        proceduresStmt.setMaxRows(0);
4515:                                    }
4516:
4517:                                    proceduresStmt
4518:                                            .setString(1, procNamePattern);
4519:
4520:                                    proceduresRs = proceduresStmt
4521:                                            .executeQuery();
4522:
4523:                                    if (returnFunctions) {
4524:                                        convertToJdbcFunctionList(db,
4525:                                                proceduresRs,
4526:                                                needsClientFiltering, db,
4527:                                                procedureRowsOrderedByName,
4528:                                                nameIndex, fields);
4529:                                    }
4530:                                }
4531:
4532:                                // Now, sort them
4533:
4534:                                Iterator proceduresIter = procedureRowsOrderedByName
4535:                                        .values().iterator();
4536:
4537:                                while (proceduresIter.hasNext()) {
4538:                                    procedureRows.add(proceduresIter.next());
4539:                                }
4540:                            } finally {
4541:                                SQLException rethrowSqlEx = null;
4542:
4543:                                if (proceduresRs != null) {
4544:                                    try {
4545:                                        proceduresRs.close();
4546:                                    } catch (SQLException sqlEx) {
4547:                                        rethrowSqlEx = sqlEx;
4548:                                    }
4549:                                }
4550:
4551:                                if (proceduresStmt != null) {
4552:                                    try {
4553:                                        proceduresStmt.close();
4554:                                    } catch (SQLException sqlEx) {
4555:                                        rethrowSqlEx = sqlEx;
4556:                                    }
4557:                                }
4558:
4559:                                if (rethrowSqlEx != null) {
4560:                                    throw rethrowSqlEx;
4561:                                }
4562:                            }
4563:                        }
4564:                    }.doForAll();
4565:                }
4566:
4567:                return buildResultSet(fields, procedureRows);
4568:            }
4569:
4570:            /**
4571:             * What's the database vendor's preferred term for "procedure"?
4572:             * 
4573:             * @return the vendor term
4574:             * @throws SQLException
4575:             *             if an error occurs (don't know why it would in this case...)
4576:             */
4577:            public String getProcedureTerm() throws SQLException {
4578:                return "PROCEDURE";
4579:            }
4580:
4581:            /**
4582:             * @see DatabaseMetaData#getResultSetHoldability()
4583:             */
4584:            public int getResultSetHoldability() throws SQLException {
4585:                return ResultSet.HOLD_CURSORS_OVER_COMMIT;
4586:            }
4587:
4588:            private void getResultsImpl(String catalog, String table,
4589:                    String keysComment, List tuples, String fkTableName,
4590:                    boolean isExport) throws SQLException {
4591:
4592:                LocalAndReferencedColumns parsedInfo = parseTableStatusIntoLocalAndReferencedColumns(keysComment);
4593:
4594:                if (isExport && !parsedInfo.referencedTable.equals(table)) {
4595:                    return;
4596:                }
4597:
4598:                if (parsedInfo.localColumnsList.size() != parsedInfo.referencedColumnsList
4599:                        .size()) {
4600:                    throw SQLError
4601:                            .createSQLException(
4602:                                    "Error parsing foreign keys definition,"
4603:                                            + "number of local and referenced columns is not the same.",
4604:                                    SQLError.SQL_STATE_GENERAL_ERROR);
4605:                }
4606:
4607:                Iterator localColumnNames = parsedInfo.localColumnsList
4608:                        .iterator();
4609:                Iterator referColumnNames = parsedInfo.referencedColumnsList
4610:                        .iterator();
4611:
4612:                int keySeqIndex = 1;
4613:
4614:                while (localColumnNames.hasNext()) {
4615:                    byte[][] tuple = new byte[14][];
4616:                    String lColumnName = removeQuotedId(localColumnNames.next()
4617:                            .toString());
4618:                    String rColumnName = removeQuotedId(referColumnNames.next()
4619:                            .toString());
4620:                    tuple[FKTABLE_CAT] = ((catalog == null) ? new byte[0]
4621:                            : s2b(catalog));
4622:                    tuple[FKTABLE_SCHEM] = null;
4623:                    tuple[FKTABLE_NAME] = s2b((isExport) ? fkTableName : table);
4624:                    tuple[FKCOLUMN_NAME] = s2b(lColumnName);
4625:                    tuple[PKTABLE_CAT] = s2b(parsedInfo.referencedCatalog);
4626:                    tuple[PKTABLE_SCHEM] = null;
4627:                    tuple[PKTABLE_NAME] = s2b((isExport) ? table
4628:                            : parsedInfo.referencedTable);
4629:                    tuple[PKCOLUMN_NAME] = s2b(rColumnName);
4630:                    tuple[KEY_SEQ] = s2b(Integer.toString(keySeqIndex++));
4631:
4632:                    int[] actions = getForeignKeyActions(keysComment);
4633:
4634:                    tuple[UPDATE_RULE] = s2b(Integer.toString(actions[1]));
4635:                    tuple[DELETE_RULE] = s2b(Integer.toString(actions[0]));
4636:                    tuple[FK_NAME] = s2b(parsedInfo.constraintName);
4637:                    tuple[PK_NAME] = null; // not available from show table status
4638:                    tuple[DEFERRABILITY] = s2b(Integer
4639:                            .toString(java.sql.DatabaseMetaData.importedKeyNotDeferrable));
4640:                    tuples.add(new ByteArrayRow(tuple));
4641:                }
4642:            }
4643:
4644:            /**
4645:             * Get the schema names available in this database. The results are ordered
4646:             * by schema name.
4647:             * <P>
4648:             * The schema column is:
4649:             * <OL>
4650:             * <li> <B>TABLE_SCHEM</B> String => schema name </li>
4651:             * </ol>
4652:             * </p>
4653:             * 
4654:             * @return ResultSet each row has a single String column that is a schema
4655:             *         name
4656:             * @throws SQLException
4657:             *             DOCUMENT ME!
4658:             */
4659:            public java.sql.ResultSet getSchemas() throws SQLException {
4660:                Field[] fields = new Field[2];
4661:                fields[0] = new Field("", "TABLE_SCHEM", java.sql.Types.CHAR, 0);
4662:                fields[1] = new Field("", "TABLE_CATALOG", java.sql.Types.CHAR,
4663:                        0);
4664:
4665:                ArrayList tuples = new ArrayList();
4666:                java.sql.ResultSet results = buildResultSet(fields, tuples);
4667:
4668:                return results;
4669:            }
4670:
4671:            /**
4672:             * What's the database vendor's preferred term for "schema"?
4673:             * 
4674:             * @return the vendor term
4675:             * @throws SQLException
4676:             *             DOCUMENT ME!
4677:             */
4678:            public String getSchemaTerm() throws SQLException {
4679:                return "";
4680:            }
4681:
4682:            /**
4683:             * This is the string that can be used to escape '_' or '%' in the string
4684:             * pattern style catalog search parameters.
4685:             * <P>
4686:             * The '_' character represents any single character.
4687:             * </p>
4688:             * <P>
4689:             * The '%' character represents any sequence of zero or more characters.
4690:             * </p>
4691:             * 
4692:             * @return the string used to escape wildcard characters
4693:             * @throws SQLException
4694:             *             DOCUMENT ME!
4695:             */
4696:            public String getSearchStringEscape() throws SQLException {
4697:                return "\\";
4698:            }
4699:
4700:            /**
4701:             * Get a comma separated list of all a database's SQL keywords that are NOT
4702:             * also SQL92 keywords.
4703:             * 
4704:             * @return the list
4705:             * @throws SQLException
4706:             *             DOCUMENT ME!
4707:             */
4708:            public String getSQLKeywords() throws SQLException {
4709:                return mysqlKeywordsThatArentSQL92;
4710:            }
4711:
4712:            /**
4713:             * @see DatabaseMetaData#getSQLStateType()
4714:             */
4715:            public int getSQLStateType() throws SQLException {
4716:                if (this .conn.versionMeetsMinimum(4, 1, 0)) {
4717:                    return DatabaseMetaData.sqlStateSQL99;
4718:                }
4719:
4720:                if (this .conn.getUseSqlStateCodes()) {
4721:                    return DatabaseMetaData.sqlStateSQL99;
4722:                }
4723:
4724:                return DatabaseMetaData.sqlStateXOpen;
4725:            }
4726:
4727:            /**
4728:             * Get a comma separated list of string functions.
4729:             * 
4730:             * @return the list
4731:             * @throws SQLException
4732:             *             DOCUMENT ME!
4733:             */
4734:            public String getStringFunctions() throws SQLException {
4735:                return "ASCII,BIN,BIT_LENGTH,CHAR,CHARACTER_LENGTH,CHAR_LENGTH,CONCAT,"
4736:                        + "CONCAT_WS,CONV,ELT,EXPORT_SET,FIELD,FIND_IN_SET,HEX,INSERT,"
4737:                        + "INSTR,LCASE,LEFT,LENGTH,LOAD_FILE,LOCATE,LOCATE,LOWER,LPAD,"
4738:                        + "LTRIM,MAKE_SET,MATCH,MID,OCT,OCTET_LENGTH,ORD,POSITION,"
4739:                        + "QUOTE,REPEAT,REPLACE,REVERSE,RIGHT,RPAD,RTRIM,SOUNDEX,"
4740:                        + "SPACE,STRCMP,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING,"
4741:                        + "SUBSTRING_INDEX,TRIM,UCASE,UPPER";
4742:            }
4743:
4744:            /**
4745:             * @see DatabaseMetaData#getSuperTables(String, String, String)
4746:             */
4747:            public java.sql.ResultSet getSuperTables(String arg0, String arg1,
4748:                    String arg2) throws SQLException {
4749:                Field[] fields = new Field[4];
4750:                fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 32);
4751:                fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 32);
4752:                fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 32);
4753:                fields[3] = new Field("", "SUPERTABLE_NAME", Types.CHAR, 32);
4754:
4755:                return buildResultSet(fields, new ArrayList());
4756:            }
4757:
4758:            /**
4759:             * @see DatabaseMetaData#getSuperTypes(String, String, String)
4760:             */
4761:            public java.sql.ResultSet getSuperTypes(String arg0, String arg1,
4762:                    String arg2) throws SQLException {
4763:                Field[] fields = new Field[6];
4764:                fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 32);
4765:                fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 32);
4766:                fields[2] = new Field("", "TYPE_NAME", Types.CHAR, 32);
4767:                fields[3] = new Field("", "SUPERTYPE_CAT", Types.CHAR, 32);
4768:                fields[4] = new Field("", "SUPERTYPE_SCHEM", Types.CHAR, 32);
4769:                fields[5] = new Field("", "SUPERTYPE_NAME", Types.CHAR, 32);
4770:
4771:                return buildResultSet(fields, new ArrayList());
4772:            }
4773:
4774:            /**
4775:             * Get a comma separated list of system functions.
4776:             * 
4777:             * @return the list
4778:             * @throws SQLException
4779:             *             DOCUMENT ME!
4780:             */
4781:            public String getSystemFunctions() throws SQLException {
4782:                return "DATABASE,USER,SYSTEM_USER,SESSION_USER,PASSWORD,ENCRYPT,LAST_INSERT_ID,VERSION";
4783:            }
4784:
4785:            private String getTableNameWithCase(String table) {
4786:                String tableNameWithCase = (this .conn.lowerCaseTableNames() ? table
4787:                        .toLowerCase()
4788:                        : table);
4789:
4790:                return tableNameWithCase;
4791:            }
4792:
4793:            /**
4794:             * Get a description of the access rights for each table available in a
4795:             * catalog.
4796:             * <P>
4797:             * Only privileges matching the schema and table name criteria are returned.
4798:             * They are ordered by TABLE_SCHEM, TABLE_NAME, and PRIVILEGE.
4799:             * </p>
4800:             * <P>
4801:             * Each privilige description has the following columns:
4802:             * <OL>
4803:             * <li> <B>TABLE_CAT</B> String => table catalog (may be null) </li>
4804:             * <li> <B>TABLE_SCHEM</B> String => table schema (may be null) </li>
4805:             * <li> <B>TABLE_NAME</B> String => table name </li>
4806:             * <li> <B>COLUMN_NAME</B> String => column name </li>
4807:             * <li> <B>GRANTOR</B> => grantor of access (may be null) </li>
4808:             * <li> <B>GRANTEE</B> String => grantee of access </li>
4809:             * <li> <B>PRIVILEGE</B> String => name of access (SELECT, INSERT, UPDATE,
4810:             * REFRENCES, ...) </li>
4811:             * <li> <B>IS_GRANTABLE</B> String => "YES" if grantee is permitted to
4812:             * grant to others; "NO" if not; null if unknown </li>
4813:             * </ol>
4814:             * </p>
4815:             * 
4816:             * @param catalog
4817:             *            a catalog name; "" retrieves those without a catalog
4818:             * @param schemaPattern
4819:             *            a schema name pattern; "" retrieves those without a schema
4820:             * @param tableNamePattern
4821:             *            a table name pattern
4822:             * @return ResultSet each row is a table privilege description
4823:             * @throws SQLException
4824:             *             if a database access error occurs
4825:             * @see #getSearchStringEscape
4826:             */
4827:            public java.sql.ResultSet getTablePrivileges(String catalog,
4828:                    String schemaPattern, String tableNamePattern)
4829:                    throws SQLException {
4830:
4831:                if (tableNamePattern == null) {
4832:                    if (this .conn.getNullNamePatternMatchesAll()) {
4833:                        tableNamePattern = "%";
4834:                    } else {
4835:                        throw SQLError.createSQLException(
4836:                                "Table name pattern can not be NULL or empty.",
4837:                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
4838:                    }
4839:                }
4840:
4841:                Field[] fields = new Field[7];
4842:                fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 64);
4843:                fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 1);
4844:                fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 64);
4845:                fields[3] = new Field("", "GRANTOR", Types.CHAR, 77);
4846:                fields[4] = new Field("", "GRANTEE", Types.CHAR, 77);
4847:                fields[5] = new Field("", "PRIVILEGE", Types.CHAR, 64);
4848:                fields[6] = new Field("", "IS_GRANTABLE", Types.CHAR, 3);
4849:
4850:                StringBuffer grantQuery = new StringBuffer(
4851:                        "SELECT host,db,table_name,grantor,user,table_priv from mysql.tables_priv ");
4852:                grantQuery.append(" WHERE ");
4853:
4854:                if ((catalog != null) && (catalog.length() != 0)) {
4855:                    grantQuery.append(" db='");
4856:                    grantQuery.append(catalog);
4857:                    grantQuery.append("' AND ");
4858:                }
4859:
4860:                grantQuery.append("table_name like '");
4861:                grantQuery.append(tableNamePattern);
4862:                grantQuery.append("'");
4863:
4864:                ResultSet results = null;
4865:                ArrayList grantRows = new ArrayList();
4866:                Statement stmt = null;
4867:
4868:                try {
4869:                    stmt = this .conn.createStatement();
4870:                    stmt.setEscapeProcessing(false);
4871:
4872:                    results = stmt.executeQuery(grantQuery.toString());
4873:
4874:                    while (results.next()) {
4875:                        String host = results.getString(1);
4876:                        String db = results.getString(2);
4877:                        String table = results.getString(3);
4878:                        String grantor = results.getString(4);
4879:                        String user = results.getString(5);
4880:
4881:                        if ((user == null) || (user.length() == 0)) {
4882:                            user = "%";
4883:                        }
4884:
4885:                        StringBuffer fullUser = new StringBuffer(user);
4886:
4887:                        if ((host != null)
4888:                                && this .conn.getUseHostsInPrivileges()) {
4889:                            fullUser.append("@");
4890:                            fullUser.append(host);
4891:                        }
4892:
4893:                        String allPrivileges = results.getString(6);
4894:
4895:                        if (allPrivileges != null) {
4896:                            allPrivileges = allPrivileges
4897:                                    .toUpperCase(Locale.ENGLISH);
4898:
4899:                            StringTokenizer st = new StringTokenizer(
4900:                                    allPrivileges, ",");
4901:
4902:                            while (st.hasMoreTokens()) {
4903:                                String privilege = st.nextToken().trim();
4904:
4905:                                // Loop through every column in the table
4906:                                java.sql.ResultSet columnResults = null;
4907:
4908:                                try {
4909:                                    columnResults = getColumns(catalog,
4910:                                            schemaPattern, table, "%");
4911:
4912:                                    while (columnResults.next()) {
4913:                                        byte[][] tuple = new byte[8][];
4914:                                        tuple[0] = s2b(db);
4915:                                        tuple[1] = null;
4916:                                        tuple[2] = s2b(table);
4917:
4918:                                        if (grantor != null) {
4919:                                            tuple[3] = s2b(grantor);
4920:                                        } else {
4921:                                            tuple[3] = null;
4922:                                        }
4923:
4924:                                        tuple[4] = s2b(fullUser.toString());
4925:                                        tuple[5] = s2b(privilege);
4926:                                        tuple[6] = null;
4927:                                        grantRows.add(new ByteArrayRow(tuple));
4928:                                    }
4929:                                } finally {
4930:                                    if (columnResults != null) {
4931:                                        try {
4932:                                            columnResults.close();
4933:                                        } catch (Exception ex) {
4934:                                            ;
4935:                                        }
4936:                                    }
4937:                                }
4938:                            }
4939:                        }
4940:                    }
4941:                } finally {
4942:                    if (results != null) {
4943:                        try {
4944:                            results.close();
4945:                        } catch (Exception ex) {
4946:                            ;
4947:                        }
4948:
4949:                        results = null;
4950:                    }
4951:
4952:                    if (stmt != null) {
4953:                        try {
4954:                            stmt.close();
4955:                        } catch (Exception ex) {
4956:                            ;
4957:                        }
4958:
4959:                        stmt = null;
4960:                    }
4961:                }
4962:
4963:                return buildResultSet(fields, grantRows);
4964:            }
4965:
4966:            /**
4967:             * Get a description of tables available in a catalog.
4968:             * <P>
4969:             * Only table descriptions matching the catalog, schema, table name and type
4970:             * criteria are returned. They are ordered by TABLE_TYPE, TABLE_SCHEM and
4971:             * TABLE_NAME.
4972:             * </p>
4973:             * <P>
4974:             * Each table description has the following columns:
4975:             * <OL>
4976:             * <li> <B>TABLE_CAT</B> String => table catalog (may be null) </li>
4977:             * <li> <B>TABLE_SCHEM</B> String => table schema (may be null) </li>
4978:             * <li> <B>TABLE_NAME</B> String => table name </li>
4979:             * <li> <B>TABLE_TYPE</B> String => table type. Typical types are "TABLE",
4980:             * "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS",
4981:             * "SYNONYM". </li>
4982:             * <li> <B>REMARKS</B> String => explanatory comment on the table </li>
4983:             * </ol>
4984:             * </p>
4985:             * <P>
4986:             * <B>Note:</B> Some databases may not return information for all tables.
4987:             * </p>
4988:             * 
4989:             * @param catalog
4990:             *            a catalog name; "" retrieves those without a catalog
4991:             * @param schemaPattern
4992:             *            a schema name pattern; "" retrieves those without a schema
4993:             * @param tableNamePattern
4994:             *            a table name pattern
4995:             * @param types
4996:             *            a list of table types to include; null returns all types
4997:             * @return ResultSet each row is a table description
4998:             * @throws SQLException
4999:             *             DOCUMENT ME!
5000:             * @see #getSearchStringEscape
5001:             */
5002:            public java.sql.ResultSet getTables(String catalog,
5003:                    String schemaPattern, String tableNamePattern,
5004:                    final String[] types) throws SQLException {
5005:
5006:                if (tableNamePattern == null) {
5007:                    if (this .conn.getNullNamePatternMatchesAll()) {
5008:                        tableNamePattern = "%";
5009:                    } else {
5010:                        throw SQLError.createSQLException(
5011:                                "Table name pattern can not be NULL or empty.",
5012:                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
5013:                    }
5014:                }
5015:
5016:                Field[] fields = new Field[5];
5017:                fields[0] = new Field("", "TABLE_CAT", java.sql.Types.VARCHAR,
5018:                        255);
5019:                fields[1] = new Field("", "TABLE_SCHEM",
5020:                        java.sql.Types.VARCHAR, 0);
5021:                fields[2] = new Field("", "TABLE_NAME", java.sql.Types.VARCHAR,
5022:                        255);
5023:                fields[3] = new Field("", "TABLE_TYPE", java.sql.Types.VARCHAR,
5024:                        5);
5025:                fields[4] = new Field("", "REMARKS", java.sql.Types.VARCHAR, 0);
5026:
5027:                final ArrayList tuples = new ArrayList();
5028:
5029:                final Statement stmt = this .conn.getMetadataSafeStatement();
5030:
5031:                final String tableNamePat = tableNamePattern;
5032:
5033:                try {
5034:
5035:                    new IterateBlock(getCatalogIterator(catalog)) {
5036:                        void forEach(Object catalogStr) throws SQLException {
5037:                            ResultSet results = null;
5038:
5039:                            try {
5040:
5041:                                if (!conn.versionMeetsMinimum(5, 0, 2)) {
5042:                                    try {
5043:                                        results = stmt
5044:                                                .executeQuery("SHOW TABLES FROM "
5045:                                                        + quotedId
5046:                                                        + catalogStr.toString()
5047:                                                        + quotedId
5048:                                                        + " LIKE '"
5049:                                                        + tableNamePat + "'");
5050:                                    } catch (SQLException sqlEx) {
5051:                                        if (SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE
5052:                                                .equals(sqlEx.getSQLState())) {
5053:                                            throw sqlEx;
5054:                                        }
5055:
5056:                                        return;
5057:                                    }
5058:                                } else {
5059:                                    try {
5060:                                        results = stmt
5061:                                                .executeQuery("SHOW FULL TABLES FROM "
5062:                                                        + quotedId
5063:                                                        + catalogStr.toString()
5064:                                                        + quotedId
5065:                                                        + " LIKE '"
5066:                                                        + tableNamePat + "'");
5067:                                    } catch (SQLException sqlEx) {
5068:                                        if (SQLError.SQL_STATE_COMMUNICATION_LINK_FAILURE
5069:                                                .equals(sqlEx.getSQLState())) {
5070:                                            throw sqlEx;
5071:                                        }
5072:
5073:                                        return;
5074:                                    }
5075:                                }
5076:
5077:                                boolean shouldReportTables = false;
5078:                                boolean shouldReportViews = false;
5079:
5080:                                if (types == null || types.length == 0) {
5081:                                    shouldReportTables = true;
5082:                                    shouldReportViews = true;
5083:                                } else {
5084:                                    for (int i = 0; i < types.length; i++) {
5085:                                        if ("TABLE".equalsIgnoreCase(types[i])) {
5086:                                            shouldReportTables = true;
5087:                                        }
5088:
5089:                                        if ("VIEW".equalsIgnoreCase(types[i])) {
5090:                                            shouldReportViews = true;
5091:                                        }
5092:                                    }
5093:                                }
5094:
5095:                                int typeColumnIndex = 0;
5096:                                boolean hasTableTypes = false;
5097:
5098:                                if (conn.versionMeetsMinimum(5, 0, 2)) {
5099:                                    try {
5100:                                        // Both column names have been in use in the
5101:                                        // source tree
5102:                                        // so far....
5103:                                        typeColumnIndex = results
5104:                                                .findColumn("table_type");
5105:                                        hasTableTypes = true;
5106:                                    } catch (SQLException sqlEx) {
5107:
5108:                                        // We should probably check SQLState here, but
5109:                                        // that
5110:                                        // can change depending on the server version
5111:                                        // and
5112:                                        // user properties, however, we'll get a 'true'
5113:                                        // SQLException when we actually try to find the
5114:                                        // 'Type' column
5115:                                        // 
5116:                                        try {
5117:                                            typeColumnIndex = results
5118:                                                    .findColumn("Type");
5119:                                            hasTableTypes = true;
5120:                                        } catch (SQLException sqlEx2) {
5121:                                            hasTableTypes = false;
5122:                                        }
5123:                                    }
5124:                                }
5125:
5126:                                TreeMap tablesOrderedByName = null;
5127:                                TreeMap viewsOrderedByName = null;
5128:
5129:                                while (results.next()) {
5130:                                    byte[][] row = new byte[5][];
5131:                                    row[0] = (catalogStr.toString() == null) ? null
5132:                                            : s2b(catalogStr.toString());
5133:                                    row[1] = null;
5134:                                    row[2] = results.getBytes(1);
5135:                                    row[4] = new byte[0];
5136:
5137:                                    if (hasTableTypes) {
5138:                                        String tableType = results
5139:                                                .getString(typeColumnIndex);
5140:
5141:                                        if (("table"
5142:                                                .equalsIgnoreCase(tableType) || "base table"
5143:                                                .equalsIgnoreCase(tableType))
5144:                                                && shouldReportTables) {
5145:                                            row[3] = TABLE_AS_BYTES;
5146:
5147:                                            if (tablesOrderedByName == null) {
5148:                                                tablesOrderedByName = new TreeMap();
5149:                                            }
5150:
5151:                                            tablesOrderedByName.put(results
5152:                                                    .getString(1), row);
5153:                                        } else if ("view"
5154:                                                .equalsIgnoreCase(tableType)
5155:                                                && shouldReportViews) {
5156:                                            row[3] = VIEW_AS_BYTES;
5157:
5158:                                            if (viewsOrderedByName == null) {
5159:                                                viewsOrderedByName = new TreeMap();
5160:                                            }
5161:
5162:                                            viewsOrderedByName.put(results
5163:                                                    .getString(1), row);
5164:                                        } else if (!hasTableTypes) {
5165:                                            // punt?
5166:                                            row[3] = TABLE_AS_BYTES;
5167:
5168:                                            if (tablesOrderedByName == null) {
5169:                                                tablesOrderedByName = new TreeMap();
5170:                                            }
5171:
5172:                                            tablesOrderedByName.put(results
5173:                                                    .getString(1), row);
5174:                                        }
5175:                                    } else {
5176:                                        if (shouldReportTables) {
5177:                                            // Pre-MySQL-5.0.1, tables only
5178:                                            row[3] = TABLE_AS_BYTES;
5179:
5180:                                            if (tablesOrderedByName == null) {
5181:                                                tablesOrderedByName = new TreeMap();
5182:                                            }
5183:
5184:                                            tablesOrderedByName.put(results
5185:                                                    .getString(1), row);
5186:                                        }
5187:                                    }
5188:                                }
5189:
5190:                                // They are ordered by TABLE_TYPE,
5191:                                // * TABLE_SCHEM and TABLE_NAME.
5192:
5193:                                if (tablesOrderedByName != null) {
5194:                                    Iterator tablesIter = tablesOrderedByName
5195:                                            .values().iterator();
5196:
5197:                                    while (tablesIter.hasNext()) {
5198:                                        tuples.add(new ByteArrayRow(
5199:                                                (byte[][]) tablesIter.next()));
5200:                                    }
5201:                                }
5202:
5203:                                if (viewsOrderedByName != null) {
5204:                                    Iterator viewsIter = viewsOrderedByName
5205:                                            .values().iterator();
5206:
5207:                                    while (viewsIter.hasNext()) {
5208:                                        tuples.add(new ByteArrayRow(
5209:                                                (byte[][]) viewsIter.next()));
5210:                                    }
5211:                                }
5212:
5213:                            } finally {
5214:                                if (results != null) {
5215:                                    try {
5216:                                        results.close();
5217:                                    } catch (Exception ex) {
5218:                                        ;
5219:                                    }
5220:
5221:                                    results = null;
5222:                                }
5223:
5224:                            }
5225:                        }
5226:                    }.doForAll();
5227:                } finally {
5228:                    if (stmt != null) {
5229:                        stmt.close();
5230:                    }
5231:                }
5232:
5233:                java.sql.ResultSet tables = buildResultSet(fields, tuples);
5234:
5235:                return tables;
5236:            }
5237:
5238:            /**
5239:             * Get the table types available in this database. The results are ordered
5240:             * by table type.
5241:             * <P>
5242:             * The table type is:
5243:             * <OL>
5244:             * <li> <B>TABLE_TYPE</B> String => table type. Typical types are "TABLE",
5245:             * "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS",
5246:             * "SYNONYM". </li>
5247:             * </ol>
5248:             * </p>
5249:             * 
5250:             * @return ResultSet each row has a single String column that is a table
5251:             *         type
5252:             * @throws SQLException
5253:             *             DOCUMENT ME!
5254:             */
5255:            public java.sql.ResultSet getTableTypes() throws SQLException {
5256:                ArrayList tuples = new ArrayList();
5257:                Field[] fields = new Field[1];
5258:                fields[0] = new Field("", "TABLE_TYPE", Types.VARCHAR, 5);
5259:
5260:                byte[][] tableTypeRow = new byte[1][];
5261:                tableTypeRow[0] = TABLE_AS_BYTES;
5262:                tuples.add(new ByteArrayRow(tableTypeRow));
5263:
5264:                if (this .conn.versionMeetsMinimum(5, 0, 1)) {
5265:                    byte[][] viewTypeRow = new byte[1][];
5266:                    viewTypeRow[0] = VIEW_AS_BYTES;
5267:                    tuples.add(new ByteArrayRow(viewTypeRow));
5268:                }
5269:
5270:                byte[][] tempTypeRow = new byte[1][];
5271:                tempTypeRow[0] = s2b("LOCAL TEMPORARY");
5272:                tuples.add(new ByteArrayRow(tempTypeRow));
5273:
5274:                return buildResultSet(fields, tuples);
5275:            }
5276:
5277:            /**
5278:             * Get a comma separated list of time and date functions.
5279:             * 
5280:             * @return the list
5281:             * @throws SQLException
5282:             *             DOCUMENT ME!
5283:             */
5284:            public String getTimeDateFunctions() throws SQLException {
5285:                return "DAYOFWEEK,WEEKDAY,DAYOFMONTH,DAYOFYEAR,MONTH,DAYNAME,"
5286:                        + "MONTHNAME,QUARTER,WEEK,YEAR,HOUR,MINUTE,SECOND,PERIOD_ADD,"
5287:                        + "PERIOD_DIFF,TO_DAYS,FROM_DAYS,DATE_FORMAT,TIME_FORMAT,"
5288:                        + "CURDATE,CURRENT_DATE,CURTIME,CURRENT_TIME,NOW,SYSDATE,"
5289:                        + "CURRENT_TIMESTAMP,UNIX_TIMESTAMP,FROM_UNIXTIME,"
5290:                        + "SEC_TO_TIME,TIME_TO_SEC";
5291:            }
5292:
5293:            /**
5294:             * Get a description of all the standard SQL types supported by this
5295:             * database. They are ordered by DATA_TYPE and then by how closely the data
5296:             * type maps to the corresponding JDBC SQL type.
5297:             * <P>
5298:             * Each type description has the following columns:
5299:             * <OL>
5300:             * <li> <B>TYPE_NAME</B> String => Type name </li>
5301:             * <li> <B>DATA_TYPE</B> short => SQL data type from java.sql.Types </li>
5302:             * <li> <B>PRECISION</B> int => maximum precision </li>
5303:             * <li> <B>LITERAL_PREFIX</B> String => prefix used to quote a literal (may
5304:             * be null) </li>
5305:             * <li> <B>LITERAL_SUFFIX</B> String => suffix used to quote a literal (may
5306:             * be null) </li>
5307:             * <li> <B>CREATE_PARAMS</B> String => parameters used in creating the type
5308:             * (may be null) </li>
5309:             * <li> <B>NULLABLE</B> short => can you use NULL for this type?
5310:             * <UL>
5311:             * <li> typeNoNulls - does not allow NULL values </li>
5312:             * <li> typeNullable - allows NULL values </li>
5313:             * <li> typeNullableUnknown - nullability unknown </li>
5314:             * </ul>
5315:             * </li>
5316:             * <li> <B>CASE_SENSITIVE</B> boolean=> is it case sensitive? </li>
5317:             * <li> <B>SEARCHABLE</B> short => can you use "WHERE" based on this type:
5318:             * <UL>
5319:             * <li> typePredNone - No support </li>
5320:             * <li> typePredChar - Only supported with WHERE .. LIKE </li>
5321:             * <li> typePredBasic - Supported except for WHERE .. LIKE </li>
5322:             * <li> typeSearchable - Supported for all WHERE .. </li>
5323:             * </ul>
5324:             * </li>
5325:             * <li> <B>UNSIGNED_ATTRIBUTE</B> boolean => is it unsigned? </li>
5326:             * <li> <B>FIXED_PREC_SCALE</B> boolean => can it be a money value? </li>
5327:             * <li> <B>AUTO_INCREMENT</B> boolean => can it be used for an
5328:             * auto-increment value? </li>
5329:             * <li> <B>LOCAL_TYPE_NAME</B> String => localized version of type name
5330:             * (may be null) </li>
5331:             * <li> <B>MINIMUM_SCALE</B> short => minimum scale supported </li>
5332:             * <li> <B>MAXIMUM_SCALE</B> short => maximum scale supported </li>
5333:             * <li> <B>SQL_DATA_TYPE</B> int => unused </li>
5334:             * <li> <B>SQL_DATETIME_SUB</B> int => unused </li>
5335:             * <li> <B>NUM_PREC_RADIX</B> int => usually 2 or 10 </li>
5336:             * </ol>
5337:             * </p>
5338:             * 
5339:             * @return ResultSet each row is a SQL type description
5340:             * @throws SQLException
5341:             *             DOCUMENT ME!
5342:             */
5343:            /**
5344:             * Get a description of all the standard SQL types supported by this
5345:             * database. They are ordered by DATA_TYPE and then by how closely the data
5346:             * type maps to the corresponding JDBC SQL type.
5347:             * <P>
5348:             * Each type description has the following columns:
5349:             * <OL>
5350:             * <li> <B>TYPE_NAME</B> String => Type name </li>
5351:             * <li> <B>DATA_TYPE</B> short => SQL data type from java.sql.Types </li>
5352:             * <li> <B>PRECISION</B> int => maximum precision </li>
5353:             * <li> <B>LITERAL_PREFIX</B> String => prefix used to quote a literal (may
5354:             * be null) </li>
5355:             * <li> <B>LITERAL_SUFFIX</B> String => suffix used to quote a literal (may
5356:             * be null) </li>
5357:             * <li> <B>CREATE_PARAMS</B> String => parameters used in creating the type
5358:             * (may be null) </li>
5359:             * <li> <B>NULLABLE</B> short => can you use NULL for this type?
5360:             * <UL>
5361:             * <li> typeNoNulls - does not allow NULL values </li>
5362:             * <li> typeNullable - allows NULL values </li>
5363:             * <li> typeNullableUnknown - nullability unknown </li>
5364:             * </ul>
5365:             * </li>
5366:             * <li> <B>CASE_SENSITIVE</B> boolean=> is it case sensitive? </li>
5367:             * <li> <B>SEARCHABLE</B> short => can you use "WHERE" based on this type:
5368:             * <UL>
5369:             * <li> typePredNone - No support </li>
5370:             * <li> typePredChar - Only supported with WHERE .. LIKE </li>
5371:             * <li> typePredBasic - Supported except for WHERE .. LIKE </li>
5372:             * <li> typeSearchable - Supported for all WHERE .. </li>
5373:             * </ul>
5374:             * </li>
5375:             * <li> <B>UNSIGNED_ATTRIBUTE</B> boolean => is it unsigned? </li>
5376:             * <li> <B>FIXED_PREC_SCALE</B> boolean => can it be a money value? </li>
5377:             * <li> <B>AUTO_INCREMENT</B> boolean => can it be used for an
5378:             * auto-increment value? </li>
5379:             * <li> <B>LOCAL_TYPE_NAME</B> String => localized version of type name
5380:             * (may be null) </li>
5381:             * <li> <B>MINIMUM_SCALE</B> short => minimum scale supported </li>
5382:             * <li> <B>MAXIMUM_SCALE</B> short => maximum scale supported </li>
5383:             * <li> <B>SQL_DATA_TYPE</B> int => unused </li>
5384:             * <li> <B>SQL_DATETIME_SUB</B> int => unused </li>
5385:             * <li> <B>NUM_PREC_RADIX</B> int => usually 2 or 10 </li>
5386:             * </ol>
5387:             * </p>
5388:             * 
5389:             * @return ResultSet each row is a SQL type description
5390:             * @throws SQLException
5391:             *             DOCUMENT ME!
5392:             */
5393:            public java.sql.ResultSet getTypeInfo() throws SQLException {
5394:                Field[] fields = new Field[18];
5395:                fields[0] = new Field("", "TYPE_NAME", Types.CHAR, 32);
5396:                fields[1] = new Field("", "DATA_TYPE", Types.SMALLINT, 5);
5397:                fields[2] = new Field("", "PRECISION", Types.INTEGER, 10);
5398:                fields[3] = new Field("", "LITERAL_PREFIX", Types.CHAR, 4);
5399:                fields[4] = new Field("", "LITERAL_SUFFIX", Types.CHAR, 4);
5400:                fields[5] = new Field("", "CREATE_PARAMS", Types.CHAR, 32);
5401:                fields[6] = new Field("", "NULLABLE", Types.SMALLINT, 5);
5402:                fields[7] = new Field("", "CASE_SENSITIVE", Types.CHAR, 3);
5403:                fields[8] = new Field("", "SEARCHABLE", Types.SMALLINT, 3);
5404:                fields[9] = new Field("", "UNSIGNED_ATTRIBUTE", Types.CHAR, 3);
5405:                fields[10] = new Field("", "FIXED_PREC_SCALE", Types.CHAR, 3);
5406:                fields[11] = new Field("", "AUTO_INCREMENT", Types.CHAR, 3);
5407:                fields[12] = new Field("", "LOCAL_TYPE_NAME", Types.CHAR, 32);
5408:                fields[13] = new Field("", "MINIMUM_SCALE", Types.SMALLINT, 5);
5409:                fields[14] = new Field("", "MAXIMUM_SCALE", Types.SMALLINT, 5);
5410:                fields[15] = new Field("", "SQL_DATA_TYPE", Types.INTEGER, 10);
5411:                fields[16] = new Field("", "SQL_DATETIME_SUB", Types.INTEGER,
5412:                        10);
5413:                fields[17] = new Field("", "NUM_PREC_RADIX", Types.INTEGER, 10);
5414:
5415:                byte[][] rowVal = null;
5416:                ArrayList tuples = new ArrayList();
5417:
5418:                /*
5419:                 * The following are ordered by java.sql.Types, and then by how closely
5420:                 * the MySQL type matches the JDBC Type (per spec)
5421:                 */
5422:                /*
5423:                 * MySQL Type: BIT (silently converted to TINYINT(1)) JDBC Type: BIT
5424:                 */
5425:                rowVal = new byte[18][];
5426:                rowVal[0] = s2b("BIT");
5427:                rowVal[1] = Integer.toString(java.sql.Types.BIT).getBytes();
5428:
5429:                // JDBC Data type
5430:                rowVal[2] = s2b("1"); // Precision
5431:                rowVal[3] = s2b(""); // Literal Prefix
5432:                rowVal[4] = s2b(""); // Literal Suffix
5433:                rowVal[5] = s2b(""); // Create Params
5434:                rowVal[6] = Integer.toString(
5435:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
5436:
5437:                // Nullable
5438:                rowVal[7] = s2b("true"); // Case Sensitive
5439:                rowVal[8] = Integer.toString(
5440:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
5441:
5442:                // Searchable
5443:                rowVal[9] = s2b("false"); // Unsignable
5444:                rowVal[10] = s2b("false"); // Fixed Prec Scale
5445:                rowVal[11] = s2b("false"); // Auto Increment
5446:                rowVal[12] = s2b("BIT"); // Locale Type Name
5447:                rowVal[13] = s2b("0"); // Minimum Scale
5448:                rowVal[14] = s2b("0"); // Maximum Scale
5449:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5450:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5451:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5452:                tuples.add(new ByteArrayRow(rowVal));
5453:
5454:                /*
5455:                 * MySQL Type: BOOL (silently converted to TINYINT(1)) JDBC Type: BIT
5456:                 */
5457:                rowVal = new byte[18][];
5458:                rowVal[0] = s2b("BOOL");
5459:                rowVal[1] = Integer.toString(java.sql.Types.BIT).getBytes();
5460:
5461:                // JDBC Data type
5462:                rowVal[2] = s2b("1"); // Precision
5463:                rowVal[3] = s2b(""); // Literal Prefix
5464:                rowVal[4] = s2b(""); // Literal Suffix
5465:                rowVal[5] = s2b(""); // Create Params
5466:                rowVal[6] = Integer.toString(
5467:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
5468:
5469:                // Nullable
5470:                rowVal[7] = s2b("true"); // Case Sensitive
5471:                rowVal[8] = Integer.toString(
5472:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
5473:
5474:                // Searchable
5475:                rowVal[9] = s2b("false"); // Unsignable
5476:                rowVal[10] = s2b("false"); // Fixed Prec Scale
5477:                rowVal[11] = s2b("false"); // Auto Increment
5478:                rowVal[12] = s2b("BOOL"); // Locale Type Name
5479:                rowVal[13] = s2b("0"); // Minimum Scale
5480:                rowVal[14] = s2b("0"); // Maximum Scale
5481:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5482:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5483:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5484:                tuples.add(new ByteArrayRow(rowVal));
5485:
5486:                /*
5487:                 * MySQL Type: TINYINT JDBC Type: TINYINT
5488:                 */
5489:                rowVal = new byte[18][];
5490:                rowVal[0] = s2b("TINYINT");
5491:                rowVal[1] = Integer.toString(java.sql.Types.TINYINT).getBytes();
5492:
5493:                // JDBC Data type
5494:                rowVal[2] = s2b("3"); // Precision
5495:                rowVal[3] = s2b(""); // Literal Prefix
5496:                rowVal[4] = s2b(""); // Literal Suffix
5497:                rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params
5498:                rowVal[6] = Integer.toString(
5499:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
5500:
5501:                // Nullable
5502:                rowVal[7] = s2b("false"); // Case Sensitive
5503:                rowVal[8] = Integer.toString(
5504:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
5505:
5506:                // Searchable
5507:                rowVal[9] = s2b("true"); // Unsignable
5508:                rowVal[10] = s2b("false"); // Fixed Prec Scale
5509:                rowVal[11] = s2b("true"); // Auto Increment
5510:                rowVal[12] = s2b("TINYINT"); // Locale Type Name
5511:                rowVal[13] = s2b("0"); // Minimum Scale
5512:                rowVal[14] = s2b("0"); // Maximum Scale
5513:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5514:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5515:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5516:                tuples.add(new ByteArrayRow(rowVal));
5517:
5518:                /*
5519:                 * MySQL Type: BIGINT JDBC Type: BIGINT
5520:                 */
5521:                rowVal = new byte[18][];
5522:                rowVal[0] = s2b("BIGINT");
5523:                rowVal[1] = Integer.toString(java.sql.Types.BIGINT).getBytes();
5524:
5525:                // JDBC Data type
5526:                rowVal[2] = s2b("19"); // Precision
5527:                rowVal[3] = s2b(""); // Literal Prefix
5528:                rowVal[4] = s2b(""); // Literal Suffix
5529:                rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params
5530:                rowVal[6] = Integer.toString(
5531:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
5532:
5533:                // Nullable
5534:                rowVal[7] = s2b("false"); // Case Sensitive
5535:                rowVal[8] = Integer.toString(
5536:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
5537:
5538:                // Searchable
5539:                rowVal[9] = s2b("true"); // Unsignable
5540:                rowVal[10] = s2b("false"); // Fixed Prec Scale
5541:                rowVal[11] = s2b("true"); // Auto Increment
5542:                rowVal[12] = s2b("BIGINT"); // Locale Type Name
5543:                rowVal[13] = s2b("0"); // Minimum Scale
5544:                rowVal[14] = s2b("0"); // Maximum Scale
5545:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5546:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5547:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5548:                tuples.add(new ByteArrayRow(rowVal));
5549:
5550:                /*
5551:                 * MySQL Type: LONG VARBINARY JDBC Type: LONGVARBINARY
5552:                 */
5553:                rowVal = new byte[18][];
5554:                rowVal[0] = s2b("LONG VARBINARY");
5555:                rowVal[1] = Integer.toString(java.sql.Types.LONGVARBINARY)
5556:                        .getBytes();
5557:
5558:                // JDBC Data type
5559:                rowVal[2] = s2b("16777215"); // Precision
5560:                rowVal[3] = s2b("'"); // Literal Prefix
5561:                rowVal[4] = s2b("'"); // Literal Suffix
5562:                rowVal[5] = s2b(""); // Create Params
5563:                rowVal[6] = Integer.toString(
5564:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
5565:
5566:                // Nullable
5567:                rowVal[7] = s2b("true"); // Case Sensitive
5568:                rowVal[8] = Integer.toString(
5569:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
5570:
5571:                // Searchable
5572:                rowVal[9] = s2b("false"); // Unsignable
5573:                rowVal[10] = s2b("false"); // Fixed Prec Scale
5574:                rowVal[11] = s2b("false"); // Auto Increment
5575:                rowVal[12] = s2b("LONG VARBINARY"); // Locale Type Name
5576:                rowVal[13] = s2b("0"); // Minimum Scale
5577:                rowVal[14] = s2b("0"); // Maximum Scale
5578:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5579:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5580:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5581:                tuples.add(new ByteArrayRow(rowVal));
5582:
5583:                /*
5584:                 * MySQL Type: MEDIUMBLOB JDBC Type: LONGVARBINARY
5585:                 */
5586:                rowVal = new byte[18][];
5587:                rowVal[0] = s2b("MEDIUMBLOB");
5588:                rowVal[1] = Integer.toString(java.sql.Types.LONGVARBINARY)
5589:                        .getBytes();
5590:
5591:                // JDBC Data type
5592:                rowVal[2] = s2b("16777215"); // Precision
5593:                rowVal[3] = s2b("'"); // Literal Prefix
5594:                rowVal[4] = s2b("'"); // Literal Suffix
5595:                rowVal[5] = s2b(""); // Create Params
5596:                rowVal[6] = Integer.toString(
5597:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
5598:
5599:                // Nullable
5600:                rowVal[7] = s2b("true"); // Case Sensitive
5601:                rowVal[8] = Integer.toString(
5602:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
5603:
5604:                // Searchable
5605:                rowVal[9] = s2b("false"); // Unsignable
5606:                rowVal[10] = s2b("false"); // Fixed Prec Scale
5607:                rowVal[11] = s2b("false"); // Auto Increment
5608:                rowVal[12] = s2b("MEDIUMBLOB"); // Locale Type Name
5609:                rowVal[13] = s2b("0"); // Minimum Scale
5610:                rowVal[14] = s2b("0"); // Maximum Scale
5611:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5612:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5613:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5614:                tuples.add(new ByteArrayRow(rowVal));
5615:
5616:                /*
5617:                 * MySQL Type: LONGBLOB JDBC Type: LONGVARBINARY
5618:                 */
5619:                rowVal = new byte[18][];
5620:                rowVal[0] = s2b("LONGBLOB");
5621:                rowVal[1] = Integer.toString(java.sql.Types.LONGVARBINARY)
5622:                        .getBytes();
5623:
5624:                // JDBC Data type
5625:                rowVal[2] = Integer.toString(Integer.MAX_VALUE).getBytes();
5626:
5627:                // Precision
5628:                rowVal[3] = s2b("'"); // Literal Prefix
5629:                rowVal[4] = s2b("'"); // Literal Suffix
5630:                rowVal[5] = s2b(""); // Create Params
5631:                rowVal[6] = Integer.toString(
5632:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
5633:
5634:                // Nullable
5635:                rowVal[7] = s2b("true"); // Case Sensitive
5636:                rowVal[8] = Integer.toString(
5637:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
5638:
5639:                // Searchable
5640:                rowVal[9] = s2b("false"); // Unsignable
5641:                rowVal[10] = s2b("false"); // Fixed Prec Scale
5642:                rowVal[11] = s2b("false"); // Auto Increment
5643:                rowVal[12] = s2b("LONGBLOB"); // Locale Type Name
5644:                rowVal[13] = s2b("0"); // Minimum Scale
5645:                rowVal[14] = s2b("0"); // Maximum Scale
5646:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5647:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5648:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5649:                tuples.add(new ByteArrayRow(rowVal));
5650:
5651:                /*
5652:                 * MySQL Type: BLOB JDBC Type: LONGVARBINARY
5653:                 */
5654:                rowVal = new byte[18][];
5655:                rowVal[0] = s2b("BLOB");
5656:                rowVal[1] = Integer.toString(java.sql.Types.LONGVARBINARY)
5657:                        .getBytes();
5658:
5659:                // JDBC Data type
5660:                rowVal[2] = s2b("65535"); // Precision
5661:                rowVal[3] = s2b("'"); // Literal Prefix
5662:                rowVal[4] = s2b("'"); // Literal Suffix
5663:                rowVal[5] = s2b(""); // Create Params
5664:                rowVal[6] = Integer.toString(
5665:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
5666:
5667:                // Nullable
5668:                rowVal[7] = s2b("true"); // Case Sensitive
5669:                rowVal[8] = Integer.toString(
5670:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
5671:
5672:                // Searchable
5673:                rowVal[9] = s2b("false"); // Unsignable
5674:                rowVal[10] = s2b("false"); // Fixed Prec Scale
5675:                rowVal[11] = s2b("false"); // Auto Increment
5676:                rowVal[12] = s2b("BLOB"); // Locale Type Name
5677:                rowVal[13] = s2b("0"); // Minimum Scale
5678:                rowVal[14] = s2b("0"); // Maximum Scale
5679:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5680:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5681:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5682:                tuples.add(new ByteArrayRow(rowVal));
5683:
5684:                /*
5685:                 * MySQL Type: TINYBLOB JDBC Type: LONGVARBINARY
5686:                 */
5687:                rowVal = new byte[18][];
5688:                rowVal[0] = s2b("TINYBLOB");
5689:                rowVal[1] = Integer.toString(java.sql.Types.LONGVARBINARY)
5690:                        .getBytes();
5691:
5692:                // JDBC Data type
5693:                rowVal[2] = s2b("255"); // Precision
5694:                rowVal[3] = s2b("'"); // Literal Prefix
5695:                rowVal[4] = s2b("'"); // Literal Suffix
5696:                rowVal[5] = s2b(""); // Create Params
5697:                rowVal[6] = Integer.toString(
5698:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
5699:
5700:                // Nullable
5701:                rowVal[7] = s2b("true"); // Case Sensitive
5702:                rowVal[8] = Integer.toString(
5703:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
5704:
5705:                // Searchable
5706:                rowVal[9] = s2b("false"); // Unsignable
5707:                rowVal[10] = s2b("false"); // Fixed Prec Scale
5708:                rowVal[11] = s2b("false"); // Auto Increment
5709:                rowVal[12] = s2b("TINYBLOB"); // Locale Type Name
5710:                rowVal[13] = s2b("0"); // Minimum Scale
5711:                rowVal[14] = s2b("0"); // Maximum Scale
5712:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5713:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5714:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5715:                tuples.add(new ByteArrayRow(rowVal));
5716:
5717:                /*
5718:                 * MySQL Type: VARBINARY (sliently converted to VARCHAR(M) BINARY) JDBC
5719:                 * Type: VARBINARY
5720:                 */
5721:                rowVal = new byte[18][];
5722:                rowVal[0] = s2b("VARBINARY");
5723:                rowVal[1] = Integer.toString(java.sql.Types.VARBINARY)
5724:                        .getBytes();
5725:
5726:                // JDBC Data type
5727:                rowVal[2] = s2b("255"); // Precision
5728:                rowVal[3] = s2b("'"); // Literal Prefix
5729:                rowVal[4] = s2b("'"); // Literal Suffix
5730:                rowVal[5] = s2b("(M)"); // Create Params
5731:                rowVal[6] = Integer.toString(
5732:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
5733:
5734:                // Nullable
5735:                rowVal[7] = s2b("true"); // Case Sensitive
5736:                rowVal[8] = Integer.toString(
5737:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
5738:
5739:                // Searchable
5740:                rowVal[9] = s2b("false"); // Unsignable
5741:                rowVal[10] = s2b("false"); // Fixed Prec Scale
5742:                rowVal[11] = s2b("false"); // Auto Increment
5743:                rowVal[12] = s2b("VARBINARY"); // Locale Type Name
5744:                rowVal[13] = s2b("0"); // Minimum Scale
5745:                rowVal[14] = s2b("0"); // Maximum Scale
5746:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5747:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5748:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5749:                tuples.add(new ByteArrayRow(rowVal));
5750:
5751:                /*
5752:                 * MySQL Type: BINARY (silently converted to CHAR(M) BINARY) JDBC Type:
5753:                 * BINARY
5754:                 */
5755:                rowVal = new byte[18][];
5756:                rowVal[0] = s2b("BINARY");
5757:                rowVal[1] = Integer.toString(java.sql.Types.BINARY).getBytes();
5758:
5759:                // JDBC Data type
5760:                rowVal[2] = s2b("255"); // Precision
5761:                rowVal[3] = s2b("'"); // Literal Prefix
5762:                rowVal[4] = s2b("'"); // Literal Suffix
5763:                rowVal[5] = s2b("(M)"); // Create Params
5764:                rowVal[6] = Integer.toString(
5765:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
5766:
5767:                // Nullable
5768:                rowVal[7] = s2b("true"); // Case Sensitive
5769:                rowVal[8] = Integer.toString(
5770:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
5771:
5772:                // Searchable
5773:                rowVal[9] = s2b("false"); // Unsignable
5774:                rowVal[10] = s2b("false"); // Fixed Prec Scale
5775:                rowVal[11] = s2b("false"); // Auto Increment
5776:                rowVal[12] = s2b("BINARY"); // Locale Type Name
5777:                rowVal[13] = s2b("0"); // Minimum Scale
5778:                rowVal[14] = s2b("0"); // Maximum Scale
5779:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5780:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5781:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5782:                tuples.add(new ByteArrayRow(rowVal));
5783:
5784:                /*
5785:                 * MySQL Type: LONG VARCHAR JDBC Type: LONGVARCHAR
5786:                 */
5787:                rowVal = new byte[18][];
5788:                rowVal[0] = s2b("LONG VARCHAR");
5789:                rowVal[1] = Integer.toString(java.sql.Types.LONGVARCHAR)
5790:                        .getBytes();
5791:
5792:                // JDBC Data type
5793:                rowVal[2] = s2b("16777215"); // Precision
5794:                rowVal[3] = s2b("'"); // Literal Prefix
5795:                rowVal[4] = s2b("'"); // Literal Suffix
5796:                rowVal[5] = s2b(""); // Create Params
5797:                rowVal[6] = Integer.toString(
5798:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
5799:
5800:                // Nullable
5801:                rowVal[7] = s2b("false"); // Case Sensitive
5802:                rowVal[8] = Integer.toString(
5803:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
5804:
5805:                // Searchable
5806:                rowVal[9] = s2b("false"); // Unsignable
5807:                rowVal[10] = s2b("false"); // Fixed Prec Scale
5808:                rowVal[11] = s2b("false"); // Auto Increment
5809:                rowVal[12] = s2b("LONG VARCHAR"); // Locale Type Name
5810:                rowVal[13] = s2b("0"); // Minimum Scale
5811:                rowVal[14] = s2b("0"); // Maximum Scale
5812:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5813:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5814:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5815:                tuples.add(new ByteArrayRow(rowVal));
5816:
5817:                /*
5818:                 * MySQL Type: MEDIUMTEXT JDBC Type: LONGVARCHAR
5819:                 */
5820:                rowVal = new byte[18][];
5821:                rowVal[0] = s2b("MEDIUMTEXT");
5822:                rowVal[1] = Integer.toString(java.sql.Types.LONGVARCHAR)
5823:                        .getBytes();
5824:
5825:                // JDBC Data type
5826:                rowVal[2] = s2b("16777215"); // Precision
5827:                rowVal[3] = s2b("'"); // Literal Prefix
5828:                rowVal[4] = s2b("'"); // Literal Suffix
5829:                rowVal[5] = s2b(""); // Create Params
5830:                rowVal[6] = Integer.toString(
5831:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
5832:
5833:                // Nullable
5834:                rowVal[7] = s2b("false"); // Case Sensitive
5835:                rowVal[8] = Integer.toString(
5836:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
5837:
5838:                // Searchable
5839:                rowVal[9] = s2b("false"); // Unsignable
5840:                rowVal[10] = s2b("false"); // Fixed Prec Scale
5841:                rowVal[11] = s2b("false"); // Auto Increment
5842:                rowVal[12] = s2b("MEDIUMTEXT"); // Locale Type Name
5843:                rowVal[13] = s2b("0"); // Minimum Scale
5844:                rowVal[14] = s2b("0"); // Maximum Scale
5845:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5846:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5847:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5848:                tuples.add(new ByteArrayRow(rowVal));
5849:
5850:                /*
5851:                 * MySQL Type: LONGTEXT JDBC Type: LONGVARCHAR
5852:                 */
5853:                rowVal = new byte[18][];
5854:                rowVal[0] = s2b("LONGTEXT");
5855:                rowVal[1] = Integer.toString(java.sql.Types.LONGVARCHAR)
5856:                        .getBytes();
5857:
5858:                // JDBC Data type
5859:                rowVal[2] = Integer.toString(Integer.MAX_VALUE).getBytes();
5860:
5861:                // Precision
5862:                rowVal[3] = s2b("'"); // Literal Prefix
5863:                rowVal[4] = s2b("'"); // Literal Suffix
5864:                rowVal[5] = s2b(""); // Create Params
5865:                rowVal[6] = Integer.toString(
5866:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
5867:
5868:                // Nullable
5869:                rowVal[7] = s2b("false"); // Case Sensitive
5870:                rowVal[8] = Integer.toString(
5871:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
5872:
5873:                // Searchable
5874:                rowVal[9] = s2b("false"); // Unsignable
5875:                rowVal[10] = s2b("false"); // Fixed Prec Scale
5876:                rowVal[11] = s2b("false"); // Auto Increment
5877:                rowVal[12] = s2b("LONGTEXT"); // Locale Type Name
5878:                rowVal[13] = s2b("0"); // Minimum Scale
5879:                rowVal[14] = s2b("0"); // Maximum Scale
5880:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5881:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5882:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5883:                tuples.add(new ByteArrayRow(rowVal));
5884:
5885:                /*
5886:                 * MySQL Type: TEXT JDBC Type: LONGVARCHAR
5887:                 */
5888:                rowVal = new byte[18][];
5889:                rowVal[0] = s2b("TEXT");
5890:                rowVal[1] = Integer.toString(java.sql.Types.LONGVARCHAR)
5891:                        .getBytes();
5892:
5893:                // JDBC Data type
5894:                rowVal[2] = s2b("65535"); // Precision
5895:                rowVal[3] = s2b("'"); // Literal Prefix
5896:                rowVal[4] = s2b("'"); // Literal Suffix
5897:                rowVal[5] = s2b(""); // Create Params
5898:                rowVal[6] = Integer.toString(
5899:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
5900:
5901:                // Nullable
5902:                rowVal[7] = s2b("false"); // Case Sensitive
5903:                rowVal[8] = Integer.toString(
5904:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
5905:
5906:                // Searchable
5907:                rowVal[9] = s2b("false"); // Unsignable
5908:                rowVal[10] = s2b("false"); // Fixed Prec Scale
5909:                rowVal[11] = s2b("false"); // Auto Increment
5910:                rowVal[12] = s2b("TEXT"); // Locale Type Name
5911:                rowVal[13] = s2b("0"); // Minimum Scale
5912:                rowVal[14] = s2b("0"); // Maximum Scale
5913:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5914:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5915:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5916:                tuples.add(new ByteArrayRow(rowVal));
5917:
5918:                /*
5919:                 * MySQL Type: TINYTEXT JDBC Type: LONGVARCHAR
5920:                 */
5921:                rowVal = new byte[18][];
5922:                rowVal[0] = s2b("TINYTEXT");
5923:                rowVal[1] = Integer.toString(java.sql.Types.LONGVARCHAR)
5924:                        .getBytes();
5925:
5926:                // JDBC Data type
5927:                rowVal[2] = s2b("255"); // Precision
5928:                rowVal[3] = s2b("'"); // Literal Prefix
5929:                rowVal[4] = s2b("'"); // Literal Suffix
5930:                rowVal[5] = s2b(""); // Create Params
5931:                rowVal[6] = Integer.toString(
5932:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
5933:
5934:                // Nullable
5935:                rowVal[7] = s2b("false"); // Case Sensitive
5936:                rowVal[8] = Integer.toString(
5937:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
5938:
5939:                // Searchable
5940:                rowVal[9] = s2b("false"); // Unsignable
5941:                rowVal[10] = s2b("false"); // Fixed Prec Scale
5942:                rowVal[11] = s2b("false"); // Auto Increment
5943:                rowVal[12] = s2b("TINYTEXT"); // Locale Type Name
5944:                rowVal[13] = s2b("0"); // Minimum Scale
5945:                rowVal[14] = s2b("0"); // Maximum Scale
5946:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5947:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5948:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5949:                tuples.add(new ByteArrayRow(rowVal));
5950:
5951:                /*
5952:                 * MySQL Type: CHAR JDBC Type: CHAR
5953:                 */
5954:                rowVal = new byte[18][];
5955:                rowVal[0] = s2b("CHAR");
5956:                rowVal[1] = Integer.toString(java.sql.Types.CHAR).getBytes();
5957:
5958:                // JDBC Data type
5959:                rowVal[2] = s2b("255"); // Precision
5960:                rowVal[3] = s2b("'"); // Literal Prefix
5961:                rowVal[4] = s2b("'"); // Literal Suffix
5962:                rowVal[5] = s2b("(M)"); // Create Params
5963:                rowVal[6] = Integer.toString(
5964:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
5965:
5966:                // Nullable
5967:                rowVal[7] = s2b("false"); // Case Sensitive
5968:                rowVal[8] = Integer.toString(
5969:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
5970:
5971:                // Searchable
5972:                rowVal[9] = s2b("false"); // Unsignable
5973:                rowVal[10] = s2b("false"); // Fixed Prec Scale
5974:                rowVal[11] = s2b("false"); // Auto Increment
5975:                rowVal[12] = s2b("CHAR"); // Locale Type Name
5976:                rowVal[13] = s2b("0"); // Minimum Scale
5977:                rowVal[14] = s2b("0"); // Maximum Scale
5978:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5979:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5980:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5981:                tuples.add(new ByteArrayRow(rowVal));
5982:
5983:                // The maximum number of digits for DECIMAL or NUMERIC is 65 (64 from MySQL 5.0.3 to 5.0.5). 
5984:
5985:                int decimalPrecision = 254;
5986:
5987:                if (this .conn.versionMeetsMinimum(5, 0, 3)) {
5988:                    if (this .conn.versionMeetsMinimum(5, 0, 6)) {
5989:                        decimalPrecision = 65;
5990:                    } else {
5991:                        decimalPrecision = 64;
5992:                    }
5993:                }
5994:
5995:                /*
5996:                 * MySQL Type: NUMERIC (silently converted to DECIMAL) JDBC Type:
5997:                 * NUMERIC
5998:                 */
5999:                rowVal = new byte[18][];
6000:                rowVal[0] = s2b("NUMERIC");
6001:                rowVal[1] = Integer.toString(java.sql.Types.NUMERIC).getBytes();
6002:
6003:                // JDBC Data type
6004:                rowVal[2] = s2b(String.valueOf(decimalPrecision)); // Precision
6005:                rowVal[3] = s2b(""); // Literal Prefix
6006:                rowVal[4] = s2b(""); // Literal Suffix
6007:                rowVal[5] = s2b("[(M[,D])] [ZEROFILL]"); // Create Params
6008:                rowVal[6] = Integer.toString(
6009:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
6010:
6011:                // Nullable
6012:                rowVal[7] = s2b("false"); // Case Sensitive
6013:                rowVal[8] = Integer.toString(
6014:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
6015:
6016:                // Searchable
6017:                rowVal[9] = s2b("false"); // Unsignable
6018:                rowVal[10] = s2b("false"); // Fixed Prec Scale
6019:                rowVal[11] = s2b("true"); // Auto Increment
6020:                rowVal[12] = s2b("NUMERIC"); // Locale Type Name
6021:                rowVal[13] = s2b("-308"); // Minimum Scale
6022:                rowVal[14] = s2b("308"); // Maximum Scale
6023:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
6024:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
6025:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
6026:                tuples.add(new ByteArrayRow(rowVal));
6027:
6028:                /*
6029:                 * MySQL Type: DECIMAL JDBC Type: DECIMAL
6030:                 */
6031:                rowVal = new byte[18][];
6032:                rowVal[0] = s2b("DECIMAL");
6033:                rowVal[1] = Integer.toString(java.sql.Types.DECIMAL).getBytes();
6034:
6035:                // JDBC Data type
6036:                rowVal[2] = s2b(String.valueOf(decimalPrecision)); // Precision
6037:                rowVal[3] = s2b(""); // Literal Prefix
6038:                rowVal[4] = s2b(""); // Literal Suffix
6039:                rowVal[5] = s2b("[(M[,D])] [ZEROFILL]"); // Create Params
6040:                rowVal[6] = Integer.toString(
6041:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
6042:
6043:                // Nullable
6044:                rowVal[7] = s2b("false"); // Case Sensitive
6045:                rowVal[8] = Integer.toString(
6046:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
6047:
6048:                // Searchable
6049:                rowVal[9] = s2b("false"); // Unsignable
6050:                rowVal[10] = s2b("false"); // Fixed Prec Scale
6051:                rowVal[11] = s2b("true"); // Auto Increment
6052:                rowVal[12] = s2b("DECIMAL"); // Locale Type Name
6053:                rowVal[13] = s2b("-308"); // Minimum Scale
6054:                rowVal[14] = s2b("308"); // Maximum Scale
6055:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
6056:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
6057:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
6058:                tuples.add(new ByteArrayRow(rowVal));
6059:
6060:                /*
6061:                 * MySQL Type: INTEGER JDBC Type: INTEGER
6062:                 */
6063:                rowVal = new byte[18][];
6064:                rowVal[0] = s2b("INTEGER");
6065:                rowVal[1] = Integer.toString(java.sql.Types.INTEGER).getBytes();
6066:
6067:                // JDBC Data type
6068:                rowVal[2] = s2b("10"); // Precision
6069:                rowVal[3] = s2b(""); // Literal Prefix
6070:                rowVal[4] = s2b(""); // Literal Suffix
6071:                rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params
6072:                rowVal[6] = Integer.toString(
6073:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
6074:
6075:                // Nullable
6076:                rowVal[7] = s2b("false"); // Case Sensitive
6077:                rowVal[8] = Integer.toString(
6078:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
6079:
6080:                // Searchable
6081:                rowVal[9] = s2b("true"); // Unsignable
6082:                rowVal[10] = s2b("false"); // Fixed Prec Scale
6083:                rowVal[11] = s2b("true"); // Auto Increment
6084:                rowVal[12] = s2b("INTEGER"); // Locale Type Name
6085:                rowVal[13] = s2b("0"); // Minimum Scale
6086:                rowVal[14] = s2b("0"); // Maximum Scale
6087:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
6088:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
6089:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
6090:                tuples.add(new ByteArrayRow(rowVal));
6091:
6092:                /*
6093:                 * MySQL Type: INT JDBC Type: INTEGER
6094:                 */
6095:                rowVal = new byte[18][];
6096:                rowVal[0] = s2b("INT");
6097:                rowVal[1] = Integer.toString(java.sql.Types.INTEGER).getBytes();
6098:
6099:                // JDBC Data type
6100:                rowVal[2] = s2b("10"); // Precision
6101:                rowVal[3] = s2b(""); // Literal Prefix
6102:                rowVal[4] = s2b(""); // Literal Suffix
6103:                rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params
6104:                rowVal[6] = Integer.toString(
6105:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
6106:
6107:                // Nullable
6108:                rowVal[7] = s2b("false"); // Case Sensitive
6109:                rowVal[8] = Integer.toString(
6110:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
6111:
6112:                // Searchable
6113:                rowVal[9] = s2b("true"); // Unsignable
6114:                rowVal[10] = s2b("false"); // Fixed Prec Scale
6115:                rowVal[11] = s2b("true"); // Auto Increment
6116:                rowVal[12] = s2b("INT"); // Locale Type Name
6117:                rowVal[13] = s2b("0"); // Minimum Scale
6118:                rowVal[14] = s2b("0"); // Maximum Scale
6119:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
6120:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
6121:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
6122:                tuples.add(new ByteArrayRow(rowVal));
6123:
6124:                /*
6125:                 * MySQL Type: MEDIUMINT JDBC Type: INTEGER
6126:                 */
6127:                rowVal = new byte[18][];
6128:                rowVal[0] = s2b("MEDIUMINT");
6129:                rowVal[1] = Integer.toString(java.sql.Types.INTEGER).getBytes();
6130:
6131:                // JDBC Data type
6132:                rowVal[2] = s2b("7"); // Precision
6133:                rowVal[3] = s2b(""); // Literal Prefix
6134:                rowVal[4] = s2b(""); // Literal Suffix
6135:                rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params
6136:                rowVal[6] = Integer.toString(
6137:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
6138:
6139:                // Nullable
6140:                rowVal[7] = s2b("false"); // Case Sensitive
6141:                rowVal[8] = Integer.toString(
6142:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
6143:
6144:                // Searchable
6145:                rowVal[9] = s2b("true"); // Unsignable
6146:                rowVal[10] = s2b("false"); // Fixed Prec Scale
6147:                rowVal[11] = s2b("true"); // Auto Increment
6148:                rowVal[12] = s2b("MEDIUMINT"); // Locale Type Name
6149:                rowVal[13] = s2b("0"); // Minimum Scale
6150:                rowVal[14] = s2b("0"); // Maximum Scale
6151:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
6152:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
6153:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
6154:                tuples.add(new ByteArrayRow(rowVal));
6155:
6156:                /*
6157:                 * MySQL Type: SMALLINT JDBC Type: SMALLINT
6158:                 */
6159:                rowVal = new byte[18][];
6160:                rowVal[0] = s2b("SMALLINT");
6161:                rowVal[1] = Integer.toString(java.sql.Types.SMALLINT)
6162:                        .getBytes();
6163:
6164:                // JDBC Data type
6165:                rowVal[2] = s2b("5"); // Precision
6166:                rowVal[3] = s2b(""); // Literal Prefix
6167:                rowVal[4] = s2b(""); // Literal Suffix
6168:                rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params
6169:                rowVal[6] = Integer.toString(
6170:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
6171:
6172:                // Nullable
6173:                rowVal[7] = s2b("false"); // Case Sensitive
6174:                rowVal[8] = Integer.toString(
6175:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
6176:
6177:                // Searchable
6178:                rowVal[9] = s2b("true"); // Unsignable
6179:                rowVal[10] = s2b("false"); // Fixed Prec Scale
6180:                rowVal[11] = s2b("true"); // Auto Increment
6181:                rowVal[12] = s2b("SMALLINT"); // Locale Type Name
6182:                rowVal[13] = s2b("0"); // Minimum Scale
6183:                rowVal[14] = s2b("0"); // Maximum Scale
6184:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
6185:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
6186:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
6187:                tuples.add(new ByteArrayRow(rowVal));
6188:
6189:                /*
6190:                 * MySQL Type: FLOAT JDBC Type: REAL (this is the SINGLE PERCISION
6191:                 * floating point type)
6192:                 */
6193:                rowVal = new byte[18][];
6194:                rowVal[0] = s2b("FLOAT");
6195:                rowVal[1] = Integer.toString(java.sql.Types.REAL).getBytes();
6196:
6197:                // JDBC Data type
6198:                rowVal[2] = s2b("10"); // Precision
6199:                rowVal[3] = s2b(""); // Literal Prefix
6200:                rowVal[4] = s2b(""); // Literal Suffix
6201:                rowVal[5] = s2b("[(M,D)] [ZEROFILL]"); // Create Params
6202:                rowVal[6] = Integer.toString(
6203:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
6204:
6205:                // Nullable
6206:                rowVal[7] = s2b("false"); // Case Sensitive
6207:                rowVal[8] = Integer.toString(
6208:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
6209:
6210:                // Searchable
6211:                rowVal[9] = s2b("false"); // Unsignable
6212:                rowVal[10] = s2b("false"); // Fixed Prec Scale
6213:                rowVal[11] = s2b("true"); // Auto Increment
6214:                rowVal[12] = s2b("FLOAT"); // Locale Type Name
6215:                rowVal[13] = s2b("-38"); // Minimum Scale
6216:                rowVal[14] = s2b("38"); // Maximum Scale
6217:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
6218:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
6219:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
6220:                tuples.add(new ByteArrayRow(rowVal));
6221:
6222:                /*
6223:                 * MySQL Type: DOUBLE JDBC Type: DOUBLE
6224:                 */
6225:                rowVal = new byte[18][];
6226:                rowVal[0] = s2b("DOUBLE");
6227:                rowVal[1] = Integer.toString(java.sql.Types.DOUBLE).getBytes();
6228:
6229:                // JDBC Data type
6230:                rowVal[2] = s2b("17"); // Precision
6231:                rowVal[3] = s2b(""); // Literal Prefix
6232:                rowVal[4] = s2b(""); // Literal Suffix
6233:                rowVal[5] = s2b("[(M,D)] [ZEROFILL]"); // Create Params
6234:                rowVal[6] = Integer.toString(
6235:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
6236:
6237:                // Nullable
6238:                rowVal[7] = s2b("false"); // Case Sensitive
6239:                rowVal[8] = Integer.toString(
6240:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
6241:
6242:                // Searchable
6243:                rowVal[9] = s2b("false"); // Unsignable
6244:                rowVal[10] = s2b("false"); // Fixed Prec Scale
6245:                rowVal[11] = s2b("true"); // Auto Increment
6246:                rowVal[12] = s2b("DOUBLE"); // Locale Type Name
6247:                rowVal[13] = s2b("-308"); // Minimum Scale
6248:                rowVal[14] = s2b("308"); // Maximum Scale
6249:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
6250:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
6251:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
6252:                tuples.add(new ByteArrayRow(rowVal));
6253:
6254:                /*
6255:                 * MySQL Type: DOUBLE PRECISION JDBC Type: DOUBLE
6256:                 */
6257:                rowVal = new byte[18][];
6258:                rowVal[0] = s2b("DOUBLE PRECISION");
6259:                rowVal[1] = Integer.toString(java.sql.Types.DOUBLE).getBytes();
6260:
6261:                // JDBC Data type
6262:                rowVal[2] = s2b("17"); // Precision
6263:                rowVal[3] = s2b(""); // Literal Prefix
6264:                rowVal[4] = s2b(""); // Literal Suffix
6265:                rowVal[5] = s2b("[(M,D)] [ZEROFILL]"); // Create Params
6266:                rowVal[6] = Integer.toString(
6267:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
6268:
6269:                // Nullable
6270:                rowVal[7] = s2b("false"); // Case Sensitive
6271:                rowVal[8] = Integer.toString(
6272:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
6273:
6274:                // Searchable
6275:                rowVal[9] = s2b("false"); // Unsignable
6276:                rowVal[10] = s2b("false"); // Fixed Prec Scale
6277:                rowVal[11] = s2b("true"); // Auto Increment
6278:                rowVal[12] = s2b("DOUBLE PRECISION"); // Locale Type Name
6279:                rowVal[13] = s2b("-308"); // Minimum Scale
6280:                rowVal[14] = s2b("308"); // Maximum Scale
6281:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
6282:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
6283:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
6284:                tuples.add(new ByteArrayRow(rowVal));
6285:
6286:                /*
6287:                 * MySQL Type: REAL (does not map to Types.REAL) JDBC Type: DOUBLE
6288:                 */
6289:                rowVal = new byte[18][];
6290:                rowVal[0] = s2b("REAL");
6291:                rowVal[1] = Integer.toString(java.sql.Types.DOUBLE).getBytes();
6292:
6293:                // JDBC Data type
6294:                rowVal[2] = s2b("17"); // Precision
6295:                rowVal[3] = s2b(""); // Literal Prefix
6296:                rowVal[4] = s2b(""); // Literal Suffix
6297:                rowVal[5] = s2b("[(M,D)] [ZEROFILL]"); // Create Params
6298:                rowVal[6] = Integer.toString(
6299:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
6300:
6301:                // Nullable
6302:                rowVal[7] = s2b("false"); // Case Sensitive
6303:                rowVal[8] = Integer.toString(
6304:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
6305:
6306:                // Searchable
6307:                rowVal[9] = s2b("false"); // Unsignable
6308:                rowVal[10] = s2b("false"); // Fixed Prec Scale
6309:                rowVal[11] = s2b("true"); // Auto Increment
6310:                rowVal[12] = s2b("REAL"); // Locale Type Name
6311:                rowVal[13] = s2b("-308"); // Minimum Scale
6312:                rowVal[14] = s2b("308"); // Maximum Scale
6313:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
6314:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
6315:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
6316:                tuples.add(new ByteArrayRow(rowVal));
6317:
6318:                /*
6319:                 * MySQL Type: VARCHAR JDBC Type: VARCHAR
6320:                 */
6321:                rowVal = new byte[18][];
6322:                rowVal[0] = s2b("VARCHAR");
6323:                rowVal[1] = Integer.toString(java.sql.Types.VARCHAR).getBytes();
6324:
6325:                // JDBC Data type
6326:                rowVal[2] = s2b("255"); // Precision
6327:                rowVal[3] = s2b("'"); // Literal Prefix
6328:                rowVal[4] = s2b("'"); // Literal Suffix
6329:                rowVal[5] = s2b("(M)"); // Create Params
6330:                rowVal[6] = Integer.toString(
6331:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
6332:
6333:                // Nullable
6334:                rowVal[7] = s2b("false"); // Case Sensitive
6335:                rowVal[8] = Integer.toString(
6336:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
6337:
6338:                // Searchable
6339:                rowVal[9] = s2b("false"); // Unsignable
6340:                rowVal[10] = s2b("false"); // Fixed Prec Scale
6341:                rowVal[11] = s2b("false"); // Auto Increment
6342:                rowVal[12] = s2b("VARCHAR"); // Locale Type Name
6343:                rowVal[13] = s2b("0"); // Minimum Scale
6344:                rowVal[14] = s2b("0"); // Maximum Scale
6345:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
6346:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
6347:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
6348:                tuples.add(new ByteArrayRow(rowVal));
6349:
6350:                /*
6351:                 * MySQL Type: ENUM JDBC Type: VARCHAR
6352:                 */
6353:                rowVal = new byte[18][];
6354:                rowVal[0] = s2b("ENUM");
6355:                rowVal[1] = Integer.toString(java.sql.Types.VARCHAR).getBytes();
6356:
6357:                // JDBC Data type
6358:                rowVal[2] = s2b("65535"); // Precision
6359:                rowVal[3] = s2b("'"); // Literal Prefix
6360:                rowVal[4] = s2b("'"); // Literal Suffix
6361:                rowVal[5] = s2b(""); // Create Params
6362:                rowVal[6] = Integer.toString(
6363:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
6364:
6365:                // Nullable
6366:                rowVal[7] = s2b("false"); // Case Sensitive
6367:                rowVal[8] = Integer.toString(
6368:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
6369:
6370:                // Searchable
6371:                rowVal[9] = s2b("false"); // Unsignable
6372:                rowVal[10] = s2b("false"); // Fixed Prec Scale
6373:                rowVal[11] = s2b("false"); // Auto Increment
6374:                rowVal[12] = s2b("ENUM"); // Locale Type Name
6375:                rowVal[13] = s2b("0"); // Minimum Scale
6376:                rowVal[14] = s2b("0"); // Maximum Scale
6377:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
6378:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
6379:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
6380:                tuples.add(new ByteArrayRow(rowVal));
6381:
6382:                /*
6383:                 * MySQL Type: SET JDBC Type: VARCHAR
6384:                 */
6385:                rowVal = new byte[18][];
6386:                rowVal[0] = s2b("SET");
6387:                rowVal[1] = Integer.toString(java.sql.Types.VARCHAR).getBytes();
6388:
6389:                // JDBC Data type
6390:                rowVal[2] = s2b("64"); // Precision
6391:                rowVal[3] = s2b("'"); // Literal Prefix
6392:                rowVal[4] = s2b("'"); // Literal Suffix
6393:                rowVal[5] = s2b(""); // Create Params
6394:                rowVal[6] = Integer.toString(
6395:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
6396:
6397:                // Nullable
6398:                rowVal[7] = s2b("false"); // Case Sensitive
6399:                rowVal[8] = Integer.toString(
6400:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
6401:
6402:                // Searchable
6403:                rowVal[9] = s2b("false"); // Unsignable
6404:                rowVal[10] = s2b("false"); // Fixed Prec Scale
6405:                rowVal[11] = s2b("false"); // Auto Increment
6406:                rowVal[12] = s2b("SET"); // Locale Type Name
6407:                rowVal[13] = s2b("0"); // Minimum Scale
6408:                rowVal[14] = s2b("0"); // Maximum Scale
6409:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
6410:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
6411:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
6412:                tuples.add(new ByteArrayRow(rowVal));
6413:
6414:                /*
6415:                 * MySQL Type: DATE JDBC Type: DATE
6416:                 */
6417:                rowVal = new byte[18][];
6418:                rowVal[0] = s2b("DATE");
6419:                rowVal[1] = Integer.toString(java.sql.Types.DATE).getBytes();
6420:
6421:                // JDBC Data type
6422:                rowVal[2] = s2b("0"); // Precision
6423:                rowVal[3] = s2b("'"); // Literal Prefix
6424:                rowVal[4] = s2b("'"); // Literal Suffix
6425:                rowVal[5] = s2b(""); // Create Params
6426:                rowVal[6] = Integer.toString(
6427:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
6428:
6429:                // Nullable
6430:                rowVal[7] = s2b("false"); // Case Sensitive
6431:                rowVal[8] = Integer.toString(
6432:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
6433:
6434:                // Searchable
6435:                rowVal[9] = s2b("false"); // Unsignable
6436:                rowVal[10] = s2b("false"); // Fixed Prec Scale
6437:                rowVal[11] = s2b("false"); // Auto Increment
6438:                rowVal[12] = s2b("DATE"); // Locale Type Name
6439:                rowVal[13] = s2b("0"); // Minimum Scale
6440:                rowVal[14] = s2b("0"); // Maximum Scale
6441:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
6442:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
6443:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
6444:                tuples.add(new ByteArrayRow(rowVal));
6445:
6446:                /*
6447:                 * MySQL Type: TIME JDBC Type: TIME
6448:                 */
6449:                rowVal = new byte[18][];
6450:                rowVal[0] = s2b("TIME");
6451:                rowVal[1] = Integer.toString(java.sql.Types.TIME).getBytes();
6452:
6453:                // JDBC Data type
6454:                rowVal[2] = s2b("0"); // Precision
6455:                rowVal[3] = s2b("'"); // Literal Prefix
6456:                rowVal[4] = s2b("'"); // Literal Suffix
6457:                rowVal[5] = s2b(""); // Create Params
6458:                rowVal[6] = Integer.toString(
6459:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
6460:
6461:                // Nullable
6462:                rowVal[7] = s2b("false"); // Case Sensitive
6463:                rowVal[8] = Integer.toString(
6464:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
6465:
6466:                // Searchable
6467:                rowVal[9] = s2b("false"); // Unsignable
6468:                rowVal[10] = s2b("false"); // Fixed Prec Scale
6469:                rowVal[11] = s2b("false"); // Auto Increment
6470:                rowVal[12] = s2b("TIME"); // Locale Type Name
6471:                rowVal[13] = s2b("0"); // Minimum Scale
6472:                rowVal[14] = s2b("0"); // Maximum Scale
6473:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
6474:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
6475:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
6476:                tuples.add(new ByteArrayRow(rowVal));
6477:
6478:                /*
6479:                 * MySQL Type: DATETIME JDBC Type: TIMESTAMP
6480:                 */
6481:                rowVal = new byte[18][];
6482:                rowVal[0] = s2b("DATETIME");
6483:                rowVal[1] = Integer.toString(java.sql.Types.TIMESTAMP)
6484:                        .getBytes();
6485:
6486:                // JDBC Data type
6487:                rowVal[2] = s2b("0"); // Precision
6488:                rowVal[3] = s2b("'"); // Literal Prefix
6489:                rowVal[4] = s2b("'"); // Literal Suffix
6490:                rowVal[5] = s2b(""); // Create Params
6491:                rowVal[6] = Integer.toString(
6492:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
6493:
6494:                // Nullable
6495:                rowVal[7] = s2b("false"); // Case Sensitive
6496:                rowVal[8] = Integer.toString(
6497:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
6498:
6499:                // Searchable
6500:                rowVal[9] = s2b("false"); // Unsignable
6501:                rowVal[10] = s2b("false"); // Fixed Prec Scale
6502:                rowVal[11] = s2b("false"); // Auto Increment
6503:                rowVal[12] = s2b("DATETIME"); // Locale Type Name
6504:                rowVal[13] = s2b("0"); // Minimum Scale
6505:                rowVal[14] = s2b("0"); // Maximum Scale
6506:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
6507:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
6508:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
6509:                tuples.add(new ByteArrayRow(rowVal));
6510:
6511:                /*
6512:                 * MySQL Type: TIMESTAMP JDBC Type: TIMESTAMP
6513:                 */
6514:                rowVal = new byte[18][];
6515:                rowVal[0] = s2b("TIMESTAMP");
6516:                rowVal[1] = Integer.toString(java.sql.Types.TIMESTAMP)
6517:                        .getBytes();
6518:
6519:                // JDBC Data type
6520:                rowVal[2] = s2b("0"); // Precision
6521:                rowVal[3] = s2b("'"); // Literal Prefix
6522:                rowVal[4] = s2b("'"); // Literal Suffix
6523:                rowVal[5] = s2b("[(M)]"); // Create Params
6524:                rowVal[6] = Integer.toString(
6525:                        java.sql.DatabaseMetaData.typeNullable).getBytes();
6526:
6527:                // Nullable
6528:                rowVal[7] = s2b("false"); // Case Sensitive
6529:                rowVal[8] = Integer.toString(
6530:                        java.sql.DatabaseMetaData.typeSearchable).getBytes();
6531:
6532:                // Searchable
6533:                rowVal[9] = s2b("false"); // Unsignable
6534:                rowVal[10] = s2b("false"); // Fixed Prec Scale
6535:                rowVal[11] = s2b("false"); // Auto Increment
6536:                rowVal[12] = s2b("TIMESTAMP"); // Locale Type Name
6537:                rowVal[13] = s2b("0"); // Minimum Scale
6538:                rowVal[14] = s2b("0"); // Maximum Scale
6539:                rowVal[15] = s2b("0"); // SQL Data Type (not used)
6540:                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
6541:                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
6542:                tuples.add(new ByteArrayRow(rowVal));
6543:
6544:                return buildResultSet(fields, tuples);
6545:            }
6546:
6547:            /**
6548:             * JDBC 2.0 Get a description of the user-defined types defined in a
6549:             * particular schema. Schema specific UDTs may have type JAVA_OBJECT,
6550:             * STRUCT, or DISTINCT.
6551:             * <P>
6552:             * Only types matching the catalog, schema, type name and type criteria are
6553:             * returned. They are ordered by DATA_TYPE, TYPE_SCHEM and TYPE_NAME. The
6554:             * type name parameter may be a fully qualified name. In this case, the
6555:             * catalog and schemaPattern parameters are ignored.
6556:             * </p>
6557:             * <P>
6558:             * Each type description has the following columns:
6559:             * <OL>
6560:             * <li> <B>TYPE_CAT</B> String => the type's catalog (may be null) </li>
6561:             * <li> <B>TYPE_SCHEM</B> String => type's schema (may be null) </li>
6562:             * <li> <B>TYPE_NAME</B> String => type name </li>
6563:             * <li> <B>CLASS_NAME</B> String => Java class name </li>
6564:             * <li> <B>DATA_TYPE</B> String => type value defined in java.sql.Types.
6565:             * One of JAVA_OBJECT, STRUCT, or DISTINCT </li>
6566:             * <li> <B>REMARKS</B> String => explanatory comment on the type </li>
6567:             * </ol>
6568:             * </p>
6569:             * <P>
6570:             * <B>Note:</B> If the driver does not support UDTs then an empty result
6571:             * set is returned.
6572:             * </p>
6573:             * 
6574:             * @param catalog
6575:             *            a catalog name; "" retrieves those without a catalog; null
6576:             *            means drop catalog name from the selection criteria
6577:             * @param schemaPattern
6578:             *            a schema name pattern; "" retrieves those without a schema
6579:             * @param typeNamePattern
6580:             *            a type name pattern; may be a fully qualified name
6581:             * @param types
6582:             *            a list of user-named types to include (JAVA_OBJECT, STRUCT, or
6583:             *            DISTINCT); null returns all types
6584:             * @return ResultSet - each row is a type description
6585:             * @exception SQLException
6586:             *                if a database-access error occurs.
6587:             */
6588:            public java.sql.ResultSet getUDTs(String catalog,
6589:                    String schemaPattern, String typeNamePattern, int[] types)
6590:                    throws SQLException {
6591:                Field[] fields = new Field[6];
6592:                fields[0] = new Field("", "TYPE_CAT", Types.VARCHAR, 32);
6593:                fields[1] = new Field("", "TYPE_SCHEM", Types.VARCHAR, 32);
6594:                fields[2] = new Field("", "TYPE_NAME", Types.VARCHAR, 32);
6595:                fields[3] = new Field("", "CLASS_NAME", Types.VARCHAR, 32);
6596:                fields[4] = new Field("", "DATA_TYPE", Types.VARCHAR, 32);
6597:                fields[5] = new Field("", "REMARKS", Types.VARCHAR, 32);
6598:
6599:                ArrayList tuples = new ArrayList();
6600:
6601:                return buildResultSet(fields, tuples);
6602:            }
6603:
6604:            /**
6605:             * What's the url for this database?
6606:             * 
6607:             * @return the url or null if it can't be generated
6608:             * @throws SQLException
6609:             *             DOCUMENT ME!
6610:             */
6611:            public String getURL() throws SQLException {
6612:                return this .conn.getURL();
6613:            }
6614:
6615:            /**
6616:             * What's our user name as known to the database?
6617:             * 
6618:             * @return our database user name
6619:             * @throws SQLException
6620:             *             DOCUMENT ME!
6621:             */
6622:            public String getUserName() throws SQLException {
6623:                if (this .conn.getUseHostsInPrivileges()) {
6624:                    Statement stmt = null;
6625:                    ResultSet rs = null;
6626:
6627:                    try {
6628:                        stmt = this .conn.createStatement();
6629:                        stmt.setEscapeProcessing(false);
6630:
6631:                        rs = stmt.executeQuery("SELECT USER()");
6632:                        rs.next();
6633:
6634:                        return rs.getString(1);
6635:                    } finally {
6636:                        if (rs != null) {
6637:                            try {
6638:                                rs.close();
6639:                            } catch (Exception ex) {
6640:                                AssertionFailedException.shouldNotHappen(ex);
6641:                            }
6642:
6643:                            rs = null;
6644:                        }
6645:
6646:                        if (stmt != null) {
6647:                            try {
6648:                                stmt.close();
6649:                            } catch (Exception ex) {
6650:                                AssertionFailedException.shouldNotHappen(ex);
6651:                            }
6652:
6653:                            stmt = null;
6654:                        }
6655:                    }
6656:                }
6657:
6658:                return this .conn.getUser();
6659:            }
6660:
6661:            /**
6662:             * Get a description of a table's columns that are automatically updated
6663:             * when any value in a row is updated. They are unordered.
6664:             * <P>
6665:             * Each column description has the following columns:
6666:             * <OL>
6667:             * <li> <B>SCOPE</B> short => is not used </li>
6668:             * <li> <B>COLUMN_NAME</B> String => column name </li>
6669:             * <li> <B>DATA_TYPE</B> short => SQL data type from java.sql.Types </li>
6670:             * <li> <B>TYPE_NAME</B> String => Data source dependent type name </li>
6671:             * <li> <B>COLUMN_SIZE</B> int => precision </li>
6672:             * <li> <B>BUFFER_LENGTH</B> int => length of column value in bytes </li>
6673:             * <li> <B>DECIMAL_DIGITS</B> short => scale </li>
6674:             * <li> <B>PSEUDO_COLUMN</B> short => is this a pseudo column like an
6675:             * Oracle ROWID
6676:             * <UL>
6677:             * <li> versionColumnUnknown - may or may not be pseudo column </li>
6678:             * <li> versionColumnNotPseudo - is NOT a pseudo column </li>
6679:             * <li> versionColumnPseudo - is a pseudo column </li>
6680:             * </ul>
6681:             * </li>
6682:             * </ol>
6683:             * </p>
6684:             * 
6685:             * @param catalog
6686:             *            a catalog name; "" retrieves those without a catalog
6687:             * @param schema
6688:             *            a schema name; "" retrieves those without a schema
6689:             * @param table
6690:             *            a table name
6691:             * @return ResultSet each row is a column description
6692:             * @throws SQLException
6693:             *             DOCUMENT ME!
6694:             */
6695:            public java.sql.ResultSet getVersionColumns(String catalog,
6696:                    String schema, String table) throws SQLException {
6697:                Field[] fields = new Field[8];
6698:                fields[0] = new Field("", "SCOPE", Types.SMALLINT, 5);
6699:                fields[1] = new Field("", "COLUMN_NAME", Types.CHAR, 32);
6700:                fields[2] = new Field("", "DATA_TYPE", Types.SMALLINT, 5);
6701:                fields[3] = new Field("", "TYPE_NAME", Types.CHAR, 16);
6702:                fields[4] = new Field("", "COLUMN_SIZE", Types.CHAR, 16);
6703:                fields[5] = new Field("", "BUFFER_LENGTH", Types.CHAR, 16);
6704:                fields[6] = new Field("", "DECIMAL_DIGITS", Types.CHAR, 16);
6705:                fields[7] = new Field("", "PSEUDO_COLUMN", Types.SMALLINT, 5);
6706:
6707:                return buildResultSet(fields, new ArrayList());
6708:
6709:                // do TIMESTAMP columns count?
6710:            }
6711:
6712:            /**
6713:             * JDBC 2.0 Determine whether or not a visible row insert can be detected by
6714:             * calling ResultSet.rowInserted().
6715:             * 
6716:             * @param type
6717:             *            set type, i.e. ResultSet.TYPE_XXX
6718:             * @return true if changes are detected by the resultset type
6719:             * @exception SQLException
6720:             *                if a database-access error occurs.
6721:             */
6722:            public boolean insertsAreDetected(int type) throws SQLException {
6723:                return false;
6724:            }
6725:
6726:            /**
6727:             * Does a catalog appear at the start of a qualified table name? (Otherwise
6728:             * it appears at the end)
6729:             * 
6730:             * @return true if it appears at the start
6731:             * @throws SQLException
6732:             *             DOCUMENT ME!
6733:             */
6734:            public boolean isCatalogAtStart() throws SQLException {
6735:                return true;
6736:            }
6737:
6738:            /**
6739:             * Is the database in read-only mode?
6740:             * 
6741:             * @return true if so
6742:             * @throws SQLException
6743:             *             DOCUMENT ME!
6744:             */
6745:            public boolean isReadOnly() throws SQLException {
6746:                return false;
6747:            }
6748:
6749:            /**
6750:             * @see DatabaseMetaData#locatorsUpdateCopy()
6751:             */
6752:            public boolean locatorsUpdateCopy() throws SQLException {
6753:                return !this .conn.getEmulateLocators();
6754:            }
6755:
6756:            /**
6757:             * Are concatenations between NULL and non-NULL values NULL? A JDBC
6758:             * compliant driver always returns true.
6759:             * 
6760:             * @return true if so
6761:             * @throws SQLException
6762:             *             DOCUMENT ME!
6763:             */
6764:            public boolean nullPlusNonNullIsNull() throws SQLException {
6765:                return true;
6766:            }
6767:
6768:            /**
6769:             * Are NULL values sorted at the end regardless of sort order?
6770:             * 
6771:             * @return true if so
6772:             * @throws SQLException
6773:             *             DOCUMENT ME!
6774:             */
6775:            public boolean nullsAreSortedAtEnd() throws SQLException {
6776:                return false;
6777:            }
6778:
6779:            /**
6780:             * Are NULL values sorted at the start regardless of sort order?
6781:             * 
6782:             * @return true if so
6783:             * @throws SQLException
6784:             *             DOCUMENT ME!
6785:             */
6786:            public boolean nullsAreSortedAtStart() throws SQLException {
6787:                return (this .conn.versionMeetsMinimum(4, 0, 2) && !this .conn
6788:                        .versionMeetsMinimum(4, 0, 11));
6789:            }
6790:
6791:            /**
6792:             * Are NULL values sorted high?
6793:             * 
6794:             * @return true if so
6795:             * @throws SQLException
6796:             *             DOCUMENT ME!
6797:             */
6798:            public boolean nullsAreSortedHigh() throws SQLException {
6799:                return false;
6800:            }
6801:
6802:            /**
6803:             * Are NULL values sorted low?
6804:             * 
6805:             * @return true if so
6806:             * @throws SQLException
6807:             *             DOCUMENT ME!
6808:             */
6809:            public boolean nullsAreSortedLow() throws SQLException {
6810:                return !nullsAreSortedHigh();
6811:            }
6812:
6813:            /**
6814:             * DOCUMENT ME!
6815:             * 
6816:             * @param type
6817:             *            DOCUMENT ME!
6818:             * @return DOCUMENT ME!
6819:             * @throws SQLException
6820:             *             DOCUMENT ME!
6821:             */
6822:            public boolean othersDeletesAreVisible(int type)
6823:                    throws SQLException {
6824:                return false;
6825:            }
6826:
6827:            /**
6828:             * DOCUMENT ME!
6829:             * 
6830:             * @param type
6831:             *            DOCUMENT ME!
6832:             * @return DOCUMENT ME!
6833:             * @throws SQLException
6834:             *             DOCUMENT ME!
6835:             */
6836:            public boolean othersInsertsAreVisible(int type)
6837:                    throws SQLException {
6838:                return false;
6839:            }
6840:
6841:            /**
6842:             * JDBC 2.0 Determine whether changes made by others are visible.
6843:             * 
6844:             * @param type
6845:             *            set type, i.e. ResultSet.TYPE_XXX
6846:             * @return true if changes are visible for the result set type
6847:             * @exception SQLException
6848:             *                if a database-access error occurs.
6849:             */
6850:            public boolean othersUpdatesAreVisible(int type)
6851:                    throws SQLException {
6852:                return false;
6853:            }
6854:
6855:            /**
6856:             * DOCUMENT ME!
6857:             * 
6858:             * @param type
6859:             *            DOCUMENT ME!
6860:             * @return DOCUMENT ME!
6861:             * @throws SQLException
6862:             *             DOCUMENT ME!
6863:             */
6864:            public boolean ownDeletesAreVisible(int type) throws SQLException {
6865:                return false;
6866:            }
6867:
6868:            /**
6869:             * DOCUMENT ME!
6870:             * 
6871:             * @param type
6872:             *            DOCUMENT ME!
6873:             * @return DOCUMENT ME!
6874:             * @throws SQLException
6875:             *             DOCUMENT ME!
6876:             */
6877:            public boolean ownInsertsAreVisible(int type) throws SQLException {
6878:                return false;
6879:            }
6880:
6881:            /**
6882:             * JDBC 2.0 Determine whether a result set's own changes visible.
6883:             * 
6884:             * @param type
6885:             *            set type, i.e. ResultSet.TYPE_XXX
6886:             * @return true if changes are visible for the result set type
6887:             * @exception SQLException
6888:             *                if a database-access error occurs.
6889:             */
6890:            public boolean ownUpdatesAreVisible(int type) throws SQLException {
6891:                return false;
6892:            }
6893:
6894:            private LocalAndReferencedColumns parseTableStatusIntoLocalAndReferencedColumns(
6895:                    String keysComment) throws SQLException {
6896:                // keys will equal something like this:
6897:                // (parent_service_id child_service_id) REFER
6898:                // ds/subservices(parent_service_id child_service_id)
6899:                //
6900:                // simple-columned keys: (m) REFER
6901:                // airline/tt(a)
6902:                //
6903:                // multi-columned keys : (m n) REFER
6904:                // airline/vv(a b)
6905:                //
6906:                // parse of the string into three phases:
6907:                // 1: parse the opening parentheses to determine how many results there
6908:                // will be
6909:                // 2: read in the schema name/table name
6910:                // 3: parse the closing parentheses
6911:
6912:                String columnsDelimitter = ","; // what version did this change in?
6913:
6914:                char quoteChar = this .quotedId.length() == 0 ? 0
6915:                        : this .quotedId.charAt(0);
6916:
6917:                int indexOfOpenParenLocalColumns = StringUtils
6918:                        .indexOfIgnoreCaseRespectQuotes(0, keysComment, "(",
6919:                                quoteChar, true);
6920:
6921:                if (indexOfOpenParenLocalColumns == -1) {
6922:                    throw SQLError
6923:                            .createSQLException(
6924:                                    "Error parsing foreign keys definition,"
6925:                                            + " couldn't find start of local columns list.",
6926:                                    SQLError.SQL_STATE_GENERAL_ERROR);
6927:                }
6928:
6929:                String constraintName = removeQuotedId(keysComment.substring(0,
6930:                        indexOfOpenParenLocalColumns).trim());
6931:                keysComment = keysComment.substring(
6932:                        indexOfOpenParenLocalColumns, keysComment.length());
6933:
6934:                String keysCommentTrimmed = keysComment.trim();
6935:
6936:                int indexOfCloseParenLocalColumns = StringUtils
6937:                        .indexOfIgnoreCaseRespectQuotes(0, keysCommentTrimmed,
6938:                                ")", quoteChar, true);
6939:
6940:                if (indexOfCloseParenLocalColumns == -1) {
6941:                    throw SQLError
6942:                            .createSQLException(
6943:                                    "Error parsing foreign keys definition,"
6944:                                            + " couldn't find end of local columns list.",
6945:                                    SQLError.SQL_STATE_GENERAL_ERROR);
6946:                }
6947:
6948:                String localColumnNamesString = keysCommentTrimmed.substring(1,
6949:                        indexOfCloseParenLocalColumns);
6950:
6951:                int indexOfRefer = StringUtils.indexOfIgnoreCaseRespectQuotes(
6952:                        0, keysCommentTrimmed, "REFER ", this .quotedId
6953:                                .charAt(0), true);
6954:
6955:                if (indexOfRefer == -1) {
6956:                    throw SQLError
6957:                            .createSQLException(
6958:                                    "Error parsing foreign keys definition,"
6959:                                            + " couldn't find start of referenced tables list.",
6960:                                    SQLError.SQL_STATE_GENERAL_ERROR);
6961:                }
6962:
6963:                int indexOfOpenParenReferCol = StringUtils
6964:                        .indexOfIgnoreCaseRespectQuotes(indexOfRefer,
6965:                                keysCommentTrimmed, "(", quoteChar, false);
6966:
6967:                if (indexOfOpenParenReferCol == -1) {
6968:                    throw SQLError
6969:                            .createSQLException(
6970:                                    "Error parsing foreign keys definition,"
6971:                                            + " couldn't find start of referenced columns list.",
6972:                                    SQLError.SQL_STATE_GENERAL_ERROR);
6973:                }
6974:
6975:                String referCatalogTableString = keysCommentTrimmed.substring(
6976:                        indexOfRefer + "REFER ".length(),
6977:                        indexOfOpenParenReferCol);
6978:
6979:                int indexOfSlash = StringUtils.indexOfIgnoreCaseRespectQuotes(
6980:                        0, referCatalogTableString, "/", this .quotedId
6981:                                .charAt(0), false);
6982:
6983:                if (indexOfSlash == -1) {
6984:                    throw SQLError
6985:                            .createSQLException(
6986:                                    "Error parsing foreign keys definition,"
6987:                                            + " couldn't find name of referenced catalog.",
6988:                                    SQLError.SQL_STATE_GENERAL_ERROR);
6989:                }
6990:
6991:                String referCatalog = removeQuotedId(referCatalogTableString
6992:                        .substring(0, indexOfSlash));
6993:                String referTable = removeQuotedId(referCatalogTableString
6994:                        .substring(indexOfSlash + 1).trim());
6995:
6996:                int indexOfCloseParenRefer = StringUtils
6997:                        .indexOfIgnoreCaseRespectQuotes(
6998:                                indexOfOpenParenReferCol, keysCommentTrimmed,
6999:                                ")", quoteChar, true);
7000:
7001:                if (indexOfCloseParenRefer == -1) {
7002:                    throw SQLError
7003:                            .createSQLException(
7004:                                    "Error parsing foreign keys definition,"
7005:                                            + " couldn't find end of referenced columns list.",
7006:                                    SQLError.SQL_STATE_GENERAL_ERROR);
7007:                }
7008:
7009:                String referColumnNamesString = keysCommentTrimmed.substring(
7010:                        indexOfOpenParenReferCol + 1, indexOfCloseParenRefer);
7011:
7012:                List referColumnsList = StringUtils.split(
7013:                        referColumnNamesString, columnsDelimitter,
7014:                        this .quotedId, this .quotedId, false);
7015:                List localColumnsList = StringUtils.split(
7016:                        localColumnNamesString, columnsDelimitter,
7017:                        this .quotedId, this .quotedId, false);
7018:
7019:                return new LocalAndReferencedColumns(localColumnsList,
7020:                        referColumnsList, constraintName, referCatalog,
7021:                        referTable);
7022:            }
7023:
7024:            private String removeQuotedId(String s) {
7025:                if (s == null) {
7026:                    return null;
7027:                }
7028:
7029:                if (this .quotedId.equals("")) {
7030:                    return s;
7031:                }
7032:
7033:                s = s.trim();
7034:
7035:                int frontOffset = 0;
7036:                int backOffset = s.length();
7037:                int quoteLength = this .quotedId.length();
7038:
7039:                if (s.startsWith(this .quotedId)) {
7040:                    frontOffset = quoteLength;
7041:                }
7042:
7043:                if (s.endsWith(this .quotedId)) {
7044:                    backOffset -= quoteLength;
7045:                }
7046:
7047:                return s.substring(frontOffset, backOffset);
7048:            }
7049:
7050:            /**
7051:             * Converts the given string to bytes, using the connection's character
7052:             * encoding, or if not available, the JVM default encoding.
7053:             * 
7054:             * @param s
7055:             *            DOCUMENT ME!
7056:             * @return DOCUMENT ME!
7057:             */
7058:            protected byte[] s2b(String s) throws SQLException {
7059:                return StringUtils.s2b(s, this .conn);
7060:            }
7061:
7062:            /**
7063:             * Does the database store mixed case unquoted SQL identifiers in lower
7064:             * case?
7065:             * 
7066:             * @return true if so
7067:             * @throws SQLException
7068:             *             DOCUMENT ME!
7069:             */
7070:            public boolean storesLowerCaseIdentifiers() throws SQLException {
7071:                return this .conn.lowerCaseTableNames();
7072:            }
7073:
7074:            /**
7075:             * Does the database store mixed case quoted SQL identifiers in lower case?
7076:             * A JDBC compliant driver will always return false.
7077:             * 
7078:             * @return true if so
7079:             * @throws SQLException
7080:             *             DOCUMENT ME!
7081:             */
7082:            public boolean storesLowerCaseQuotedIdentifiers()
7083:                    throws SQLException {
7084:                return this .conn.lowerCaseTableNames();
7085:            }
7086:
7087:            /**
7088:             * Does the database store mixed case unquoted SQL identifiers in mixed
7089:             * case?
7090:             * 
7091:             * @return true if so
7092:             * @throws SQLException
7093:             *             DOCUMENT ME!
7094:             */
7095:            public boolean storesMixedCaseIdentifiers() throws SQLException {
7096:                return !this .conn.lowerCaseTableNames();
7097:            }
7098:
7099:            /**
7100:             * Does the database store mixed case quoted SQL identifiers in mixed case?
7101:             * A JDBC compliant driver will always return false.
7102:             * 
7103:             * @return true if so
7104:             * @throws SQLException
7105:             *             DOCUMENT ME!
7106:             */
7107:            public boolean storesMixedCaseQuotedIdentifiers()
7108:                    throws SQLException {
7109:                return !this .conn.lowerCaseTableNames();
7110:            }
7111:
7112:            /**
7113:             * Does the database store mixed case unquoted SQL identifiers in upper
7114:             * case?
7115:             * 
7116:             * @return true if so
7117:             * @throws SQLException
7118:             *             DOCUMENT ME!
7119:             */
7120:            public boolean storesUpperCaseIdentifiers() throws SQLException {
7121:                return false;
7122:            }
7123:
7124:            /**
7125:             * Does the database store mixed case quoted SQL identifiers in upper case?
7126:             * A JDBC compliant driver will always return true.
7127:             * 
7128:             * @return true if so
7129:             * @throws SQLException
7130:             *             DOCUMENT ME!
7131:             */
7132:            public boolean storesUpperCaseQuotedIdentifiers()
7133:                    throws SQLException {
7134:                return true; // not actually true, but required by JDBC spec!?
7135:            }
7136:
7137:            /**
7138:             * Is "ALTER TABLE" with add column supported?
7139:             * 
7140:             * @return true if so
7141:             * @throws SQLException
7142:             *             DOCUMENT ME!
7143:             */
7144:            public boolean supportsAlterTableWithAddColumn()
7145:                    throws SQLException {
7146:                return true;
7147:            }
7148:
7149:            /**
7150:             * Is "ALTER TABLE" with drop column supported?
7151:             * 
7152:             * @return true if so
7153:             * @throws SQLException
7154:             *             DOCUMENT ME!
7155:             */
7156:            public boolean supportsAlterTableWithDropColumn()
7157:                    throws SQLException {
7158:                return true;
7159:            }
7160:
7161:            /**
7162:             * Is the ANSI92 entry level SQL grammar supported? All JDBC compliant
7163:             * drivers must return true.
7164:             * 
7165:             * @return true if so
7166:             * @throws SQLException
7167:             *             DOCUMENT ME!
7168:             */
7169:            public boolean supportsANSI92EntryLevelSQL() throws SQLException {
7170:                return true;
7171:            }
7172:
7173:            /**
7174:             * Is the ANSI92 full SQL grammar supported?
7175:             * 
7176:             * @return true if so
7177:             * @throws SQLException
7178:             *             DOCUMENT ME!
7179:             */
7180:            public boolean supportsANSI92FullSQL() throws SQLException {
7181:                return false;
7182:            }
7183:
7184:            /**
7185:             * Is the ANSI92 intermediate SQL grammar supported?
7186:             * 
7187:             * @return true if so
7188:             * @throws SQLException
7189:             *             DOCUMENT ME!
7190:             */
7191:            public boolean supportsANSI92IntermediateSQL() throws SQLException {
7192:                return false;
7193:            }
7194:
7195:            /**
7196:             * JDBC 2.0 Return true if the driver supports batch updates, else return
7197:             * false.
7198:             * 
7199:             * @return DOCUMENT ME!
7200:             * @throws SQLException
7201:             *             DOCUMENT ME!
7202:             */
7203:            public boolean supportsBatchUpdates() throws SQLException {
7204:                return true;
7205:            }
7206:
7207:            /**
7208:             * Can a catalog name be used in a data manipulation statement?
7209:             * 
7210:             * @return true if so
7211:             * @throws SQLException
7212:             *             DOCUMENT ME!
7213:             */
7214:            public boolean supportsCatalogsInDataManipulation()
7215:                    throws SQLException {
7216:                // Servers before 3.22 could not do this
7217:                return this .conn.versionMeetsMinimum(3, 22, 0);
7218:            }
7219:
7220:            /**
7221:             * Can a catalog name be used in a index definition statement?
7222:             * 
7223:             * @return true if so
7224:             * @throws SQLException
7225:             *             DOCUMENT ME!
7226:             */
7227:            public boolean supportsCatalogsInIndexDefinitions()
7228:                    throws SQLException {
7229:                // Servers before 3.22 could not do this
7230:                return this .conn.versionMeetsMinimum(3, 22, 0);
7231:            }
7232:
7233:            /**
7234:             * Can a catalog name be used in a privilege definition statement?
7235:             * 
7236:             * @return true if so
7237:             * @throws SQLException
7238:             *             DOCUMENT ME!
7239:             */
7240:            public boolean supportsCatalogsInPrivilegeDefinitions()
7241:                    throws SQLException {
7242:                // Servers before 3.22 could not do this
7243:                return this .conn.versionMeetsMinimum(3, 22, 0);
7244:            }
7245:
7246:            /**
7247:             * Can a catalog name be used in a procedure call statement?
7248:             * 
7249:             * @return true if so
7250:             * @throws SQLException
7251:             *             DOCUMENT ME!
7252:             */
7253:            public boolean supportsCatalogsInProcedureCalls()
7254:                    throws SQLException {
7255:                // Servers before 3.22 could not do this
7256:                return this .conn.versionMeetsMinimum(3, 22, 0);
7257:            }
7258:
7259:            /**
7260:             * Can a catalog name be used in a table definition statement?
7261:             * 
7262:             * @return true if so
7263:             * @throws SQLException
7264:             *             DOCUMENT ME!
7265:             */
7266:            public boolean supportsCatalogsInTableDefinitions()
7267:                    throws SQLException {
7268:                // Servers before 3.22 could not do this
7269:                return this .conn.versionMeetsMinimum(3, 22, 0);
7270:            }
7271:
7272:            /**
7273:             * Is column aliasing supported?
7274:             * <P>
7275:             * If so, the SQL AS clause can be used to provide names for computed
7276:             * columns or to provide alias names for columns as required. A JDBC
7277:             * compliant driver always returns true.
7278:             * </p>
7279:             * 
7280:             * @return true if so
7281:             * @throws SQLException
7282:             *             DOCUMENT ME!
7283:             */
7284:            public boolean supportsColumnAliasing() throws SQLException {
7285:                return true;
7286:            }
7287:
7288:            /**
7289:             * Is the CONVERT function between SQL types supported?
7290:             * 
7291:             * @return true if so
7292:             * @throws SQLException
7293:             *             DOCUMENT ME!
7294:             */
7295:            public boolean supportsConvert() throws SQLException {
7296:                return false;
7297:            }
7298:
7299:            /**
7300:             * Is CONVERT between the given SQL types supported?
7301:             * 
7302:             * @param fromType
7303:             *            the type to convert from
7304:             * @param toType
7305:             *            the type to convert to
7306:             * @return true if so
7307:             * @throws SQLException
7308:             *             if an error occurs
7309:             * @see Types
7310:             */
7311:            public boolean supportsConvert(int fromType, int toType)
7312:                    throws SQLException {
7313:                switch (fromType) {
7314:                /*
7315:                 * The char/binary types can be converted to pretty much anything.
7316:                 */
7317:                case java.sql.Types.CHAR:
7318:                case java.sql.Types.VARCHAR:
7319:                case java.sql.Types.LONGVARCHAR:
7320:                case java.sql.Types.BINARY:
7321:                case java.sql.Types.VARBINARY:
7322:                case java.sql.Types.LONGVARBINARY:
7323:
7324:                    switch (toType) {
7325:                    case java.sql.Types.DECIMAL:
7326:                    case java.sql.Types.NUMERIC:
7327:                    case java.sql.Types.REAL:
7328:                    case java.sql.Types.TINYINT:
7329:                    case java.sql.Types.SMALLINT:
7330:                    case java.sql.Types.INTEGER:
7331:                    case java.sql.Types.BIGINT:
7332:                    case java.sql.Types.FLOAT:
7333:                    case java.sql.Types.DOUBLE:
7334:                    case java.sql.Types.CHAR:
7335:                    case java.sql.Types.VARCHAR:
7336:                    case java.sql.Types.LONGVARCHAR:
7337:                    case java.sql.Types.BINARY:
7338:                    case java.sql.Types.VARBINARY:
7339:                    case java.sql.Types.LONGVARBINARY:
7340:                    case java.sql.Types.OTHER:
7341:                    case java.sql.Types.DATE:
7342:                    case java.sql.Types.TIME:
7343:                    case java.sql.Types.TIMESTAMP:
7344:                        return true;
7345:
7346:                    default:
7347:                        return false;
7348:                    }
7349:
7350:                    /*
7351:                     * We don't handle the BIT type yet.
7352:                     */
7353:                case java.sql.Types.BIT:
7354:                    return false;
7355:
7356:                    /*
7357:                     * The numeric types. Basically they can convert among themselves, and
7358:                     * with char/binary types.
7359:                     */
7360:                case java.sql.Types.DECIMAL:
7361:                case java.sql.Types.NUMERIC:
7362:                case java.sql.Types.REAL:
7363:                case java.sql.Types.TINYINT:
7364:                case java.sql.Types.SMALLINT:
7365:                case java.sql.Types.INTEGER:
7366:                case java.sql.Types.BIGINT:
7367:                case java.sql.Types.FLOAT:
7368:                case java.sql.Types.DOUBLE:
7369:
7370:                    switch (toType) {
7371:                    case java.sql.Types.DECIMAL:
7372:                    case java.sql.Types.NUMERIC:
7373:                    case java.sql.Types.REAL:
7374:                    case java.sql.Types.TINYINT:
7375:                    case java.sql.Types.SMALLINT:
7376:                    case java.sql.Types.INTEGER:
7377:                    case java.sql.Types.BIGINT:
7378:                    case java.sql.Types.FLOAT:
7379:                    case java.sql.Types.DOUBLE:
7380:                    case java.sql.Types.CHAR:
7381:                    case java.sql.Types.VARCHAR:
7382:                    case java.sql.Types.LONGVARCHAR:
7383:                    case java.sql.Types.BINARY:
7384:                    case java.sql.Types.VARBINARY:
7385:                    case java.sql.Types.LONGVARBINARY:
7386:                        return true;
7387:
7388:                    default:
7389:                        return false;
7390:                    }
7391:
7392:                    /* MySQL doesn't support a NULL type. */
7393:                case java.sql.Types.NULL:
7394:                    return false;
7395:
7396:                    /*
7397:                     * With this driver, this will always be a serialized object, so the
7398:                     * char/binary types will work.
7399:                     */
7400:                case java.sql.Types.OTHER:
7401:
7402:                    switch (toType) {
7403:                    case java.sql.Types.CHAR:
7404:                    case java.sql.Types.VARCHAR:
7405:                    case java.sql.Types.LONGVARCHAR:
7406:                    case java.sql.Types.BINARY:
7407:                    case java.sql.Types.VARBINARY:
7408:                    case java.sql.Types.LONGVARBINARY:
7409:                        return true;
7410:
7411:                    default:
7412:                        return false;
7413:                    }
7414:
7415:                    /* Dates can be converted to char/binary types. */
7416:                case java.sql.Types.DATE:
7417:
7418:                    switch (toType) {
7419:                    case java.sql.Types.CHAR:
7420:                    case java.sql.Types.VARCHAR:
7421:                    case java.sql.Types.LONGVARCHAR:
7422:                    case java.sql.Types.BINARY:
7423:                    case java.sql.Types.VARBINARY:
7424:                    case java.sql.Types.LONGVARBINARY:
7425:                        return true;
7426:
7427:                    default:
7428:                        return false;
7429:                    }
7430:
7431:                    /* Time can be converted to char/binary types */
7432:                case java.sql.Types.TIME:
7433:
7434:                    switch (toType) {
7435:                    case java.sql.Types.CHAR:
7436:                    case java.sql.Types.VARCHAR:
7437:                    case java.sql.Types.LONGVARCHAR:
7438:                    case java.sql.Types.BINARY:
7439:                    case java.sql.Types.VARBINARY:
7440:                    case java.sql.Types.LONGVARBINARY:
7441:                        return true;
7442:
7443:                    default:
7444:                        return false;
7445:                    }
7446:
7447:                    /*
7448:                     * Timestamp can be converted to char/binary types and date/time types
7449:                     * (with loss of precision).
7450:                     */
7451:                case java.sql.Types.TIMESTAMP:
7452:
7453:                    switch (toType) {
7454:                    case java.sql.Types.CHAR:
7455:                    case java.sql.Types.VARCHAR:
7456:                    case java.sql.Types.LONGVARCHAR:
7457:                    case java.sql.Types.BINARY:
7458:                    case java.sql.Types.VARBINARY:
7459:                    case java.sql.Types.LONGVARBINARY:
7460:                    case java.sql.Types.TIME:
7461:                    case java.sql.Types.DATE:
7462:                        return true;
7463:
7464:                    default:
7465:                        return false;
7466:                    }
7467:
7468:                    /* We shouldn't get here! */
7469:                default:
7470:                    return false; // not sure
7471:                }
7472:            }
7473:
7474:            /**
7475:             * Is the ODBC Core SQL grammar supported?
7476:             * 
7477:             * @return true if so
7478:             * @throws SQLException
7479:             *             DOCUMENT ME!
7480:             */
7481:            public boolean supportsCoreSQLGrammar() throws SQLException {
7482:                return true;
7483:            }
7484:
7485:            /**
7486:             * Are correlated subqueries supported? A JDBC compliant driver always
7487:             * returns true.
7488:             * 
7489:             * @return true if so
7490:             * @throws SQLException
7491:             *             DOCUMENT ME!
7492:             */
7493:            public boolean supportsCorrelatedSubqueries() throws SQLException {
7494:                return this .conn.versionMeetsMinimum(4, 1, 0);
7495:            }
7496:
7497:            /**
7498:             * Are both data definition and data manipulation statements within a
7499:             * transaction supported?
7500:             * 
7501:             * @return true if so
7502:             * @throws SQLException
7503:             *             DOCUMENT ME!
7504:             */
7505:            public boolean supportsDataDefinitionAndDataManipulationTransactions()
7506:                    throws SQLException {
7507:                return false;
7508:            }
7509:
7510:            /**
7511:             * Are only data manipulation statements within a transaction supported?
7512:             * 
7513:             * @return true if so
7514:             * @throws SQLException
7515:             *             DOCUMENT ME!
7516:             */
7517:            public boolean supportsDataManipulationTransactionsOnly()
7518:                    throws SQLException {
7519:                return false;
7520:            }
7521:
7522:            /**
7523:             * If table correlation names are supported, are they restricted to be
7524:             * different from the names of the tables? A JDBC compliant driver always
7525:             * returns true.
7526:             * 
7527:             * @return true if so
7528:             * @throws SQLException
7529:             *             DOCUMENT ME!
7530:             */
7531:            public boolean supportsDifferentTableCorrelationNames()
7532:                    throws SQLException {
7533:                return true;
7534:            }
7535:
7536:            /**
7537:             * Are expressions in "ORDER BY" lists supported?
7538:             * 
7539:             * @return true if so
7540:             * @throws SQLException
7541:             *             DOCUMENT ME!
7542:             */
7543:            public boolean supportsExpressionsInOrderBy() throws SQLException {
7544:                return true;
7545:            }
7546:
7547:            /**
7548:             * Is the ODBC Extended SQL grammar supported?
7549:             * 
7550:             * @return true if so
7551:             * @throws SQLException
7552:             *             DOCUMENT ME!
7553:             */
7554:            public boolean supportsExtendedSQLGrammar() throws SQLException {
7555:                return false;
7556:            }
7557:
7558:            /**
7559:             * Are full nested outer joins supported?
7560:             * 
7561:             * @return true if so
7562:             * @throws SQLException
7563:             *             DOCUMENT ME!
7564:             */
7565:            public boolean supportsFullOuterJoins() throws SQLException {
7566:                return false;
7567:            }
7568:
7569:            /**
7570:             * JDBC 3.0
7571:             * 
7572:             * @return DOCUMENT ME!
7573:             */
7574:            public boolean supportsGetGeneratedKeys() {
7575:                return true;
7576:            }
7577:
7578:            /**
7579:             * Is some form of "GROUP BY" clause supported?
7580:             * 
7581:             * @return true if so
7582:             * @throws SQLException
7583:             *             DOCUMENT ME!
7584:             */
7585:            public boolean supportsGroupBy() throws SQLException {
7586:                return true;
7587:            }
7588:
7589:            /**
7590:             * Can a "GROUP BY" clause add columns not in the SELECT provided it
7591:             * specifies all the columns in the SELECT?
7592:             * 
7593:             * @return true if so
7594:             * @throws SQLException
7595:             *             DOCUMENT ME!
7596:             */
7597:            public boolean supportsGroupByBeyondSelect() throws SQLException {
7598:                return true;
7599:            }
7600:
7601:            /**
7602:             * Can a "GROUP BY" clause use columns not in the SELECT?
7603:             * 
7604:             * @return true if so
7605:             * @throws SQLException
7606:             *             DOCUMENT ME!
7607:             */
7608:            public boolean supportsGroupByUnrelated() throws SQLException {
7609:                return true;
7610:            }
7611:
7612:            /**
7613:             * Is the SQL Integrity Enhancement Facility supported?
7614:             * 
7615:             * @return true if so
7616:             * @throws SQLException
7617:             *             DOCUMENT ME!
7618:             */
7619:            public boolean supportsIntegrityEnhancementFacility()
7620:                    throws SQLException {
7621:                if (!this .conn
7622:                        .getOverrideSupportsIntegrityEnhancementFacility()) {
7623:                    return false;
7624:                }
7625:
7626:                return true;
7627:            }
7628:
7629:            /**
7630:             * Is the escape character in "LIKE" clauses supported? A JDBC compliant
7631:             * driver always returns true.
7632:             * 
7633:             * @return true if so
7634:             * @throws SQLException
7635:             *             DOCUMENT ME!
7636:             */
7637:            public boolean supportsLikeEscapeClause() throws SQLException {
7638:                return true;
7639:            }
7640:
7641:            /**
7642:             * Is there limited support for outer joins? (This will be true if
7643:             * supportFullOuterJoins is true.)
7644:             * 
7645:             * @return true if so
7646:             * @throws SQLException
7647:             *             DOCUMENT ME!
7648:             */
7649:            public boolean supportsLimitedOuterJoins() throws SQLException {
7650:                return true;
7651:            }
7652:
7653:            /**
7654:             * Is the ODBC Minimum SQL grammar supported? All JDBC compliant drivers
7655:             * must return true.
7656:             * 
7657:             * @return true if so
7658:             * @throws SQLException
7659:             *             DOCUMENT ME!
7660:             */
7661:            public boolean supportsMinimumSQLGrammar() throws SQLException {
7662:                return true;
7663:            }
7664:
7665:            /**
7666:             * Does the database support mixed case unquoted SQL identifiers?
7667:             * 
7668:             * @return true if so
7669:             * @throws SQLException
7670:             *             DOCUMENT ME!
7671:             */
7672:            public boolean supportsMixedCaseIdentifiers() throws SQLException {
7673:                return !this .conn.lowerCaseTableNames();
7674:            }
7675:
7676:            /**
7677:             * Does the database support mixed case quoted SQL identifiers? A JDBC
7678:             * compliant driver will always return true.
7679:             * 
7680:             * @return true if so
7681:             * @throws SQLException
7682:             *             DOCUMENT ME!
7683:             */
7684:            public boolean supportsMixedCaseQuotedIdentifiers()
7685:                    throws SQLException {
7686:                return !this .conn.lowerCaseTableNames();
7687:            }
7688:
7689:            /**
7690:             * @see DatabaseMetaData#supportsMultipleOpenResults()
7691:             */
7692:            public boolean supportsMultipleOpenResults() throws SQLException {
7693:                return true;
7694:            }
7695:
7696:            /**
7697:             * Are multiple ResultSets from a single execute supported?
7698:             * 
7699:             * @return true if so
7700:             * @throws SQLException
7701:             *             DOCUMENT ME!
7702:             */
7703:            public boolean supportsMultipleResultSets() throws SQLException {
7704:                return false;
7705:            }
7706:
7707:            /**
7708:             * Can we have multiple transactions open at once (on different
7709:             * connections)?
7710:             * 
7711:             * @return true if so
7712:             * @throws SQLException
7713:             *             DOCUMENT ME!
7714:             */
7715:            public boolean supportsMultipleTransactions() throws SQLException {
7716:                return true;
7717:            }
7718:
7719:            /**
7720:             * @see DatabaseMetaData#supportsNamedParameters()
7721:             */
7722:            public boolean supportsNamedParameters() throws SQLException {
7723:                return false;
7724:            }
7725:
7726:            /**
7727:             * Can columns be defined as non-nullable? A JDBC compliant driver always
7728:             * returns true.
7729:             * 
7730:             * @return true if so
7731:             * @throws SQLException
7732:             *             DOCUMENT ME!
7733:             */
7734:            public boolean supportsNonNullableColumns() throws SQLException {
7735:                return true;
7736:            }
7737:
7738:            /**
7739:             * Can cursors remain open across commits?
7740:             * 
7741:             * @return true if so
7742:             * @throws SQLException
7743:             *             if a database access error occurs
7744:             * @see Connection#disableAutoClose
7745:             */
7746:            public boolean supportsOpenCursorsAcrossCommit()
7747:                    throws SQLException {
7748:                return false;
7749:            }
7750:
7751:            /**
7752:             * Can cursors remain open across rollbacks?
7753:             * 
7754:             * @return true if so
7755:             * @throws SQLException
7756:             *             if an error occurs
7757:             * @see Connection#disableAutoClose
7758:             */
7759:            public boolean supportsOpenCursorsAcrossRollback()
7760:                    throws SQLException {
7761:                return false;
7762:            }
7763:
7764:            /**
7765:             * Can statements remain open across commits?
7766:             * 
7767:             * @return true if so
7768:             * @throws SQLException
7769:             *             if an error occurs
7770:             * @see Connection#disableAutoClose
7771:             */
7772:            public boolean supportsOpenStatementsAcrossCommit()
7773:                    throws SQLException {
7774:                return false;
7775:            }
7776:
7777:            /**
7778:             * Can statements remain open across rollbacks?
7779:             * 
7780:             * @return true if so
7781:             * @throws SQLException
7782:             *             if an error occurs
7783:             * @see Connection#disableAutoClose
7784:             */
7785:            public boolean supportsOpenStatementsAcrossRollback()
7786:                    throws SQLException {
7787:                return false;
7788:            }
7789:
7790:            /**
7791:             * Can an "ORDER BY" clause use columns not in the SELECT?
7792:             * 
7793:             * @return true if so
7794:             * @throws SQLException
7795:             *             DOCUMENT ME!
7796:             */
7797:            public boolean supportsOrderByUnrelated() throws SQLException {
7798:                return false;
7799:            }
7800:
7801:            /**
7802:             * Is some form of outer join supported?
7803:             * 
7804:             * @return true if so
7805:             * @throws SQLException
7806:             *             DOCUMENT ME!
7807:             */
7808:            public boolean supportsOuterJoins() throws SQLException {
7809:                return true;
7810:            }
7811:
7812:            /**
7813:             * Is positioned DELETE supported?
7814:             * 
7815:             * @return true if so
7816:             * @throws SQLException
7817:             *             DOCUMENT ME!
7818:             */
7819:            public boolean supportsPositionedDelete() throws SQLException {
7820:                return false;
7821:            }
7822:
7823:            /**
7824:             * Is positioned UPDATE supported?
7825:             * 
7826:             * @return true if so
7827:             * @throws SQLException
7828:             *             DOCUMENT ME!
7829:             */
7830:            public boolean supportsPositionedUpdate() throws SQLException {
7831:                return false;
7832:            }
7833:
7834:            /**
7835:             * JDBC 2.0 Does the database support the concurrency type in combination
7836:             * with the given result set type?
7837:             * 
7838:             * @param type
7839:             *            defined in java.sql.ResultSet
7840:             * @param concurrency
7841:             *            type defined in java.sql.ResultSet
7842:             * @return true if so
7843:             * @exception SQLException
7844:             *                if a database-access error occurs.
7845:             * @see Connection
7846:             */
7847:            public boolean supportsResultSetConcurrency(int type,
7848:                    int concurrency) throws SQLException {
7849:                switch (type) {
7850:                case ResultSet.TYPE_SCROLL_INSENSITIVE:
7851:                    if ((concurrency == ResultSet.CONCUR_READ_ONLY)
7852:                            || (concurrency == ResultSet.CONCUR_UPDATABLE)) {
7853:                        return true;
7854:                    } else {
7855:                        throw SQLError
7856:                                .createSQLException(
7857:                                        "Illegal arguments to supportsResultSetConcurrency()",
7858:                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
7859:                    }
7860:                case ResultSet.TYPE_FORWARD_ONLY:
7861:                    if ((concurrency == ResultSet.CONCUR_READ_ONLY)
7862:                            || (concurrency == ResultSet.CONCUR_UPDATABLE)) {
7863:                        return true;
7864:                    } else {
7865:                        throw SQLError
7866:                                .createSQLException(
7867:                                        "Illegal arguments to supportsResultSetConcurrency()",
7868:                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
7869:                    }
7870:                case ResultSet.TYPE_SCROLL_SENSITIVE:
7871:                    return false;
7872:                default:
7873:                    throw SQLError
7874:                            .createSQLException(
7875:                                    "Illegal arguments to supportsResultSetConcurrency()",
7876:                                    SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
7877:                }
7878:
7879:            }
7880:
7881:            /**
7882:             * @see DatabaseMetaData#supportsResultSetHoldability(int)
7883:             */
7884:            public boolean supportsResultSetHoldability(int holdability)
7885:                    throws SQLException {
7886:                return (holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT);
7887:            }
7888:
7889:            /**
7890:             * JDBC 2.0 Does the database support the given result set type?
7891:             * 
7892:             * @param type
7893:             *            defined in java.sql.ResultSet
7894:             * @return true if so
7895:             * @exception SQLException
7896:             *                if a database-access error occurs.
7897:             * @see Connection
7898:             */
7899:            public boolean supportsResultSetType(int type) throws SQLException {
7900:                return (type == ResultSet.TYPE_SCROLL_INSENSITIVE);
7901:            }
7902:
7903:            /**
7904:             * @see DatabaseMetaData#supportsSavepoints()
7905:             */
7906:            public boolean supportsSavepoints() throws SQLException {
7907:
7908:                return (this .conn.versionMeetsMinimum(4, 0, 14) || this .conn
7909:                        .versionMeetsMinimum(4, 1, 1));
7910:            }
7911:
7912:            /**
7913:             * Can a schema name be used in a data manipulation statement?
7914:             * 
7915:             * @return true if so
7916:             * @throws SQLException
7917:             *             DOCUMENT ME!
7918:             */
7919:            public boolean supportsSchemasInDataManipulation()
7920:                    throws SQLException {
7921:                return false;
7922:            }
7923:
7924:            /**
7925:             * Can a schema name be used in an index definition statement?
7926:             * 
7927:             * @return true if so
7928:             * @throws SQLException
7929:             *             DOCUMENT ME!
7930:             */
7931:            public boolean supportsSchemasInIndexDefinitions()
7932:                    throws SQLException {
7933:                return false;
7934:            }
7935:
7936:            /**
7937:             * Can a schema name be used in a privilege definition statement?
7938:             * 
7939:             * @return true if so
7940:             * @throws SQLException
7941:             *             DOCUMENT ME!
7942:             */
7943:            public boolean supportsSchemasInPrivilegeDefinitions()
7944:                    throws SQLException {
7945:                return false;
7946:            }
7947:
7948:            /**
7949:             * Can a schema name be used in a procedure call statement?
7950:             * 
7951:             * @return true if so
7952:             * @throws SQLException
7953:             *             DOCUMENT ME!
7954:             */
7955:            public boolean supportsSchemasInProcedureCalls()
7956:                    throws SQLException {
7957:                return false;
7958:            }
7959:
7960:            /**
7961:             * Can a schema name be used in a table definition statement?
7962:             * 
7963:             * @return true if so
7964:             * @throws SQLException
7965:             *             DOCUMENT ME!
7966:             */
7967:            public boolean supportsSchemasInTableDefinitions()
7968:                    throws SQLException {
7969:                return false;
7970:            }
7971:
7972:            /**
7973:             * Is SELECT for UPDATE supported?
7974:             * 
7975:             * @return true if so
7976:             * @throws SQLException
7977:             *             DOCUMENT ME!
7978:             */
7979:            public boolean supportsSelectForUpdate() throws SQLException {
7980:                return this .conn.versionMeetsMinimum(4, 0, 0);
7981:            }
7982:
7983:            /**
7984:             * @see DatabaseMetaData#supportsStatementPooling()
7985:             */
7986:            public boolean supportsStatementPooling() throws SQLException {
7987:                return false;
7988:            }
7989:
7990:            /**
7991:             * Are stored procedure calls using the stored procedure escape syntax
7992:             * supported?
7993:             * 
7994:             * @return true if so
7995:             * @throws SQLException
7996:             *             DOCUMENT ME!
7997:             */
7998:            public boolean supportsStoredProcedures() throws SQLException {
7999:                return this .conn.versionMeetsMinimum(5, 0, 0);
8000:            }
8001:
8002:            /**
8003:             * Are subqueries in comparison expressions supported? A JDBC compliant
8004:             * driver always returns true.
8005:             * 
8006:             * @return true if so
8007:             * @throws SQLException
8008:             *             DOCUMENT ME!
8009:             */
8010:            public boolean supportsSubqueriesInComparisons()
8011:                    throws SQLException {
8012:                return this .conn.versionMeetsMinimum(4, 1, 0);
8013:            }
8014:
8015:            /**
8016:             * Are subqueries in exists expressions supported? A JDBC compliant driver
8017:             * always returns true.
8018:             * 
8019:             * @return true if so
8020:             * @throws SQLException
8021:             *             DOCUMENT ME!
8022:             */
8023:            public boolean supportsSubqueriesInExists() throws SQLException {
8024:                return this .conn.versionMeetsMinimum(4, 1, 0);
8025:            }
8026:
8027:            /**
8028:             * Are subqueries in "in" statements supported? A JDBC compliant driver
8029:             * always returns true.
8030:             * 
8031:             * @return true if so
8032:             * @throws SQLException
8033:             *             DOCUMENT ME!
8034:             */
8035:            public boolean supportsSubqueriesInIns() throws SQLException {
8036:                return this .conn.versionMeetsMinimum(4, 1, 0);
8037:            }
8038:
8039:            /**
8040:             * Are subqueries in quantified expressions supported? A JDBC compliant
8041:             * driver always returns true.
8042:             * 
8043:             * @return true if so
8044:             * @throws SQLException
8045:             *             DOCUMENT ME!
8046:             */
8047:            public boolean supportsSubqueriesInQuantifieds()
8048:                    throws SQLException {
8049:                return this .conn.versionMeetsMinimum(4, 1, 0);
8050:            }
8051:
8052:            /**
8053:             * Are table correlation names supported? A JDBC compliant driver always
8054:             * returns true.
8055:             * 
8056:             * @return true if so
8057:             * @throws SQLException
8058:             *             DOCUMENT ME!
8059:             */
8060:            public boolean supportsTableCorrelationNames() throws SQLException {
8061:                return true;
8062:            }
8063:
8064:            /**
8065:             * Does the database support the given transaction isolation level?
8066:             * 
8067:             * @param level
8068:             *            the values are defined in java.sql.Connection
8069:             * @return true if so
8070:             * @throws SQLException
8071:             *             if a database access error occurs
8072:             * @see Connection
8073:             */
8074:            public boolean supportsTransactionIsolationLevel(int level)
8075:                    throws SQLException {
8076:                if (this .conn.supportsIsolationLevel()) {
8077:                    switch (level) {
8078:                    case java.sql.Connection.TRANSACTION_READ_COMMITTED:
8079:                    case java.sql.Connection.TRANSACTION_READ_UNCOMMITTED:
8080:                    case java.sql.Connection.TRANSACTION_REPEATABLE_READ:
8081:                    case java.sql.Connection.TRANSACTION_SERIALIZABLE:
8082:                        return true;
8083:
8084:                    default:
8085:                        return false;
8086:                    }
8087:                }
8088:
8089:                return false;
8090:            }
8091:
8092:            /**
8093:             * Are transactions supported? If not, commit is a noop and the isolation
8094:             * level is TRANSACTION_NONE.
8095:             * 
8096:             * @return true if transactions are supported
8097:             * @throws SQLException
8098:             *             DOCUMENT ME!
8099:             */
8100:            public boolean supportsTransactions() throws SQLException {
8101:                return this .conn.supportsTransactions();
8102:            }
8103:
8104:            /**
8105:             * Is SQL UNION supported? A JDBC compliant driver always returns true.
8106:             * 
8107:             * @return true if so
8108:             * @throws SQLException
8109:             *             DOCUMENT ME!
8110:             */
8111:            public boolean supportsUnion() throws SQLException {
8112:                return this .conn.versionMeetsMinimum(4, 0, 0);
8113:            }
8114:
8115:            /**
8116:             * Is SQL UNION ALL supported? A JDBC compliant driver always returns true.
8117:             * 
8118:             * @return true if so
8119:             * @throws SQLException
8120:             *             DOCUMENT ME!
8121:             */
8122:            public boolean supportsUnionAll() throws SQLException {
8123:                return this .conn.versionMeetsMinimum(4, 0, 0);
8124:            }
8125:
8126:            /**
8127:             * JDBC 2.0 Determine whether or not a visible row update can be detected by
8128:             * calling ResultSet.rowUpdated().
8129:             * 
8130:             * @param type
8131:             *            set type, i.e. ResultSet.TYPE_XXX
8132:             * @return true if changes are detected by the resultset type
8133:             * @exception SQLException
8134:             *                if a database-access error occurs.
8135:             */
8136:            public boolean updatesAreDetected(int type) throws SQLException {
8137:                return false;
8138:            }
8139:
8140:            /**
8141:             * Does the database use a file for each table?
8142:             * 
8143:             * @return true if the database uses a local file for each table
8144:             * @throws SQLException
8145:             *             DOCUMENT ME!
8146:             */
8147:            public boolean usesLocalFilePerTable() throws SQLException {
8148:                return false;
8149:            }
8150:
8151:            /**
8152:             * Does the database store tables in a local file?
8153:             * 
8154:             * @return true if so
8155:             * @throws SQLException
8156:             *             DOCUMENT ME!
8157:             */
8158:            public boolean usesLocalFiles() throws SQLException {
8159:                return false;
8160:            }
8161:
8162:            //
8163:            // JDBC-4.0 functions that aren't reliant on Java6
8164:            /**
8165:             * Retrieves a description of the given catalog's system or user 
8166:             * function parameters and return type.
8167:             *
8168:             * @see java.sql.DatabaseMetaData#getFunctionColumns(String, String, String, String)
8169:             * @since 1.6
8170:             */
8171:            public ResultSet getFunctionColumns(String catalog,
8172:                    String schemaPattern, String functionNamePattern,
8173:                    String columnNamePattern) throws SQLException {
8174:                Field[] fields = {
8175:                        new Field("", "FUNCTION_CAT", Types.VARCHAR, 0),
8176:                        new Field("", "FUNCTION_SCHEM", Types.VARCHAR, 0),
8177:                        new Field("", "FUNCTION_NAME", Types.VARCHAR, 0),
8178:                        new Field("", "COLUMN_NAME", Types.VARCHAR, 0),
8179:                        new Field("", "COLUMN_TYPE", Types.VARCHAR, 0),
8180:                        new Field("", "DATA_TYPE", Types.SMALLINT, 0),
8181:                        new Field("", "TYPE_NAME", Types.VARCHAR, 0),
8182:                        new Field("", "PRECISION", Types.INTEGER, 0),
8183:                        new Field("", "LENGTH", Types.INTEGER, 0),
8184:                        new Field("", "SCALE", Types.SMALLINT, 0),
8185:                        new Field("", "RADIX", Types.SMALLINT, 0),
8186:                        new Field("", "NULLABLE", Types.SMALLINT, 0),
8187:                        new Field("", "REMARKS", Types.VARCHAR, 0),
8188:                        new Field("", "CHAR_OCTET_LENGTH", Types.INTEGER, 0),
8189:                        new Field("", "ORDINAL_POSITION", Types.INTEGER, 0),
8190:                        new Field("", "IS_NULLABLE", Types.VARCHAR, 3),
8191:                        new Field("", "SPECIFIC_NAME", Types.VARCHAR, 0) };
8192:
8193:                return getProcedureOrFunctionColumns(fields, catalog,
8194:                        schemaPattern, functionNamePattern, columnNamePattern,
8195:                        false, true);
8196:            }
8197:
8198:            public boolean providesQueryObjectGenerator() throws SQLException {
8199:                return false;
8200:            }
8201:
8202:            public ResultSet getSchemas(String catalog, String schemaPattern)
8203:                    throws SQLException {
8204:                Field[] fields = {
8205:                        new Field("", "TABLE_SCHEM", Types.VARCHAR, 255),
8206:                        new Field("", "TABLE_CATALOG", Types.VARCHAR, 255) };
8207:
8208:                return buildResultSet(fields, new ArrayList());
8209:            }
8210:
8211:            public boolean supportsStoredFunctionsUsingCallSyntax()
8212:                    throws SQLException {
8213:                return true;
8214:            }
8215:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.