EMMA Coverage Report (generated Tue Jul 25 07:27:46 CDT 2006)
[all classes][com.mysql.jdbc]

COVERAGE SUMMARY FOR SOURCE FILE [DatabaseMetaData.java]

nameclass, %method, %block, %line, %
DatabaseMetaData.java94%  (15/16)90%  (204/227)86%  (11257/13162)83%  (2180.2/2635)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class DatabaseMetaData$ResultSetIterator0%   (0/1)0%   (0/4)0%   (0/27)0%   (0/8)
DatabaseMetaData$ResultSetIterator (DatabaseMetaData, ResultSet, int): void 0%   (0/1)0%   (0/13)0%   (0/4)
close (): void 0%   (0/1)0%   (0/4)0%   (0/2)
hasNext (): boolean 0%   (0/1)0%   (0/4)0%   (0/1)
next (): Object 0%   (0/1)0%   (0/6)0%   (0/1)
     
class DatabaseMetaData$8100% (1/1)100% (2/2)48%  (105/217)48%  (29.2/61)
forEach (Object): void 100% (1/1)44%  (88/200)47%  (28.2/60)
DatabaseMetaData$8 (DatabaseMetaData, DatabaseMetaData$IteratorWithCleanup, S... 100% (1/1)100% (17/17)100% (1/1)
     
class DatabaseMetaData$5100% (1/1)100% (2/2)65%  (105/161)66%  (23.6/36)
forEach (Object): void 100% (1/1)61%  (88/144)65%  (22.6/35)
DatabaseMetaData$5 (DatabaseMetaData, DatabaseMetaData$IteratorWithCleanup, S... 100% (1/1)100% (17/17)100% (1/1)
     
class DatabaseMetaData$4100% (1/1)100% (2/2)74%  (112/151)75%  (24.6/33)
forEach (Object): void 100% (1/1)71%  (95/134)74%  (23.6/32)
DatabaseMetaData$4 (DatabaseMetaData, DatabaseMetaData$IteratorWithCleanup, S... 100% (1/1)100% (17/17)100% (1/1)
     
class DatabaseMetaData$1100% (1/1)100% (2/2)75%  (202/270)72%  (39/54)
forEach (Object): void 100% (1/1)73%  (185/253)72%  (38/53)
DatabaseMetaData$1 (DatabaseMetaData, DatabaseMetaData$IteratorWithCleanup, S... 100% (1/1)100% (17/17)100% (1/1)
     
class DatabaseMetaData$2100% (1/1)100% (2/2)85%  (468/551)79%  (94.6/120)
forEach (Object): void 100% (1/1)84%  (442/525)79%  (93.6/119)
DatabaseMetaData$2 (DatabaseMetaData, DatabaseMetaData$IteratorWithCleanup, S... 100% (1/1)100% (26/26)100% (1/1)
     
class DatabaseMetaData$3100% (1/1)100% (2/2)85%  (288/337)86%  (54.3/63)
forEach (Object): void 100% (1/1)84%  (256/305)86%  (53.3/62)
DatabaseMetaData$3 (DatabaseMetaData, DatabaseMetaData$IteratorWithCleanup, S... 100% (1/1)100% (32/32)100% (1/1)
     
class DatabaseMetaData100% (1/1)90%  (177/196)86%  (8748/10121)84%  (1637.4/1951)
access$800 (DatabaseMetaData, String, ResultSet, boolean, String, Map, int): ... 0%   (0/1)0%   (0/9)0%   (0/1)
convertToJdbcFunctionList (String, ResultSet, boolean, String, Map, int): void 0%   (0/1)0%   (0/91)0%   (0/23)
getAttributes (String, String, String, String): ResultSet 0%   (0/1)0%   (0/220)0%   (0/23)
getConnection (): Connection 0%   (0/1)0%   (0/3)0%   (0/1)
getDatabaseMajorVersion (): int 0%   (0/1)0%   (0/4)0%   (0/1)
getDatabaseMinorVersion (): int 0%   (0/1)0%   (0/4)0%   (0/1)
getJDBCMajorVersion (): int 0%   (0/1)0%   (0/2)0%   (0/1)
getJDBCMinorVersion (): int 0%   (0/1)0%   (0/2)0%   (0/1)
getResultSetHoldability (): int 0%   (0/1)0%   (0/2)0%   (0/1)
getSQLStateType (): int 0%   (0/1)0%   (0/17)0%   (0/5)
getSuperTables (String, String, String): ResultSet 0%   (0/1)0%   (0/50)0%   (0/6)
getSuperTypes (String, String, String): ResultSet 0%   (0/1)0%   (0/70)0%   (0/8)
locatorsUpdateCopy (): boolean 0%   (0/1)0%   (0/8)0%   (0/1)
supportsGetGeneratedKeys (): boolean 0%   (0/1)0%   (0/2)0%   (0/1)
supportsMultipleOpenResults (): boolean 0%   (0/1)0%   (0/2)0%   (0/1)
supportsNamedParameters (): boolean 0%   (0/1)0%   (0/2)0%   (0/1)
supportsResultSetHoldability (int): boolean 0%   (0/1)0%   (0/7)0%   (0/1)
supportsStatementPooling (): boolean 0%   (0/1)0%   (0/2)0%   (0/1)
usesLocalFiles (): boolean 0%   (0/1)0%   (0/2)0%   (0/1)
getCascadeDeleteOption (String): int 100% (1/1)23%  (9/39)25%  (3/12)
getTablePrivileges (String, String, String): ResultSet 100% (1/1)41%  (141/341)34%  (28/83)
getColumnPrivileges (String, String, String, String): ResultSet 100% (1/1)48%  (153/319)41%  (29/71)
getCascadeUpdateOption (String): int 100% (1/1)49%  (19/39)42%  (5/12)
supportsSavepoints (): boolean 100% (1/1)56%  (10/18)56%  (0.6/1)
getUserName (): String 100% (1/1)56%  (42/75)59%  (12.9/22)
s2b (String): byte [] 100% (1/1)67%  (28/42)62%  (8/13)
getCatalogs (): ResultSet 100% (1/1)72%  (75/104)70%  (19.7/28)
convertToJdbcProcedureList (boolean, String, ResultSet, boolean, String, Map,... 100% (1/1)74%  (78/106)75%  (17.9/24)
getDefaultTransactionIsolation (): int 100% (1/1)75%  (6/8)67%  (2/3)
supportsConvert (int, int): boolean 100% (1/1)77%  (34/44)77%  (17/22)
getCallStmtParameterTypes (String, String, String, List): void 100% (1/1)81%  (544/670)80%  (135.8/169)
getCatalogIterator (String): DatabaseMetaData$IteratorWithCleanup 100% (1/1)81%  (35/43)90%  (9/10)
convertTypeDescriptorToProcedureRow (byte [], String, boolean, boolean, boole... 100% (1/1)82%  (127/154)81%  (25/31)
getTables (String, String, String, String []): ResultSet 100% (1/1)83%  (89/107)74%  (15.6/21)
supportsTransactionIsolationLevel (int): boolean 100% (1/1)83%  (10/12)80%  (4/5)
getProcedureColumns (String, String, String, String): ResultSet 100% (1/1)86%  (215/251)77%  (35.4/46)
getIdentifierQuoteString (): String 100% (1/1)86%  (12/14)80%  (4/5)
nullsAreSortedLow (): boolean 100% (1/1)86%  (6/7)86%  (0.9/1)
parseTableStatusIntoLocalAndReferencedColumns (String): DatabaseMetaData$Loca... 100% (1/1)86%  (158/184)80%  (24.9/31)
DatabaseMetaData (Connection, String): void 100% (1/1)86%  (25/29)80%  (8/10)
nullsAreSortedAtStart (): boolean 100% (1/1)89%  (16/18)89%  (0.9/1)
removeQuotedId (String): String 100% (1/1)91%  (40/44)85%  (11/13)
extractForeignKeyForTable (ArrayList, ResultSet, String): List 100% (1/1)91%  (321/351)91%  (75/82)
extractForeignKeyFromCreateTable (String, String): ResultSet 100% (1/1)93%  (170/183)90%  (35.3/39)
getResultsImpl (String, String, String, List, String, boolean): void 100% (1/1)96%  (157/164)96%  (28.9/30)
getPrimaryKeys (String, String, String): ResultSet 100% (1/1)96%  (103/107)94%  (17/18)
getBestRowIdentifier (String, String, String, int, boolean): ResultSet 100% (1/1)97%  (123/127)95%  (19/20)
getProcedures (String, String, String): ResultSet 100% (1/1)97%  (124/128)95%  (19/20)
getExportedKeys (String, String, String): ResultSet 100% (1/1)98%  (190/194)96%  (26/27)
getImportedKeys (String, String, String): ResultSet 100% (1/1)98%  (190/194)96%  (26/27)
getCrossReference (String, String, String, String, String, String): ResultSet 100% (1/1)98%  (195/199)96%  (26/27)
getColumns (String, String, String, String): ResultSet 100% (1/1)98%  (239/243)97%  (33/34)
<static initializer> 100% (1/1)100% (7/7)100% (2/2)
access$000 (DatabaseMetaData, String): byte [] 100% (1/1)100% (4/4)100% (1/1)
access$100 (DatabaseMetaData, String): String 100% (1/1)100% (4/4)100% (1/1)
access$1000 (): byte [] 100% (1/1)100% (2/2)100% (1/1)
access$200 (DatabaseMetaData, String): DatabaseMetaData$LocalAndReferencedCol... 100% (1/1)100% (4/4)100% (1/1)
access$300 (DatabaseMetaData, String): String 100% (1/1)100% (4/4)100% (1/1)
access$400 (DatabaseMetaData, String): int [] 100% (1/1)100% (4/4)100% (1/1)
access$500 (DatabaseMetaData, String, String, String, List, String): void 100% (1/1)100% (8/8)100% (1/1)
access$600 (DatabaseMetaData, String, String, String, List): void 100% (1/1)100% (7/7)100% (1/1)
access$700 (DatabaseMetaData, boolean, String, ResultSet, boolean, String, Ma... 100% (1/1)100% (10/10)100% (1/1)
access$900 (): byte [] 100% (1/1)100% (2/2)100% (1/1)
allProceduresAreCallable (): boolean 100% (1/1)100% (2/2)100% (1/1)
allTablesAreSelectable (): boolean 100% (1/1)100% (2/2)100% (1/1)
buildResultSet (Field [], ArrayList): ResultSet 100% (1/1)100% (36/36)100% (5/5)
dataDefinitionCausesTransactionCommit (): boolean 100% (1/1)100% (2/2)100% (1/1)
dataDefinitionIgnoredInTransactions (): boolean 100% (1/1)100% (2/2)100% (1/1)
deletesAreDetected (int): boolean 100% (1/1)100% (2/2)100% (1/1)
doesMaxRowSizeIncludeBlobs (): boolean 100% (1/1)100% (2/2)100% (1/1)
getCatalogSeparator (): String 100% (1/1)100% (2/2)100% (1/1)
getCatalogTerm (): String 100% (1/1)100% (2/2)100% (1/1)
getDatabaseProductName (): String 100% (1/1)100% (2/2)100% (1/1)
getDatabaseProductVersion (): String 100% (1/1)100% (4/4)100% (1/1)
getDriverMajorVersion (): int 100% (1/1)100% (2/2)100% (1/1)
getDriverMinorVersion (): int 100% (1/1)100% (2/2)100% (1/1)
getDriverName (): String 100% (1/1)100% (2/2)100% (1/1)
getDriverVersion (): String 100% (1/1)100% (2/2)100% (1/1)
getExportKeyResults (String, String, String, List, String): void 100% (1/1)100% (9/9)100% (2/2)
getExtraNameCharacters (): String 100% (1/1)100% (2/2)100% (1/1)
getForeignKeyActions (String): int [] 100% (1/1)100% (44/44)100% (7/7)
getImportKeyResults (String, String, String, List): void 100% (1/1)100% (9/9)100% (2/2)
getIndexInfo (String, String, String, boolean, boolean): ResultSet 100% (1/1)100% (173/173)100% (22/22)
getMaxBinaryLiteralLength (): int 100% (1/1)100% (2/2)100% (1/1)
getMaxCatalogNameLength (): int 100% (1/1)100% (2/2)100% (1/1)
getMaxCharLiteralLength (): int 100% (1/1)100% (2/2)100% (1/1)
getMaxColumnNameLength (): int 100% (1/1)100% (2/2)100% (1/1)
getMaxColumnsInGroupBy (): int 100% (1/1)100% (2/2)100% (1/1)
getMaxColumnsInIndex (): int 100% (1/1)100% (2/2)100% (1/1)
getMaxColumnsInOrderBy (): int 100% (1/1)100% (2/2)100% (1/1)
getMaxColumnsInSelect (): int 100% (1/1)100% (2/2)100% (1/1)
getMaxColumnsInTable (): int 100% (1/1)100% (2/2)100% (1/1)
getMaxConnections (): int 100% (1/1)100% (2/2)100% (1/1)
getMaxCursorNameLength (): int 100% (1/1)100% (2/2)100% (1/1)
getMaxIndexLength (): int 100% (1/1)100% (2/2)100% (1/1)
getMaxProcedureNameLength (): int 100% (1/1)100% (2/2)100% (1/1)
getMaxRowSize (): int 100% (1/1)100% (2/2)100% (1/1)
getMaxSchemaNameLength (): int 100% (1/1)100% (2/2)100% (1/1)
getMaxStatementLength (): int 100% (1/1)100% (4/4)100% (1/1)
getMaxStatements (): int 100% (1/1)100% (2/2)100% (1/1)
getMaxTableNameLength (): int 100% (1/1)100% (2/2)100% (1/1)
getMaxTablesInSelect (): int 100% (1/1)100% (2/2)100% (1/1)
getMaxUserNameLength (): int 100% (1/1)100% (2/2)100% (1/1)
getNumericFunctions (): String 100% (1/1)100% (2/2)100% (1/1)
getProcedureTerm (): String 100% (1/1)100% (2/2)100% (1/1)
getSQLKeywords (): String 100% (1/1)100% (2/2)100% (1/1)
getSchemaTerm (): String 100% (1/1)100% (2/2)100% (1/1)
getSchemas (): ResultSet 100% (1/1)100% (24/24)100% (5/5)
getSearchStringEscape (): String 100% (1/1)100% (2/2)100% (1/1)
getStringFunctions (): String 100% (1/1)100% (2/2)100% (1/1)
getSystemFunctions (): String 100% (1/1)100% (2/2)100% (1/1)
getTableNameWithCase (String): String 100% (1/1)100% (11/11)100% (2/2)
getTableTypes (): ResultSet 100% (1/1)100% (64/64)100% (14/14)
getTimeDateFunctions (): String 100% (1/1)100% (2/2)100% (1/1)
getTypeInfo (): ResultSet 100% (1/1)100% (4105/4105)100% (702/702)
getUDTs (String, String, String, int []): ResultSet 100% (1/1)100% (72/72)100% (9/9)
getURL (): String 100% (1/1)100% (4/4)100% (1/1)
getVersionColumns (String, String, String): ResultSet 100% (1/1)100% (90/90)100% (10/10)
insertsAreDetected (int): boolean 100% (1/1)100% (2/2)100% (1/1)
isCatalogAtStart (): boolean 100% (1/1)100% (2/2)100% (1/1)
isReadOnly (): boolean 100% (1/1)100% (2/2)100% (1/1)
nullPlusNonNullIsNull (): boolean 100% (1/1)100% (2/2)100% (1/1)
nullsAreSortedAtEnd (): boolean 100% (1/1)100% (2/2)100% (1/1)
nullsAreSortedHigh (): boolean 100% (1/1)100% (2/2)100% (1/1)
othersDeletesAreVisible (int): boolean 100% (1/1)100% (2/2)100% (1/1)
othersInsertsAreVisible (int): boolean 100% (1/1)100% (2/2)100% (1/1)
othersUpdatesAreVisible (int): boolean 100% (1/1)100% (2/2)100% (1/1)
ownDeletesAreVisible (int): boolean 100% (1/1)100% (2/2)100% (1/1)
ownInsertsAreVisible (int): boolean 100% (1/1)100% (2/2)100% (1/1)
ownUpdatesAreVisible (int): boolean 100% (1/1)100% (2/2)100% (1/1)
storesLowerCaseIdentifiers (): boolean 100% (1/1)100% (4/4)100% (1/1)
storesLowerCaseQuotedIdentifiers (): boolean 100% (1/1)100% (4/4)100% (1/1)
storesMixedCaseIdentifiers (): boolean 100% (1/1)100% (8/8)100% (1/1)
storesMixedCaseQuotedIdentifiers (): boolean 100% (1/1)100% (8/8)100% (1/1)
storesUpperCaseIdentifiers (): boolean 100% (1/1)100% (2/2)100% (1/1)
storesUpperCaseQuotedIdentifiers (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsANSI92EntryLevelSQL (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsANSI92FullSQL (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsANSI92IntermediateSQL (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsAlterTableWithAddColumn (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsAlterTableWithDropColumn (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsBatchUpdates (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsCatalogsInDataManipulation (): boolean 100% (1/1)100% (7/7)100% (1/1)
supportsCatalogsInIndexDefinitions (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsCatalogsInPrivilegeDefinitions (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsCatalogsInProcedureCalls (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsCatalogsInTableDefinitions (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsColumnAliasing (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsConvert (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsCoreSQLGrammar (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsCorrelatedSubqueries (): boolean 100% (1/1)100% (7/7)100% (1/1)
supportsDataDefinitionAndDataManipulationTransactions (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsDataManipulationTransactionsOnly (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsDifferentTableCorrelationNames (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsExpressionsInOrderBy (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsExtendedSQLGrammar (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsFullOuterJoins (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsGroupBy (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsGroupByBeyondSelect (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsGroupByUnrelated (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsIntegrityEnhancementFacility (): boolean 100% (1/1)100% (8/8)100% (3/3)
supportsLikeEscapeClause (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsLimitedOuterJoins (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsMinimumSQLGrammar (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsMixedCaseIdentifiers (): boolean 100% (1/1)100% (8/8)100% (1/1)
supportsMixedCaseQuotedIdentifiers (): boolean 100% (1/1)100% (8/8)100% (1/1)
supportsMultipleResultSets (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsMultipleTransactions (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsNonNullableColumns (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsOpenCursorsAcrossCommit (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsOpenCursorsAcrossRollback (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsOpenStatementsAcrossCommit (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsOpenStatementsAcrossRollback (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsOrderByUnrelated (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsOuterJoins (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsPositionedDelete (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsPositionedUpdate (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsResultSetConcurrency (int, int): boolean 100% (1/1)100% (32/32)100% (9/9)
supportsResultSetType (int): boolean 100% (1/1)100% (7/7)100% (1/1)
supportsSchemasInDataManipulation (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsSchemasInIndexDefinitions (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsSchemasInPrivilegeDefinitions (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsSchemasInProcedureCalls (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsSchemasInTableDefinitions (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsSelectForUpdate (): boolean 100% (1/1)100% (7/7)100% (1/1)
supportsStoredProcedures (): boolean 100% (1/1)100% (7/7)100% (1/1)
supportsSubqueriesInComparisons (): boolean 100% (1/1)100% (7/7)100% (1/1)
supportsSubqueriesInExists (): boolean 100% (1/1)100% (7/7)100% (1/1)
supportsSubqueriesInIns (): boolean 100% (1/1)100% (7/7)100% (1/1)
supportsSubqueriesInQuantifieds (): boolean 100% (1/1)100% (7/7)100% (1/1)
supportsTableCorrelationNames (): boolean 100% (1/1)100% (2/2)100% (1/1)
supportsTransactions (): boolean 100% (1/1)100% (4/4)100% (1/1)
supportsUnion (): boolean 100% (1/1)100% (7/7)100% (1/1)
supportsUnionAll (): boolean 100% (1/1)100% (7/7)100% (1/1)
updatesAreDetected (int): boolean 100% (1/1)100% (2/2)100% (1/1)
usesLocalFilePerTable (): boolean 100% (1/1)100% (2/2)100% (1/1)
     
class DatabaseMetaData$9100% (1/1)100% (2/2)88%  (307/349)82%  (64.9/79)
forEach (Object): void 100% (1/1)87%  (287/329)82%  (63.9/78)
DatabaseMetaData$9 (DatabaseMetaData, DatabaseMetaData$IteratorWithCleanup, S... 100% (1/1)100% (20/20)100% (1/1)
     
class DatabaseMetaData$TypeDescriptor100% (1/1)100% (1/1)92%  (442/478)89%  (106.5/119)
DatabaseMetaData$TypeDescriptor (DatabaseMetaData, String, String): void 100% (1/1)92%  (442/478)89%  (106.5/119)
     
class DatabaseMetaData$7100% (1/1)100% (2/2)95%  (180/190)94%  (36.6/39)
forEach (Object): void 100% (1/1)94%  (163/173)94%  (35.6/38)
DatabaseMetaData$7 (DatabaseMetaData, DatabaseMetaData$IteratorWithCleanup, S... 100% (1/1)100% (17/17)100% (1/1)
     
class DatabaseMetaData$6100% (1/1)100% (2/2)96%  (220/230)95%  (44.5/47)
forEach (Object): void 100% (1/1)95%  (200/210)95%  (43.5/46)
DatabaseMetaData$6 (DatabaseMetaData, DatabaseMetaData$IteratorWithCleanup, S... 100% (1/1)100% (20/20)100% (1/1)
     
class DatabaseMetaData$IterateBlock100% (1/1)100% (2/2)100% (30/30)100% (9/9)
DatabaseMetaData$IterateBlock (DatabaseMetaData, DatabaseMetaData$IteratorWit... 100% (1/1)100% (9/9)100% (3/3)
doForAll (): void 100% (1/1)100% (21/21)100% (6/6)
     
class DatabaseMetaData$IteratorWithCleanup100% (1/1)100% (1/1)100% (6/6)100% (1/1)
DatabaseMetaData$IteratorWithCleanup (DatabaseMetaData): void 100% (1/1)100% (6/6)100% (1/1)
     
class DatabaseMetaData$LocalAndReferencedColumns100% (1/1)100% (1/1)100% (21/21)100% (7/7)
DatabaseMetaData$LocalAndReferencedColumns (DatabaseMetaData, List, List, Str... 100% (1/1)100% (21/21)100% (7/7)
     
class DatabaseMetaData$SingleStringIterator100% (1/1)100% (4/4)100% (23/23)100% (8/8)
DatabaseMetaData$SingleStringIterator (DatabaseMetaData, String): void 100% (1/1)100% (13/13)100% (4/4)
close (): void 100% (1/1)100% (1/1)100% (1/1)
hasNext (): boolean 100% (1/1)100% (3/3)100% (1/1)
next (): Object 100% (1/1)100% (6/6)100% (2/2)

1/*
2 Copyright (C) 2002-2004 MySQL AB
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of version 2 of the GNU General Public License as 
6 published by the Free Software Foundation.
7 
8 There are special exceptions to the terms and conditions of the GPL 
9 as it is applied to this software. View the full text of the 
10 exception in file EXCEPTIONS-CONNECTOR-J in the directory of this 
11 software distribution.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 
22 
23 
24 */
25package com.mysql.jdbc;
26 
27import java.io.UnsupportedEncodingException;
28 
29import java.sql.ResultSet;
30import java.sql.SQLException;
31import java.sql.Statement;
32import java.sql.Types;
33 
34import java.util.ArrayList;
35import java.util.Collections;
36import java.util.HashMap;
37import java.util.Iterator;
38import java.util.List;
39import java.util.Locale;
40import java.util.Map;
41import java.util.StringTokenizer;
42import java.util.TreeMap;
43 
44/**
45 * JDBC Interface to Mysql functions
46 * <p>
47 * This class provides information about the database as a whole.
48 * </p>
49 * <p>
50 * Many of the methods here return lists of information in ResultSets. You can
51 * use the normal ResultSet methods such as getString and getInt to retrieve the
52 * data from these ResultSets. If a given form of metadata is not available,
53 * these methods show throw a SQLException.
54 * </p>
55 * <p>
56 * Some of these methods take arguments that are String patterns. These methods
57 * all have names such as fooPattern. Within a pattern String "%" means match
58 * any substring of 0 or more characters and "_" means match any one character.
59 * </p>
60 * 
61 * @author Mark Matthews
62 * @version $Id: DatabaseMetaData.java,v 1.27.4.66 2005/05/03 18:40:39 mmatthews
63 *          Exp $
64 */
65public class DatabaseMetaData implements java.sql.DatabaseMetaData {
66        protected abstract class IterateBlock {
67                IteratorWithCleanup iterator;
68 
69                IterateBlock(IteratorWithCleanup i) {
70                        iterator = i;
71                }
72 
73                public void doForAll() throws SQLException {
74                        try {
75                                while (iterator.hasNext()) {
76                                        forEach(iterator.next());
77                                }
78                        } finally {
79                                iterator.close();
80                        }
81                }
82 
83                abstract void forEach(Object each) throws SQLException;
84        }
85 
86        protected abstract class IteratorWithCleanup {
87                abstract void close() throws SQLException;
88 
89                abstract boolean hasNext() throws SQLException;
90 
91                abstract Object next() throws SQLException;
92        }
93 
94        class LocalAndReferencedColumns {
95                String constraintName;
96 
97                List localColumnsList;
98 
99                String referencedCatalog;
100 
101                List referencedColumnsList;
102 
103                String referencedTable;
104 
105                LocalAndReferencedColumns(List localColumns, List refColumns,
106                                String constName, String refCatalog, String refTable) {
107                        this.localColumnsList = localColumns;
108                        this.referencedColumnsList = refColumns;
109                        this.constraintName = constName;
110                        this.referencedTable = refTable;
111                        this.referencedCatalog = refCatalog;
112                }
113        }
114 
115        protected class ResultSetIterator extends IteratorWithCleanup {
116                int colIndex;
117 
118                ResultSet resultSet;
119 
120                ResultSetIterator(ResultSet rs, int index) {
121                        resultSet = rs;
122                        colIndex = index;
123                }
124 
125                void close() throws SQLException {
126                        resultSet.close();
127                }
128 
129                boolean hasNext() throws SQLException {
130                        return resultSet.next();
131                }
132 
133                Object next() throws SQLException {
134                        return resultSet.getObject(colIndex);
135                }
136        }
137 
138        protected class SingleStringIterator extends IteratorWithCleanup {
139                boolean onFirst = true;
140 
141                String value;
142 
143                SingleStringIterator(String s) {
144                        value = s;
145                }
146 
147                void close() throws SQLException {
148                        // not needed
149 
150                }
151 
152                boolean hasNext() throws SQLException {
153                        return onFirst;
154                }
155 
156                Object next() throws SQLException {
157                        onFirst = false;
158                        return value;
159                }
160        }
161 
162        /**
163         * Parses and represents common data type information used by various
164         * column/parameter methods.
165         */
166        class TypeDescriptor {
167                int bufferLength;
168 
169                int charOctetLength;
170 
171                int columnSize;
172 
173                short dataType;
174 
175                int decimalDigits;
176 
177                String isNullable;
178 
179                int nullability;
180 
181                int numPrecRadix = 10;
182 
183                String typeName;
184 
185                TypeDescriptor(String typeInfo, String nullabilityInfo)
186                                throws SQLException {
187                        String mysqlType = "";
188                        String fullMysqlType = null;
189 
190                        if (typeInfo.indexOf("(") != -1) {
191                                mysqlType = typeInfo.substring(0, typeInfo.indexOf("("));
192                        } else {
193                                mysqlType = typeInfo;
194                        }
195 
196                        int indexOfUnsignedInMysqlType = StringUtils.indexOfIgnoreCase(
197                                        mysqlType, "unsigned");
198 
199                        if (indexOfUnsignedInMysqlType != -1) {
200                                mysqlType = mysqlType.substring(0,
201                                                (indexOfUnsignedInMysqlType - 1));
202                        }
203 
204                        // Add unsigned to typename reported to enduser as 'native type', if
205                        // present
206 
207                        if (StringUtils.indexOfIgnoreCase(typeInfo, "unsigned") != -1) {
208                                fullMysqlType = mysqlType + " unsigned";
209                        } else {
210                                fullMysqlType = mysqlType;
211                        }
212 
213                        if (conn.getCapitalizeTypeNames()) {
214                                fullMysqlType = fullMysqlType.toUpperCase(Locale.ENGLISH);
215                        }
216 
217                        this.dataType = (short) MysqlDefs.mysqlToJavaType(mysqlType);
218 
219                        this.typeName = fullMysqlType;
220 
221                        // Figure Out the Size
222                        if (typeInfo != null) {
223                                if (StringUtils.startsWithIgnoreCase(typeInfo, "enum")
224                                                || StringUtils.startsWithIgnoreCase(typeInfo, "set")) {
225                                        String temp = typeInfo.substring(typeInfo.indexOf("("),
226                                                        typeInfo.lastIndexOf(")"));
227                                        java.util.StringTokenizer tokenizer = new java.util.StringTokenizer(
228                                                        temp, ",");
229                                        int maxLength = 0;
230 
231                                        while (tokenizer.hasMoreTokens()) {
232                                                maxLength = Math.max(maxLength, (tokenizer.nextToken()
233                                                                .length() - 2));
234                                        }
235 
236                                        this.columnSize = maxLength;
237                                        this.decimalDigits = 0;
238                                } else if (typeInfo.indexOf(",") != -1) {
239                                        // Numeric with decimals
240                                        this.columnSize = Integer.parseInt(typeInfo.substring(
241                                                        (typeInfo.indexOf("(") + 1),
242                                                        (typeInfo.indexOf(","))));
243                                        this.decimalDigits = Integer.parseInt(typeInfo.substring(
244                                                        (typeInfo.indexOf(",") + 1),
245                                                        (typeInfo.indexOf(")"))));
246                                } else {
247                                        this.columnSize = 0;
248 
249                                        /* If the size is specified with the DDL, use that */
250                                        if (typeInfo.indexOf("(") != -1) {
251                                                int endParenIndex = typeInfo.indexOf(")");
252 
253                                                if (endParenIndex == -1) {
254                                                        endParenIndex = typeInfo.length();
255                                                }
256 
257                                                this.columnSize = Integer.parseInt(typeInfo.substring(
258                                                                (typeInfo.indexOf("(") + 1), endParenIndex));
259 
260                                                // Adjust for pseudo-boolean
261                                                if (conn.getTinyInt1isBit()
262                                                                && this.columnSize == 1
263                                                                && StringUtils.startsWithIgnoreCase(typeInfo,
264                                                                                0, "tinyint")) {
265                                                        if (conn.getTransformedBitIsBoolean()) {
266                                                                this.dataType = Types.BOOLEAN;
267                                                                this.typeName = "BOOLEAN";
268                                                        } else {
269                                                                this.dataType = Types.BIT;
270                                                                this.typeName = "BIT";
271                                                        }
272                                                }
273                                        } else if (typeInfo.equalsIgnoreCase("tinyint")) {
274                                                this.columnSize = 1;
275                                        } else if (typeInfo.equalsIgnoreCase("smallint")) {
276                                                this.columnSize = 6;
277                                        } else if (typeInfo.equalsIgnoreCase("mediumint")) {
278                                                this.columnSize = 6;
279                                        } else if (typeInfo.equalsIgnoreCase("int")) {
280                                                this.columnSize = 11;
281                                        } else if (typeInfo.equalsIgnoreCase("integer")) {
282                                                this.columnSize = 11;
283                                        } else if (typeInfo.equalsIgnoreCase("bigint")) {
284                                                this.columnSize = 25;
285                                        } else if (typeInfo.equalsIgnoreCase("int24")) {
286                                                this.columnSize = 25;
287                                        } else if (typeInfo.equalsIgnoreCase("real")) {
288                                                this.columnSize = 12;
289                                        } else if (typeInfo.equalsIgnoreCase("float")) {
290                                                this.columnSize = 12;
291                                        } else if (typeInfo.equalsIgnoreCase("decimal")) {
292                                                this.columnSize = 12;
293                                        } else if (typeInfo.equalsIgnoreCase("numeric")) {
294                                                this.columnSize = 12;
295                                        } else if (typeInfo.equalsIgnoreCase("double")) {
296                                                this.columnSize = 22;
297                                        } else if (typeInfo.equalsIgnoreCase("char")) {
298                                                this.columnSize = 1;
299                                        } else if (typeInfo.equalsIgnoreCase("varchar")) {
300                                                this.columnSize = 255;
301                                        } else if (typeInfo.equalsIgnoreCase("date")) {
302                                                this.columnSize = 10;
303                                        } else if (typeInfo.equalsIgnoreCase("time")) {
304                                                this.columnSize = 8;
305                                        } else if (typeInfo.equalsIgnoreCase("timestamp")) {
306                                                this.columnSize = 19;
307                                        } else if (typeInfo.equalsIgnoreCase("datetime")) {
308                                                this.columnSize = 19;
309                                        } else if (typeInfo.equalsIgnoreCase("tinyblob")) {
310                                                this.columnSize = 255;
311                                        } else if (typeInfo.equalsIgnoreCase("blob")) {
312                                                this.columnSize = 65535;
313                                        } else if (typeInfo.equalsIgnoreCase("mediumblob")) {
314                                                this.columnSize = 16277215;
315                                        } else if (typeInfo.equalsIgnoreCase("longblob")) {
316                                                this.columnSize = Integer.MAX_VALUE;
317                                        } else if (typeInfo.equalsIgnoreCase("tinytext")) {
318                                                this.columnSize = 255;
319                                        } else if (typeInfo.equalsIgnoreCase("text")) {
320                                                this.columnSize = 65535;
321                                        } else if (typeInfo.equalsIgnoreCase("mediumtext")) {
322                                                this.columnSize = 16277215;
323                                        } else if (typeInfo.equalsIgnoreCase("longtext")) {
324                                                this.columnSize = Integer.MAX_VALUE;
325                                        } else if (typeInfo.equalsIgnoreCase("enum")) {
326                                                this.columnSize = 255;
327                                        } else if (typeInfo.equalsIgnoreCase("set")) {
328                                                this.columnSize = 255;
329                                        }
330 
331                                        this.decimalDigits = 0;
332                                }
333                        } else {
334                                this.decimalDigits = 0;
335                                this.columnSize = 0;
336                        }
337 
338                        // BUFFER_LENGTH
339                        this.bufferLength = MysqlIO.getMaxBuf();
340 
341                        // NUM_PREC_RADIX (is this right for char?)
342                        this.numPrecRadix = 10;
343 
344                        // Nullable?
345                        if (nullabilityInfo != null) {
346                                if (nullabilityInfo.equals("YES")) {
347                                        this.nullability = java.sql.DatabaseMetaData.columnNullable;
348                                        this.isNullable = "YES";
349 
350                                        // IS_NULLABLE
351                                } else {
352                                        this.nullability = java.sql.DatabaseMetaData.columnNoNulls;
353                                        this.isNullable = "NO";
354                                }
355                        } else {
356                                this.nullability = java.sql.DatabaseMetaData.columnNoNulls;
357                                this.isNullable = "NO";
358                        }
359                }
360        }
361 
362        private static final int DEFERRABILITY = 13;
363 
364        private static final int DELETE_RULE = 10;
365 
366        private static final int FK_NAME = 11;
367 
368        private static final int FKCOLUMN_NAME = 7;
369 
370        private static final int FKTABLE_CAT = 4;
371 
372        private static final int FKTABLE_NAME = 6;
373 
374        private static final int FKTABLE_SCHEM = 5;
375 
376        private static final int KEY_SEQ = 8;
377 
378        private static final int PK_NAME = 12;
379 
380        private static final int PKCOLUMN_NAME = 3;
381 
382        //
383        // Column indexes used by all DBMD foreign key
384        // ResultSets
385        //
386        private static final int PKTABLE_CAT = 0;
387 
388        private static final int PKTABLE_NAME = 2;
389 
390        private static final int PKTABLE_SCHEM = 1;
391 
392        /** The table type for generic tables that support foreign keys. */
393        private static final String SUPPORTS_FK = "SUPPORTS_FK";
394 
395        private static final byte[] TABLE_AS_BYTES = "TABLE".getBytes();
396 
397        private static final int UPDATE_RULE = 9;
398 
399        private static final byte[] VIEW_AS_BYTES = "VIEW".getBytes();
400 
401        /** The connection to the database */
402        protected Connection conn;
403 
404        /** The 'current' database name being used */
405        protected String database = null;
406 
407        /** What character to use when quoting identifiers */
408        protected String quotedId = null;
409 
410        /**
411         * Creates a new DatabaseMetaData object.
412         * 
413         * @param connToSet
414         *            DOCUMENT ME!
415         * @param databaseToSet
416         *            DOCUMENT ME!
417         */
418        public DatabaseMetaData(Connection connToSet, String databaseToSet) {
419                this.conn = connToSet;
420                this.database = databaseToSet;
421 
422                try {
423                        this.quotedId = this.conn.supportsQuotedIdentifiers() ? getIdentifierQuoteString()
424                                        : "";
425                } catch (SQLException sqlEx) {
426                        // Forced by API, never thrown from getIdentifierQuoteString() in
427                        // this
428                        // implementation.
429                        AssertionFailedException.shouldNotHappen(sqlEx);
430                }
431        }
432 
433        /**
434         * Can all the procedures returned by getProcedures be called by the current
435         * user?
436         * 
437         * @return true if so
438         * @throws SQLException
439         *             DOCUMENT ME!
440         */
441        public boolean allProceduresAreCallable() throws SQLException {
442                return false;
443        }
444 
445        /**
446         * Can all the tables returned by getTable be SELECTed by the current user?
447         * 
448         * @return true if so
449         * @throws SQLException
450         *             DOCUMENT ME!
451         */
452        public boolean allTablesAreSelectable() throws SQLException {
453                return false;
454        }
455 
456        private java.sql.ResultSet buildResultSet(com.mysql.jdbc.Field[] fields,
457                        java.util.ArrayList rows) throws SQLException {
458                int fieldsLength = fields.length;
459 
460                for (int i = 0; i < fieldsLength; i++) {
461                        fields[i].setConnection(this.conn);
462                        fields[i].setUseOldNameMetadata(true);
463                }
464 
465                return new com.mysql.jdbc.ResultSet(this.conn.getCatalog(), fields,
466                                new RowDataStatic(rows), this.conn, null);
467        }
468 
469        private void convertToJdbcFunctionList(String catalog,
470                        ResultSet proceduresRs, boolean needsClientFiltering, String db,
471                        Map procedureRowsOrderedByName, int nameIndex) throws SQLException {
472                while (proceduresRs.next()) {
473                        boolean shouldAdd = true;
474 
475                        if (needsClientFiltering) {
476                                shouldAdd = false;
477 
478                                String procDb = proceduresRs.getString(1);
479 
480                                if (db == null && procDb == null) {
481                                        shouldAdd = true;
482                                } else if (db != null & db.equals(procDb)) {
483                                        shouldAdd = true;
484                                }
485                        }
486 
487                        if (shouldAdd) {
488                                String functionName = proceduresRs.getString(nameIndex);
489                                byte[][] rowData = new byte[8][];
490                                rowData[0] = catalog == null ? null : s2b(catalog);
491                                rowData[1] = null;
492                                rowData[2] = s2b(functionName);
493                                rowData[3] = null;
494                                rowData[4] = null;
495                                rowData[5] = null;
496                                rowData[6] = null;
497                                rowData[7] = s2b(Integer.toString(procedureReturnsResult));
498 
499                                procedureRowsOrderedByName.put(functionName, rowData);
500                        }
501                }
502        }
503 
504        private void convertToJdbcProcedureList(boolean fromSelect, String catalog,
505                        ResultSet proceduresRs, boolean needsClientFiltering, String db,
506                        Map procedureRowsOrderedByName, int nameIndex) throws SQLException {
507                while (proceduresRs.next()) {
508                        boolean shouldAdd = true;
509 
510                        if (needsClientFiltering) {
511                                shouldAdd = false;
512 
513                                String procDb = proceduresRs.getString(1);
514 
515                                if (db == null && procDb == null) {
516                                        shouldAdd = true;
517                                } else if (db != null & db.equals(procDb)) {
518                                        shouldAdd = true;
519                                }
520                        }
521 
522                        if (shouldAdd) {
523                                String procedureName = proceduresRs.getString(nameIndex);
524                                byte[][] rowData = new byte[8][];
525                                rowData[0] = catalog == null ? null : s2b(catalog);
526                                rowData[1] = null;
527                                rowData[2] = s2b(procedureName);
528                                rowData[3] = null;
529                                rowData[4] = null;
530                                rowData[5] = null;
531                                rowData[6] = null;
532 
533                                boolean isFunction = fromSelect ? "FUNCTION"
534                                                .equalsIgnoreCase(proceduresRs.getString("type"))
535                                                : false;
536                                rowData[7] = s2b(isFunction ? Integer
537                                                .toString(procedureReturnsResult) : Integer
538                                                .toString(procedureResultUnknown));
539 
540                                procedureRowsOrderedByName.put(procedureName, rowData);
541                        }
542                }
543        }
544 
545        private byte[][] convertTypeDescriptorToProcedureRow(
546                        byte[] procNameAsBytes, String paramName, boolean isOutParam,
547                        boolean isInParam, boolean isReturnParam, TypeDescriptor typeDesc)
548                        throws SQLException {
549                byte[][] row = new byte[14][];
550                row[0] = null; // PROCEDURE_CAT
551                row[1] = null; // PROCEDURE_SCHEM
552                row[2] = procNameAsBytes; // PROCEDURE/NAME
553                row[3] = s2b(paramName); // COLUMN_NAME
554                // COLUMN_TYPE
555                if (isInParam && isOutParam) {
556                        row[4] = s2b(String.valueOf(procedureColumnInOut));
557                } else if (isInParam) {
558                        row[4] = s2b(String.valueOf(procedureColumnIn));
559                } else if (isOutParam) {
560                        row[4] = s2b(String.valueOf(procedureColumnOut));
561                } else if (isReturnParam) {
562                        row[4] = s2b(String.valueOf(procedureColumnReturn));
563                } else {
564                        row[4] = s2b(String.valueOf(procedureColumnUnknown));
565                }
566                row[5] = s2b(Short.toString(typeDesc.dataType)); // DATA_TYPE
567                row[6] = s2b(typeDesc.typeName); // TYPE_NAME
568                row[7] = s2b(Integer.toString(typeDesc.columnSize)); // PRECISION
569                row[8] = s2b(Integer.toString(typeDesc.bufferLength)); // LENGTH
570                row[9] = s2b(Integer.toString(typeDesc.decimalDigits)); // SCALE
571                row[10] = s2b(Integer.toString(typeDesc.numPrecRadix)); // RADIX
572                // Map 'column****' to 'procedure****'
573                switch (typeDesc.nullability) {
574                case columnNoNulls:
575                        row[11] = s2b(Integer.toString(procedureNoNulls)); // NULLABLE
576 
577                        break;
578 
579                case columnNullable:
580                        row[11] = s2b(Integer.toString(procedureNullable)); // NULLABLE
581 
582                        break;
583 
584                case columnNullableUnknown:
585                        row[11] = s2b(Integer.toString(procedureNullableUnknown)); // nullable
586 
587                        break;
588 
589                default:
590                        throw SQLError.createSQLException(
591                                        "Internal error while parsing callable statement metadata (unknown nullability value fount)",
592                                        SQLError.SQL_STATE_GENERAL_ERROR);
593                }
594                row[12] = null;
595                return row;
596        }
597 
598        /**
599         * Does a data definition statement within a transaction force the
600         * transaction to commit?
601         * 
602         * @return true if so
603         * @throws SQLException
604         *             DOCUMENT ME!
605         */
606        public boolean dataDefinitionCausesTransactionCommit() throws SQLException {
607                return true;
608        }
609 
610        /**
611         * Is a data definition statement within a transaction ignored?
612         * 
613         * @return true if so
614         * @throws SQLException
615         *             DOCUMENT ME!
616         */
617        public boolean dataDefinitionIgnoredInTransactions() throws SQLException {
618                return false;
619        }
620 
621        /**
622         * JDBC 2.0 Determine whether or not a visible row delete can be detected by
623         * calling ResultSet.rowDeleted(). If deletesAreDetected() returns false,
624         * then deleted rows are removed from the result set.
625         * 
626         * @param type
627         *            set type, i.e. ResultSet.TYPE_XXX
628         * @return true if changes are detected by the resultset type
629         * @exception SQLException
630         *                if a database-access error occurs.
631         */
632        public boolean deletesAreDetected(int type) throws SQLException {
633                return false;
634        }
635 
636        // ----------------------------------------------------------------------
637 
638        /**
639         * Did getMaxRowSize() include LONGVARCHAR and LONGVARBINARY blobs?
640         * 
641         * @return true if so
642         * @throws SQLException
643         *             DOCUMENT ME!
644         */
645        public boolean doesMaxRowSizeIncludeBlobs() throws SQLException {
646                return true;
647        }
648 
649        /**
650         * Extracts foreign key info for one table.
651         * 
652         * @param rows
653         *            the list of rows to add to
654         * @param rs
655         *            the result set from 'SHOW CREATE TABLE'
656         * @param catalog
657         *            the database name
658         * @return the list of rows with new rows added
659         * @throws SQLException
660         *             if a database access error occurs
661         */
662        public List extractForeignKeyForTable(ArrayList rows,
663                        java.sql.ResultSet rs, String catalog) throws SQLException {
664                byte[][] row = new byte[3][];
665                row[0] = rs.getBytes(1);
666                row[1] = s2b(SUPPORTS_FK);
667        
668                String createTableString = rs.getString(2);
669                StringTokenizer lineTokenizer = new StringTokenizer(createTableString,
670                                "\n");
671                StringBuffer commentBuf = new StringBuffer("comment; ");
672                boolean firstTime = true;
673        
674                String quoteChar = getIdentifierQuoteString();
675        
676                if (quoteChar == null) {
677                        quoteChar = "`";
678                }
679        
680                while (lineTokenizer.hasMoreTokens()) {
681                        String line = lineTokenizer.nextToken().trim();
682        
683                        String constraintName = null;
684        
685                        if (StringUtils.startsWithIgnoreCase(line, "CONSTRAINT")) {
686                                boolean usingBackTicks = true;
687                                int beginPos = line.indexOf(quoteChar);
688        
689                                if (beginPos == -1) {
690                                        beginPos = line.indexOf("\"");
691                                        usingBackTicks = false;
692                                }
693        
694                                if (beginPos != -1) {
695                                        int endPos = -1;
696        
697                                        if (usingBackTicks) {
698                                                endPos = line.indexOf(quoteChar, beginPos + 1);
699                                        } else {
700                                                endPos = line.indexOf("\"", beginPos + 1);
701                                        }
702        
703                                        if (endPos != -1) {
704                                                constraintName = line.substring(beginPos + 1, endPos);
705                                                line = line.substring(endPos + 1, line.length()).trim();
706                                        }
707                                }
708                        }
709        
710                        
711                        if (line.startsWith("FOREIGN KEY")) {
712                                if (line.endsWith(",")) {
713                                        line = line.substring(0, line.length() - 1);
714                                }
715        
716                                char quote = this.quotedId.charAt(0);
717                                
718                                int indexOfFK = line.indexOf("FOREIGN KEY");
719                                
720                                String localColumnName = null;
721                                String referencedCatalogName = this.quotedId + catalog + this.quotedId;
722                                String referencedTableName = null;
723                                String referencedColumnName = null;
724                                
725                                
726                                if (indexOfFK != -1) {
727                                        int afterFk = indexOfFK + "FOREIGN KEY".length();
728                                        
729                                        int indexOfRef = StringUtils.indexOfIgnoreCaseRespectQuotes(afterFk, line, "REFERENCES", quote, true);
730                                        
731                                        if (indexOfRef != -1) {
732                                                
733                                                int indexOfParenOpen = line.indexOf('(', afterFk);
734                                                int indexOfParenClose = StringUtils.indexOfIgnoreCaseRespectQuotes(indexOfParenOpen, line, ")", quote, true);
735                                                
736                                                if (indexOfParenOpen == -1 || indexOfParenClose == -1) {
737                                                        // throw SQLError.createSQLException();
738                                                }
739                                                
740                                                localColumnName = line.substring(indexOfParenOpen + 1, indexOfParenClose);
741                                                
742                                                int afterRef = indexOfRef + "REFERENCES".length();
743                                                
744                                                int referencedColumnBegin = StringUtils.indexOfIgnoreCaseRespectQuotes(afterRef, line, "(", quote, true);
745                                                
746                                                if (referencedColumnBegin != -1) {
747                                                        referencedTableName = line.substring(afterRef, referencedColumnBegin);
748        
749                                                        int referencedColumnEnd = StringUtils.indexOfIgnoreCaseRespectQuotes(referencedColumnBegin + 1, line, ")", quote, true);
750                                                        
751                                                        if (referencedColumnEnd != -1) {
752                                                                referencedColumnName = line.substring(referencedColumnBegin + 1, referencedColumnEnd);
753                                                        }
754                                                        
755                                                        int indexOfCatalogSep = StringUtils.indexOfIgnoreCaseRespectQuotes(0, referencedTableName, ".", quote, true);
756                                                        
757                                                        if (indexOfCatalogSep != -1) {
758                                                                referencedCatalogName = referencedTableName.substring(0, indexOfCatalogSep);
759                                                                referencedTableName = referencedTableName.substring(indexOfCatalogSep + 1);
760                                                        }
761                                                }
762                                        }
763                                }
764                                
765                                
766                                if (!firstTime) {
767                                        commentBuf.append("; ");
768                                } else {
769                                        firstTime = false;
770                                }
771        
772                                if (constraintName != null) {
773                                        commentBuf.append(constraintName);
774                                } else {
775                                        commentBuf.append("not_available");
776                                }
777        
778                                commentBuf.append("(");
779                                commentBuf.append(localColumnName);
780                                commentBuf.append(") REFER ");
781                                commentBuf.append(referencedCatalogName);
782                                commentBuf.append("/");
783                                commentBuf.append(referencedTableName);
784                                commentBuf.append("(");
785                                commentBuf.append(referencedColumnName);
786                                commentBuf.append(")");
787        
788                                int lastParenIndex = line.lastIndexOf(")");
789        
790                                if (lastParenIndex != (line.length() - 1)) {
791                                        String cascadeOptions = cascadeOptions = line
792                                                        .substring(lastParenIndex + 1);
793                                        commentBuf.append(" ");
794                                        commentBuf.append(cascadeOptions);
795                                }
796                        }
797                }
798        
799                row[2] = s2b(commentBuf.toString());
800                rows.add(row);
801        
802                return rows;
803        }
804 
805        /**
806         * Creates a result set similar enough to 'SHOW TABLE STATUS' to allow the
807         * same code to work on extracting the foreign key data
808         * 
809         * @param connToUse
810         *            the database connection to use
811         * @param metadata
812         *            the DatabaseMetaData instance calling this method
813         * @param catalog
814         *            the database name to extract foreign key info for
815         * @param tableName
816         *            the table to extract foreign key info for
817         * @return A result set that has the structure of 'show table status'
818         * @throws SQLException
819         *             if a database access error occurs.
820         */
821        public ResultSet extractForeignKeyFromCreateTable(String catalog,
822                        String tableName) throws SQLException {
823                ArrayList tableList = new ArrayList();
824                java.sql.ResultSet rs = null;
825                java.sql.Statement stmt = null;
826 
827                if (tableName != null) {
828                        tableList.add(tableName);
829                } else {
830                        try {
831                                rs = getTables(catalog, "", "%", new String[] { "TABLE" });
832 
833                                while (rs.next()) {
834                                        tableList.add(rs.getString("TABLE_NAME"));
835                                }
836                        } finally {
837                                if (rs != null) {
838                                        rs.close();
839                                }
840 
841                                rs = null;
842                        }
843                }
844 
845                ArrayList rows = new ArrayList();
846                Field[] fields = new Field[3];
847                fields[0] = new Field("", "Name", Types.CHAR, Integer.MAX_VALUE);
848                fields[1] = new Field("", "Type", Types.CHAR, 255);
849                fields[2] = new Field("", "Comment", Types.CHAR, Integer.MAX_VALUE);
850 
851                int numTables = tableList.size();
852                stmt = this.conn.getMetadataSafeStatement();
853 
854                String quoteChar = getIdentifierQuoteString();
855 
856                if (quoteChar == null) {
857                        quoteChar = "`";
858                }
859 
860                try {
861                        for (int i = 0; i < numTables; i++) {
862                                String tableToExtract = (String) tableList.get(i);
863 
864                                String query = new StringBuffer("SHOW CREATE TABLE ").append(
865                                                quoteChar).append(catalog).append(quoteChar)
866                                                .append(".").append(quoteChar).append(tableToExtract)
867                                                .append(quoteChar).toString();
868                                rs = stmt.executeQuery(query);
869 
870                                while (rs.next()) {
871                                        extractForeignKeyForTable(rows, rs, catalog);
872                                }
873                        }
874                } finally {
875                        if (rs != null) {
876                                rs.close();
877                        }
878 
879                        rs = null;
880 
881                        if (stmt != null) {
882                                stmt.close();
883                        }
884 
885                        stmt = null;
886                }
887 
888                return buildResultSet(fields, rows);
889        }
890 
891        /**
892         * @see DatabaseMetaData#getAttributes(String, String, String, String)
893         */
894        public java.sql.ResultSet getAttributes(String arg0, String arg1,
895                        String arg2, String arg3) throws SQLException {
896                Field[] fields = new Field[21];
897                fields[0] = new Field("", "TYPE_CAT", Types.CHAR, 32);
898                fields[1] = new Field("", "TYPE_SCHEM", Types.CHAR, 32);
899                fields[2] = new Field("", "TYPE_NAME", Types.CHAR, 32);
900                fields[3] = new Field("", "ATTR_NAME", Types.CHAR, 32);
901                fields[4] = new Field("", "DATA_TYPE", Types.SMALLINT, 32);
902                fields[5] = new Field("", "ATTR_TYPE_NAME", Types.CHAR, 32);
903                fields[6] = new Field("", "ATTR_SIZE", Types.INTEGER, 32);
904                fields[7] = new Field("", "DECIMAL_DIGITS", Types.INTEGER, 32);
905                fields[8] = new Field("", "NUM_PREC_RADIX", Types.INTEGER, 32);
906                fields[9] = new Field("", "NULLABLE ", Types.INTEGER, 32);
907                fields[10] = new Field("", "REMARKS", Types.CHAR, 32);
908                fields[11] = new Field("", "ATTR_DEF", Types.CHAR, 32);
909                fields[12] = new Field("", "SQL_DATA_TYPE", Types.INTEGER, 32);
910                fields[13] = new Field("", "SQL_DATETIME_SUB", Types.INTEGER, 32);
911                fields[14] = new Field("", "CHAR_OCTET_LENGTH", Types.INTEGER, 32);
912                fields[15] = new Field("", "ORDINAL_POSITION", Types.INTEGER, 32);
913                fields[16] = new Field("", "IS_NULLABLE", Types.CHAR, 32);
914                fields[17] = new Field("", "SCOPE_CATALOG", Types.CHAR, 32);
915                fields[18] = new Field("", "SCOPE_SCHEMA", Types.CHAR, 32);
916                fields[19] = new Field("", "SCOPE_TABLE", Types.CHAR, 32);
917                fields[20] = new Field("", "SOURCE_DATA_TYPE", Types.SMALLINT, 32);
918 
919                return buildResultSet(fields, new ArrayList());
920        }
921 
922        /**
923         * Get a description of a table's optimal set of columns that uniquely
924         * identifies a row. They are ordered by SCOPE.
925         * <P>
926         * Each column description has the following columns:
927         * <OL>
928         * <li> <B>SCOPE</B> short => actual scope of result
929         * <UL>
930         * <li> bestRowTemporary - very temporary, while using row </li>
931         * <li> bestRowTransaction - valid for remainder of current transaction
932         * </li>
933         * <li> bestRowSession - valid for remainder of current session </li>
934         * </ul>
935         * </li>
936         * <li> <B>COLUMN_NAME</B> String => column name </li>
937         * <li> <B>DATA_TYPE</B> short => SQL data type from java.sql.Types </li>
938         * <li> <B>TYPE_NAME</B> String => Data source dependent type name </li>
939         * <li> <B>COLUMN_SIZE</B> int => precision </li>
940         * <li> <B>BUFFER_LENGTH</B> int => not used </li>
941         * <li> <B>DECIMAL_DIGITS</B> short => scale </li>
942         * <li> <B>PSEUDO_COLUMN</B> short => is this a pseudo column like an
943         * Oracle ROWID
944         * <UL>
945         * <li> bestRowUnknown - may or may not be pseudo column </li>
946         * <li> bestRowNotPseudo - is NOT a pseudo column </li>
947         * <li> bestRowPseudo - is a pseudo column </li>
948         * </ul>
949         * </li>
950         * </ol>
951         * </p>
952         * 
953         * @param catalog
954         *            a catalog name; "" retrieves those without a catalog
955         * @param schema
956         *            a schema name; "" retrieves those without a schema
957         * @param table
958         *            a table name
959         * @param scope
960         *            the scope of interest; use same values as SCOPE
961         * @param nullable
962         *            include columns that are nullable?
963         * @return ResultSet each row is a column description
964         * @throws SQLException
965         *             DOCUMENT ME!
966         */
967        public java.sql.ResultSet getBestRowIdentifier(String catalog,
968                        String schema, final String table, int scope, boolean nullable)
969                        throws SQLException {
970                if (table == null) {
971                        throw SQLError.createSQLException("Table not specified.",
972                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
973                }
974 
975                Field[] fields = new Field[8];
976                fields[0] = new Field("", "SCOPE", Types.SMALLINT, 5);
977                fields[1] = new Field("", "COLUMN_NAME", Types.CHAR, 32);
978                fields[2] = new Field("", "DATA_TYPE", Types.SMALLINT, 32);
979                fields[3] = new Field("", "TYPE_NAME", Types.CHAR, 32);
980                fields[4] = new Field("", "COLUMN_SIZE", Types.INTEGER, 10);
981                fields[5] = new Field("", "BUFFER_LENGTH", Types.INTEGER, 10);
982                fields[6] = new Field("", "DECIMAL_DIGITS", Types.INTEGER, 10);
983                fields[7] = new Field("", "PSEUDO_COLUMN", Types.SMALLINT, 5);
984 
985                final ArrayList rows = new ArrayList();
986                final Statement stmt = this.conn.getMetadataSafeStatement();
987 
988                try {
989 
990                        new IterateBlock(getCatalogIterator(catalog)) {
991                                void forEach(Object catalogStr) throws SQLException {
992                                        ResultSet results = null;
993 
994                                        try {
995                                                StringBuffer queryBuf = new StringBuffer(
996                                                                "SHOW COLUMNS FROM ");
997                                                queryBuf.append(quotedId);
998                                                queryBuf.append(table);
999                                                queryBuf.append(quotedId);
1000                                                queryBuf.append(" FROM ");
1001                                                queryBuf.append(quotedId);
1002                                                queryBuf.append(catalogStr.toString());
1003                                                queryBuf.append(quotedId);
1004 
1005                                                results = stmt.executeQuery(queryBuf.toString());
1006 
1007                                                while (results.next()) {
1008                                                        String keyType = results.getString("Key");
1009 
1010                                                        if (keyType != null) {
1011                                                                if (StringUtils.startsWithIgnoreCase(keyType,
1012                                                                                "PRI")) {
1013                                                                        byte[][] rowVal = new byte[8][];
1014                                                                        rowVal[0] = Integer
1015                                                                                        .toString(
1016                                                                                                        java.sql.DatabaseMetaData.bestRowSession)
1017                                                                                        .getBytes();
1018                                                                        rowVal[1] = results.getBytes("Field");
1019 
1020                                                                        String type = results.getString("Type");
1021                                                                        int size = MysqlIO.getMaxBuf();
1022                                                                        int decimals = 0;
1023 
1024                                                                        /*
1025                                                                         * Parse the Type column from MySQL
1026                                                                         */
1027                                                                        if (type.indexOf("enum") != -1) {
1028                                                                                String temp = type.substring(type
1029                                                                                                .indexOf("("), type
1030                                                                                                .indexOf(")"));
1031                                                                                java.util.StringTokenizer tokenizer = new java.util.StringTokenizer(
1032                                                                                                temp, ",");
1033                                                                                int maxLength = 0;
1034 
1035                                                                                while (tokenizer.hasMoreTokens()) {
1036                                                                                        maxLength = Math.max(maxLength,
1037                                                                                                        (tokenizer.nextToken()
1038                                                                                                                        .length() - 2));
1039                                                                                }
1040 
1041                                                                                size = maxLength;
1042                                                                                decimals = 0;
1043                                                                                type = "enum";
1044                                                                        } else if (type.indexOf("(") != -1) {
1045                                                                                if (type.indexOf(",") != -1) {
1046                                                                                        size = Integer.parseInt(type
1047                                                                                                        .substring(type
1048                                                                                                                        .indexOf("(") + 1,
1049                                                                                                                        type.indexOf(",")));
1050                                                                                        decimals = Integer.parseInt(type
1051                                                                                                        .substring(type
1052                                                                                                                        .indexOf(",") + 1,
1053                                                                                                                        type.indexOf(")")));
1054                                                                                } else {
1055                                                                                        size = Integer.parseInt(type
1056                                                                                                        .substring(type
1057                                                                                                                        .indexOf("(") + 1,
1058                                                                                                                        type.indexOf(")")));
1059                                                                                }
1060 
1061                                                                                type = type.substring(0, type
1062                                                                                                .indexOf("("));
1063                                                                        }
1064 
1065                                                                        rowVal[2] = s2b(String.valueOf(MysqlDefs
1066                                                                                        .mysqlToJavaType(type)));
1067                                                                        rowVal[3] = s2b(type);
1068                                                                        rowVal[4] = Integer.toString(
1069                                                                                        size + decimals).getBytes();
1070                                                                        rowVal[5] = Integer.toString(
1071                                                                                        size + decimals).getBytes();
1072                                                                        rowVal[6] = Integer.toString(decimals)
1073                                                                                        .getBytes();
1074                                                                        rowVal[7] = Integer
1075                                                                                        .toString(
1076                                                                                                        java.sql.DatabaseMetaData.bestRowNotPseudo)
1077                                                                                        .getBytes();
1078 
1079                                                                        rows.add(rowVal);
1080                                                                }
1081                                                        }
1082                                                }
1083 
1084                                        } finally {
1085                                                if (results != null) {
1086                                                        try {
1087                                                                results.close();
1088                                                        } catch (Exception ex) {
1089                                                                ;
1090                                                        }
1091 
1092                                                        results = null;
1093                                                }
1094                                        }
1095                                }
1096                        }.doForAll();
1097                } finally {
1098                        if (stmt != null) {
1099                                stmt.close();
1100                        }
1101                }
1102 
1103                java.sql.ResultSet results = buildResultSet(fields, rows);
1104 
1105                return results;
1106 
1107        }
1108 
1109        /*
1110         * * Each row in the ResultSet is a parameter desription or column
1111         * description with the following fields: <OL> <li> <B>PROCEDURE_CAT</B>
1112         * String => procedure catalog (may be null) </li> <li> <B>PROCEDURE_SCHEM</B>
1113         * String => procedure schema (may be null) </li> <li> <B>PROCEDURE_NAME</B>
1114         * String => procedure name </li> <li> <B>COLUMN_NAME</B> String =>
1115         * column/parameter name </li> <li> <B>COLUMN_TYPE</B> Short => kind of
1116         * column/parameter: <UL> <li> procedureColumnUnknown - nobody knows </li>
1117         * <li> procedureColumnIn - IN parameter </li> <li> procedureColumnInOut -
1118         * INOUT parameter </li> <li> procedureColumnOut - OUT parameter </li> <li>
1119         * procedureColumnReturn - procedure return value </li> <li>
1120         * procedureColumnResult - result column in ResultSet </li> </ul> </li> <li>
1121         * <B>DATA_TYPE</B> short => SQL type from java.sql.Types </li> <li>
1122         * <B>TYPE_NAME</B> String => SQL type name </li> <li> <B>PRECISION</B>
1123         * int => precision </li> <li> <B>LENGTH</B> int => length in bytes of data
1124         * </li> <li> <B>SCALE</B> short => scale </li> <li> <B>RADIX</B> short =>
1125         * radix </li> <li> <B>NULLABLE</B> short => can it contain NULL? <UL> <li>
1126         * procedureNoNulls - does not allow NULL values </li> <li>
1127         * procedureNullable - allows NULL values </li> <li>
1128         * procedureNullableUnknown - nullability unknown </li> </ul> </li> <li>
1129         * <B>REMARKS</B> String => comment describing parameter/column </li> </ol>
1130         * </p> <P> <B>Note:</B> Some databases may not return the column
1131         * descriptions for a procedure. Additional columns beyond REMARKS can be
1132         * defined by the database. </p> @param catalog a catalog name; "" retrieves
1133         * those without a catalog @param schemaPattern a schema name pattern; ""
1134         * retrieves those without a schema @param procedureNamePattern a procedure
1135         * name pattern @param columnNamePattern a column name pattern @return
1136         * ResultSet each row is a stored procedure parameter or column description
1137         * @throws SQLException if a database access error occurs
1138         * 
1139         * @see #getSearchStringEscape
1140         */
1141        private void getCallStmtParameterTypes(String catalog, String procName,
1142                        String parameterNamePattern, List resultRows) throws SQLException {
1143                java.sql.Statement paramRetrievalStmt = null;
1144                java.sql.ResultSet paramRetrievalRs = null;
1145 
1146                if (parameterNamePattern == null) {
1147                        if (this.conn.getNullNamePatternMatchesAll()) {
1148                                parameterNamePattern = "%";
1149                        } else {
1150                                throw SQLError.createSQLException(
1151                                                "Parameter/Column name pattern can not be NULL or empty.",
1152                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
1153                        }
1154                }
1155 
1156                byte[] procNameAsBytes = null;
1157 
1158                try {
1159                        procNameAsBytes = procName.getBytes("UTF-8");
1160                } catch (UnsupportedEncodingException ueEx) {
1161                        procNameAsBytes = s2b(procName);
1162 
1163                        // Set all fields to connection encoding
1164                }
1165 
1166                String quoteChar = getIdentifierQuoteString();
1167 
1168                String storageDefnDelims = "(" + quoteChar;
1169                String storageDefnClosures = ")" + quoteChar;
1170 
1171                // First try 'select from mysql.proc, as this is easier to parse...
1172                String parameterDef = null;
1173                
1174                PreparedStatement paramRetrievalPreparedStatement = null;
1175                
1176                try {
1177                        paramRetrievalStmt = this.conn.getMetadataSafeStatement();
1178                        
1179                        if (this.conn.lowerCaseTableNames() && catalog != null 
1180                                        && catalog.length() != 0) {
1181                                // Workaround for bug in server wrt. to 
1182                                // SHOW CREATE PROCEDURE not respecting
1183                                // lower-case table names
1184                                
1185                                String oldCatalog = this.conn.getCatalog();
1186                                ResultSet rs = null;
1187                                
1188                                try {
1189                                        this.conn.setCatalog(catalog);
1190                                        rs = paramRetrievalStmt.executeQuery("SELECT DATABASE()");
1191                                        rs.next();
1192                                        
1193                                        catalog = rs.getString(1);
1194                                        
1195                                } finally {
1196                                        
1197                                        this.conn.setCatalog(oldCatalog);
1198                                        
1199                                        if (rs != null) {
1200                                                rs.close();
1201                                        }
1202                                }
1203                        }
1204                        
1205                        if (paramRetrievalStmt.getMaxRows() != 0) {
1206                                paramRetrievalStmt.setMaxRows(0);
1207                        }
1208 
1209                        int dotIndex = -1;
1210 
1211                        if (!" ".equals(quoteChar)) {
1212                                dotIndex = StringUtils.indexOfIgnoreCaseRespectQuotes(0,
1213                                                procName, ".", quoteChar.charAt(0), !this.conn
1214                                                                .isNoBackslashEscapesSet());
1215                        } else {
1216                                dotIndex = procName.indexOf(".");
1217                        }
1218 
1219                        String dbName = null;
1220 
1221                        if (dotIndex != -1 && (dotIndex + 1) < procName.length()) {
1222                                dbName = procName.substring(0, dotIndex);
1223                                procName = procName.substring(dotIndex + 1);
1224                        } else {
1225                                dbName = catalog;
1226                        }
1227 
1228                        StringBuffer procNameBuf = new StringBuffer();
1229 
1230                        if (dbName != null) {
1231                                if (!" ".equals(quoteChar) && !dbName.startsWith(quoteChar)) {
1232                                        procNameBuf.append(quoteChar);
1233                                }
1234 
1235                                procNameBuf.append(dbName);
1236 
1237                                if (!" ".equals(quoteChar) && !dbName.startsWith(quoteChar)) {
1238                                        procNameBuf.append(quoteChar);
1239                                }
1240 
1241                                procNameBuf.append(".");
1242                        }
1243 
1244                        boolean procNameIsNotQuoted = !procName.startsWith(quoteChar);
1245 
1246                        if (!" ".equals(quoteChar) && procNameIsNotQuoted) {
1247                                procNameBuf.append(quoteChar);
1248                        }
1249 
1250                        procNameBuf.append(procName);
1251 
1252                        if (!" ".equals(quoteChar) && procNameIsNotQuoted) {
1253                                procNameBuf.append(quoteChar);
1254                        }
1255 
1256                        boolean parsingFunction = false;
1257 
1258                        try {
1259                                paramRetrievalRs = paramRetrievalStmt
1260                                                .executeQuery("SHOW CREATE PROCEDURE "
1261                                                                + procNameBuf.toString());
1262                                parsingFunction = false;
1263                        } catch (SQLException sqlEx) {
1264                                paramRetrievalRs = paramRetrievalStmt
1265                                                .executeQuery("SHOW CREATE FUNCTION "
1266                                                                + procNameBuf.toString());
1267                                parsingFunction = true;
1268                        }
1269 
1270                        if (paramRetrievalRs.next()) {
1271                                String procedureDef = parsingFunction ? paramRetrievalRs
1272                                                .getString("Create Function") : paramRetrievalRs
1273                                                .getString("Create Procedure");
1274 
1275                                int openParenIndex = StringUtils
1276                                                .indexOfIgnoreCaseRespectQuotes(0, procedureDef, "(",
1277                                                                quoteChar.charAt(0), !this.conn
1278                                                                                .isNoBackslashEscapesSet());
1279 
1280                                String beforeBegin = null;
1281 
1282                                // Try and fudge this with the 'begin' statement
1283                                int beginIndex = 0;
1284 
1285                                if (!parsingFunction) {
1286                                        beginIndex = StringUtils.indexOfIgnoreCaseRespectQuotes(0,
1287                                                        procedureDef, "\nbegin", quoteChar.charAt(0),
1288                                                        !this.conn.isNoBackslashEscapesSet());
1289                                } else {
1290                                        // Grab the return column first, since it needs
1291                                        // to go first in the output result set
1292                                        int returnsIndex = StringUtils
1293                                                        .indexOfIgnoreCaseRespectQuotes(0, procedureDef,
1294                                                                        " RETURNS ", quoteChar.charAt(0),
1295                                                                        !this.conn.isNoBackslashEscapesSet());
1296 
1297                                        beginIndex = StringUtils.indexOfIgnoreCaseRespectQuotes(
1298                                                        returnsIndex, procedureDef, "\nbegin", quoteChar
1299                                                                        .charAt(0), !this.conn
1300                                                                        .isNoBackslashEscapesSet());
1301 
1302                                        if (beginIndex == -1) {
1303                                                beginIndex = StringUtils
1304                                                                .indexOfIgnoreCaseRespectQuotes(0,
1305                                                                                procedureDef, "\n",
1306                                                                                quoteChar.charAt(0), !this.conn
1307                                                                                                .isNoBackslashEscapesSet());
1308                                        }
1309 
1310                                        // Okay, give up...
1311 
1312                                        if (beginIndex == -1) {
1313                                                throw SQLError.createSQLException(
1314                                                                "Driver requires declaration of procedure to either contain a '\\nbegin' or '\\n' to follow argument declaration, or SELECT privilege on mysql.proc to parse column types.",
1315                                                                SQLError.SQL_STATE_GENERAL_ERROR);
1316                                        }
1317 
1318                                        String returnsDefn = procedureDef.substring(returnsIndex
1319                                                        + "RETURNS ".length(), beginIndex);
1320                                        TypeDescriptor returnDescriptor = new TypeDescriptor(
1321                                                        returnsDefn, null);
1322 
1323                                        resultRows.add(convertTypeDescriptorToProcedureRow(
1324                                                        procNameAsBytes, "", false, false, true,
1325                                                        returnDescriptor));
1326 
1327                                        beginIndex = returnsIndex; // further processing needs to
1328                                        // look before "RETURNS" token
1329                                }
1330 
1331                                // Bah, we _really_ need information schema here
1332 
1333                                if (beginIndex != -1) {
1334                                        beforeBegin = procedureDef.substring(0, beginIndex);
1335                                } else {
1336                                        beginIndex = StringUtils.indexOfIgnoreCaseRespectQuotes(0,
1337                                                        procedureDef, "\n", quoteChar.charAt(0), !this.conn
1338                                                                        .isNoBackslashEscapesSet());
1339 
1340                                        if (beginIndex != -1) {
1341                                                beforeBegin = procedureDef.substring(0, beginIndex);
1342                                        } else {
1343                                                throw SQLError.createSQLException(
1344                                                                "Driver requires declaration of procedure to either contain a '\\nbegin' or '\\n' to follow argument declaration, or SELECT privilege on mysql.proc to parse column types.",
1345                                                                SQLError.SQL_STATE_GENERAL_ERROR);
1346                                        }
1347 
1348                                }
1349 
1350                                int endParenIndex = beforeBegin.lastIndexOf(')');
1351 
1352                                if ((openParenIndex == -1) || (endParenIndex == -1)) {
1353                                        // parse error?
1354                                        throw SQLError.createSQLException(
1355                                                        "Internal error when parsing callable statement metadata",
1356                                                        SQLError.SQL_STATE_GENERAL_ERROR);
1357                                }
1358 
1359                                parameterDef = procedureDef.substring(openParenIndex + 1,
1360                                                endParenIndex);
1361                        }
1362                } finally {
1363                        SQLException sqlExRethrow = null;
1364 
1365                        if (paramRetrievalRs != null) {
1366                                try {
1367                                        paramRetrievalRs.close();
1368                                } catch (SQLException sqlEx) {
1369                                        sqlExRethrow = sqlEx;
1370                                }
1371 
1372                                paramRetrievalRs = null;
1373                        }
1374 
1375                        if (paramRetrievalPreparedStatement != null) {
1376                                try {
1377                                        paramRetrievalPreparedStatement.close();
1378                                } catch (SQLException sqlEx) {
1379                                        sqlExRethrow = sqlEx;
1380                                }
1381 
1382                                paramRetrievalPreparedStatement = null;
1383                        }
1384 
1385                        if (paramRetrievalStmt != null) {
1386                                try {
1387                                        paramRetrievalStmt.close();
1388                                } catch (SQLException sqlEx) {
1389                                        sqlExRethrow = sqlEx;
1390                                }
1391 
1392                                paramRetrievalStmt = null;
1393                        }
1394 
1395                        if (sqlExRethrow != null) {
1396                                throw sqlExRethrow;
1397                        }
1398                }
1399 
1400                if (parameterDef != null) {
1401                        List parseList = StringUtils.split(parameterDef, ",",
1402                                        storageDefnDelims, storageDefnClosures, true);
1403 
1404                        int parseListLen = parseList.size();
1405 
1406                        for (int i = 0; i < parseListLen; i++) {
1407                                String declaration = (String) parseList.get(i);
1408 
1409                                StringTokenizer declarationTok = new StringTokenizer(
1410                                                declaration, " \t");
1411 
1412                                String paramName = null;
1413                                boolean isOutParam = false;
1414                                boolean isInParam = false;
1415 
1416                                if (declarationTok.hasMoreTokens()) {
1417                                        String possibleParamName = declarationTok.nextToken();
1418 
1419                                        if (possibleParamName.equalsIgnoreCase("OUT")) {
1420                                                isOutParam = true;
1421 
1422                                                if (declarationTok.hasMoreTokens()) {
1423                                                        paramName = declarationTok.nextToken();
1424                                                } else {
1425                                                        throw SQLError.createSQLException(
1426                                                                        "Internal error when parsing callable statement metadata (missing parameter name)",
1427                                                                        SQLError.SQL_STATE_GENERAL_ERROR);
1428                                                }
1429                                        } else if (possibleParamName.equalsIgnoreCase("INOUT")) {
1430                                                isOutParam = true;
1431                                                isInParam = true;
1432 
1433                                                if (declarationTok.hasMoreTokens()) {
1434                                                        paramName = declarationTok.nextToken();
1435                                                } else {
1436                                                        throw SQLError.createSQLException(
1437                                                                        "Internal error when parsing callable statement metadata (missing parameter name)",
1438                                                                        SQLError.SQL_STATE_GENERAL_ERROR);
1439                                                }
1440                                        } else if (possibleParamName.equalsIgnoreCase("IN")) {
1441                                                isOutParam = false;
1442                                                isInParam = true;
1443 
1444                                                if (declarationTok.hasMoreTokens()) {
1445                                                        paramName = declarationTok.nextToken();
1446                                                } else {
1447                                                        throw SQLError.createSQLException(
1448                                                                        "Internal error when parsing callable statement metadata (missing parameter name)",
1449                                                                        SQLError.SQL_STATE_GENERAL_ERROR);
1450                                                }
1451                                        } else {
1452                                                isOutParam = false;
1453                                                isInParam = true;
1454 
1455                                                paramName = possibleParamName;
1456                                        }
1457 
1458                                        TypeDescriptor typeDesc = null;
1459 
1460                                        if (declarationTok.hasMoreTokens()) {
1461                                                StringBuffer typeInfoBuf = new StringBuffer(
1462                                                                declarationTok.nextToken());
1463 
1464                                                while (declarationTok.hasMoreTokens()) {
1465                                                        typeInfoBuf.append(" ");
1466                                                        typeInfoBuf.append(declarationTok.nextToken());
1467                                                }
1468 
1469                                                String typeInfo = typeInfoBuf.toString();
1470 
1471                                                typeDesc = new TypeDescriptor(typeInfo, null);
1472                                        } else {
1473                                                throw SQLError.createSQLException(
1474                                                                "Internal error when parsing callable statement metadata (missing parameter type)",
1475                                                                SQLError.SQL_STATE_GENERAL_ERROR);
1476                                        }
1477 
1478                                        int wildCompareRes = StringUtils.wildCompare(paramName,
1479                                                        parameterNamePattern);
1480 
1481                                        if (wildCompareRes != StringUtils.WILD_COMPARE_NO_MATCH) {
1482                                                byte[][] row = convertTypeDescriptorToProcedureRow(
1483                                                                procNameAsBytes, paramName, isOutParam,
1484                                                                isInParam, false, typeDesc);
1485 
1486                                                resultRows.add(row);
1487                                        }
1488                                } else {
1489                                        throw SQLError.createSQLException(
1490                                                        "Internal error when parsing callable statement metadata (unknown output from 'SHOW CREATE PROCEDURE')",
1491                                                        SQLError.SQL_STATE_GENERAL_ERROR);
1492                                }
1493                        }
1494                } else {
1495                        // Is this an error? JDBC spec doesn't make it clear if stored
1496                        // procedure doesn't
1497                        // exist, is it an error....
1498                }
1499        }
1500 
1501        /**
1502         * Parses the cascade option string and returns the DBMD constant that
1503         * represents it (for deletes)
1504         * 
1505         * @param cascadeOptions
1506         *            the comment from 'SHOW TABLE STATUS'
1507         * @return the DBMD constant that represents the cascade option
1508         */
1509        private int getCascadeDeleteOption(String cascadeOptions) {
1510                int onDeletePos = cascadeOptions.indexOf("ON DELETE");
1511 
1512                if (onDeletePos != -1) {
1513                        String deleteOptions = cascadeOptions.substring(onDeletePos,
1514                                        cascadeOptions.length());
1515 
1516                        if (deleteOptions.startsWith("ON DELETE CASCADE")) {
1517                                return java.sql.DatabaseMetaData.importedKeyCascade;
1518                        } else if (deleteOptions.startsWith("ON DELETE SET NULL")) {
1519                                return java.sql.DatabaseMetaData.importedKeySetNull;
1520                        } else if (deleteOptions.startsWith("ON DELETE RESTRICT")) {
1521                                return java.sql.DatabaseMetaData.importedKeyRestrict;
1522                        } else if (deleteOptions.startsWith("ON DELETE NO ACTION")) {
1523                                return java.sql.DatabaseMetaData.importedKeyNoAction;
1524                        }
1525                }
1526 
1527                return java.sql.DatabaseMetaData.importedKeyNoAction;
1528        }
1529 
1530        /**
1531         * Parses the cascade option string and returns the DBMD constant that
1532         * represents it (for Updates)
1533         * 
1534         * @param cascadeOptions
1535         *            the comment from 'SHOW TABLE STATUS'
1536         * @return the DBMD constant that represents the cascade option
1537         */
1538        private int getCascadeUpdateOption(String cascadeOptions) {
1539                int onUpdatePos = cascadeOptions.indexOf("ON UPDATE");
1540 
1541                if (onUpdatePos != -1) {
1542                        String updateOptions = cascadeOptions.substring(onUpdatePos,
1543                                        cascadeOptions.length());
1544 
1545                        if (updateOptions.startsWith("ON UPDATE CASCADE")) {
1546                                return java.sql.DatabaseMetaData.importedKeyCascade;
1547                        } else if (updateOptions.startsWith("ON UPDATE SET NULL")) {
1548                                return java.sql.DatabaseMetaData.importedKeySetNull;
1549                        } else if (updateOptions.startsWith("ON UPDATE RESTRICT")) {
1550                                return java.sql.DatabaseMetaData.importedKeyRestrict;
1551                        } else if (updateOptions.startsWith("ON UPDATE NO ACTION")) {
1552                                return java.sql.DatabaseMetaData.importedKeyNoAction;
1553                        }
1554                }
1555 
1556                return java.sql.DatabaseMetaData.importedKeyNoAction;
1557        }
1558 
1559        protected IteratorWithCleanup getCatalogIterator(String catalogSpec)
1560                        throws SQLException {
1561                IteratorWithCleanup allCatalogsIter;
1562                if (catalogSpec != null) {
1563                        if (!catalogSpec.equals("")) {
1564                                allCatalogsIter = new SingleStringIterator(catalogSpec);
1565                        } else {
1566                                // legacy mode of operation
1567                                allCatalogsIter = new SingleStringIterator(this.database);
1568                        }
1569                } else if (this.conn.getNullCatalogMeansCurrent()) {
1570                        allCatalogsIter = new SingleStringIterator(this.database);
1571                } else {
1572                        allCatalogsIter = new ResultSetIterator(getCatalogs(), 1);
1573                }
1574 
1575                return allCatalogsIter;
1576        }
1577 
1578        /**
1579         * Get the catalog names available in this database. The results are ordered
1580         * by catalog name.
1581         * <P>
1582         * The catalog column is:
1583         * <OL>
1584         * <li> <B>TABLE_CAT</B> String => catalog name </li>
1585         * </ol>
1586         * </p>
1587         * 
1588         * @return ResultSet each row has a single String column that is a catalog
1589         *         name
1590         * @throws SQLException
1591         *             DOCUMENT ME!
1592         */
1593        public java.sql.ResultSet getCatalogs() throws SQLException {
1594                java.sql.ResultSet results = null;
1595                java.sql.Statement stmt = null;
1596 
1597                try {
1598                        stmt = this.conn.createStatement();
1599                        stmt.setEscapeProcessing(false);
1600                        results = stmt.executeQuery("SHOW DATABASES");
1601 
1602                        java.sql.ResultSetMetaData resultsMD = results.getMetaData();
1603                        Field[] fields = new Field[1];
1604                        fields[0] = new Field("", "TABLE_CAT", Types.VARCHAR, resultsMD
1605                                        .getColumnDisplaySize(1));
1606 
1607                        ArrayList tuples = new ArrayList();
1608 
1609                        while (results.next()) {
1610                                byte[][] rowVal = new byte[1][];
1611                                rowVal[0] = results.getBytes(1);
1612                                tuples.add(rowVal);
1613                        }
1614 
1615                        return buildResultSet(fields, tuples);
1616                } finally {
1617                        if (results != null) {
1618                                try {
1619                                        results.close();
1620                                } catch (SQLException sqlEx) {
1621                                        AssertionFailedException.shouldNotHappen(sqlEx);
1622                                }
1623 
1624                                results = null;
1625                        }
1626 
1627                        if (stmt != null) {
1628                                try {
1629                                        stmt.close();
1630                                } catch (SQLException sqlEx) {
1631                                        AssertionFailedException.shouldNotHappen(sqlEx);
1632                                }
1633 
1634                                stmt = null;
1635                        }
1636                }
1637        }
1638 
1639        /**
1640         * What's the separator between catalog and table name?
1641         * 
1642         * @return the separator string
1643         * @throws SQLException
1644         *             DOCUMENT ME!
1645         */
1646        public String getCatalogSeparator() throws SQLException {
1647                return ".";
1648        }
1649 
1650        // ----------------------------------------------------------------------
1651        // The following group of methods exposes various limitations
1652        // based on the target database with the current driver.
1653        // Unless otherwise specified, a result of zero means there is no
1654        // limit, or the limit is not known.
1655 
1656        /**
1657         * What's the database vendor's preferred term for "catalog"?
1658         * 
1659         * @return the vendor term
1660         * @throws SQLException
1661         *             DOCUMENT ME!
1662         */
1663        public String getCatalogTerm() throws SQLException {
1664                return "database";
1665        }
1666 
1667        /**
1668         * Get a description of the access rights for a table's columns.
1669         * <P>
1670         * Only privileges matching the column name criteria are returned. They are
1671         * ordered by COLUMN_NAME and PRIVILEGE.
1672         * </p>
1673         * <P>
1674         * Each privilige description has the following columns:
1675         * <OL>
1676         * <li> <B>TABLE_CAT</B> String => table catalog (may be null) </li>
1677         * <li> <B>TABLE_SCHEM</B> String => table schema (may be null) </li>
1678         * <li> <B>TABLE_NAME</B> String => table name </li>
1679         * <li> <B>COLUMN_NAME</B> String => column name </li>
1680         * <li> <B>GRANTOR</B> => grantor of access (may be null) </li>
1681         * <li> <B>GRANTEE</B> String => grantee of access </li>
1682         * <li> <B>PRIVILEGE</B> String => name of access (SELECT, INSERT, UPDATE,
1683         * REFRENCES, ...) </li>
1684         * <li> <B>IS_GRANTABLE</B> String => "YES" if grantee is permitted to
1685         * grant to others; "NO" if not; null if unknown </li>
1686         * </ol>
1687         * </p>
1688         * 
1689         * @param catalog
1690         *            a catalog name; "" retrieves those without a catalog
1691         * @param schema
1692         *            a schema name; "" retrieves those without a schema
1693         * @param table
1694         *            a table name
1695         * @param columnNamePattern
1696         *            a column name pattern
1697         * @return ResultSet each row is a column privilege description
1698         * @throws SQLException
1699         *             if a database access error occurs
1700         * @see #getSearchStringEscape
1701         */
1702        public java.sql.ResultSet getColumnPrivileges(String catalog,
1703                        String schema, String table, String columnNamePattern)
1704                        throws SQLException {
1705                Field[] fields = new Field[8];
1706                fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 64);
1707                fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 1);
1708                fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 64);
1709                fields[3] = new Field("", "COLUMN_NAME", Types.CHAR, 64);
1710                fields[4] = new Field("", "GRANTOR", Types.CHAR, 77);
1711                fields[5] = new Field("", "GRANTEE", Types.CHAR, 77);
1712                fields[6] = new Field("", "PRIVILEGE", Types.CHAR, 64);
1713                fields[7] = new Field("", "IS_GRANTABLE", Types.CHAR, 3);
1714 
1715                StringBuffer grantQuery = new StringBuffer(
1716                                "SELECT c.host, c.db, t.grantor, c.user, "
1717                                                + "c.table_name, c.column_name, c.column_priv "
1718                                                + "from mysql.columns_priv c, mysql.tables_priv t "
1719                                                + "where c.host = t.host and c.db = t.db and "
1720                                                + "c.table_name = t.table_name ");
1721 
1722                if ((catalog != null) && (catalog.length() != 0)) {
1723                        grantQuery.append(" AND c.db='");
1724                        grantQuery.append(catalog);
1725                        grantQuery.append("' ");
1726                        ;
1727                }
1728 
1729                grantQuery.append(" AND c.table_name ='");
1730                grantQuery.append(table);
1731                grantQuery.append("' AND c.column_name like '");
1732                grantQuery.append(columnNamePattern);
1733                grantQuery.append("'");
1734 
1735                Statement stmt = null;
1736                ResultSet results = null;
1737                ArrayList grantRows = new ArrayList();
1738 
1739                try {
1740                        stmt = this.conn.createStatement();
1741                        stmt.setEscapeProcessing(false);
1742                        results = stmt.executeQuery(grantQuery.toString());
1743 
1744                        while (results.next()) {
1745                                String host = results.getString(1);
1746                                String db = results.getString(2);
1747                                String grantor = results.getString(3);
1748                                String user = results.getString(4);
1749 
1750                                if ((user == null) || (user.length() == 0)) {
1751                                        user = "%";
1752                                }
1753 
1754                                StringBuffer fullUser = new StringBuffer(user);
1755 
1756                                if ((host != null) && this.conn.getUseHostsInPrivileges()) {
1757                                        fullUser.append("@");
1758                                        fullUser.append(host);
1759                                }
1760 
1761                                String columnName = results.getString(6);
1762                                String allPrivileges = results.getString(7);
1763 
1764                                if (allPrivileges != null) {
1765                                        allPrivileges = allPrivileges.toUpperCase(Locale.ENGLISH);
1766 
1767                                        StringTokenizer st = new StringTokenizer(allPrivileges, ",");
1768 
1769                                        while (st.hasMoreTokens()) {
1770                                                String privilege = st.nextToken().trim();
1771                                                byte[][] tuple = new byte[8][];
1772                                                tuple[0] = s2b(db);
1773                                                tuple[1] = null;
1774                                                tuple[2] = s2b(table);
1775                                                tuple[3] = s2b(columnName);
1776 
1777                                                if (grantor != null) {
1778                                                        tuple[4] = s2b(grantor);
1779                                                } else {
1780                                                        tuple[4] = null;
1781                                                }
1782 
1783                                                tuple[5] = s2b(fullUser.toString());
1784                                                tuple[6] = s2b(privilege);
1785                                                tuple[7] = null;
1786                                                grantRows.add(tuple);
1787                                        }
1788                                }
1789                        }
1790                } finally {
1791                        if (results != null) {
1792                                try {
1793                                        results.close();
1794                                } catch (Exception ex) {
1795                                        ;
1796                                }
1797 
1798                                results = null;
1799                        }
1800 
1801                        if (stmt != null) {
1802                                try {
1803                                        stmt.close();
1804                                } catch (Exception ex) {
1805                                        ;
1806                                }
1807 
1808                                stmt = null;
1809                        }
1810                }
1811 
1812                return buildResultSet(fields, grantRows);
1813        }
1814 
1815        /**
1816         * Get a description of table columns available in a catalog.
1817         * <P>
1818         * Only column descriptions matching the catalog, schema, table and column
1819         * name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME
1820         * and ORDINAL_POSITION.
1821         * </p>
1822         * <P>
1823         * Each column description has the following columns:
1824         * <OL>
1825         * <li> <B>TABLE_CAT</B> String => table catalog (may be null) </li>
1826         * <li> <B>TABLE_SCHEM</B> String => table schema (may be null) </li>
1827         * <li> <B>TABLE_NAME</B> String => table name </li>
1828         * <li> <B>COLUMN_NAME</B> String => column name </li>
1829         * <li> <B>DATA_TYPE</B> short => SQL type from java.sql.Types </li>
1830         * <li> <B>TYPE_NAME</B> String => Data source dependent type name </li>
1831         * <li> <B>COLUMN_SIZE</B> int => column size. For char or date types this
1832         * is the maximum number of characters, for numeric or decimal types this is
1833         * precision. </li>
1834         * <li> <B>BUFFER_LENGTH</B> is not used. </li>
1835         * <li> <B>DECIMAL_DIGITS</B> int => the number of fractional digits </li>
1836         * <li> <B>NUM_PREC_RADIX</B> int => Radix (typically either 10 or 2) </li>
1837         * <li> <B>NULLABLE</B> int => is NULL allowed?
1838         * <UL>
1839         * <li> columnNoNulls - might not allow NULL values </li>
1840         * <li> columnNullable - definitely allows NULL values </li>
1841         * <li> columnNullableUnknown - nullability unknown </li>
1842         * </ul>
1843         * </li>
1844         * <li> <B>REMARKS</B> String => comment describing column (may be null)
1845         * </li>
1846         * <li> <B>COLUMN_DEF</B> String => default value (may be null) </li>
1847         * <li> <B>SQL_DATA_TYPE</B> int => unused </li>
1848         * <li> <B>SQL_DATETIME_SUB</B> int => unused </li>
1849         * <li> <B>CHAR_OCTET_LENGTH</B> int => for char types the maximum number
1850         * of bytes in the column </li>
1851         * <li> <B>ORDINAL_POSITION</B> int => index of column in table (starting
1852         * at 1) </li>
1853         * <li> <B>IS_NULLABLE</B> String => "NO" means column definitely does not
1854         * allow NULL values; "YES" means the column might allow NULL values. An
1855         * empty string means nobody knows. </li>
1856         * </ol>
1857         * </p>
1858         * 
1859         * @param catalog
1860         *            a catalog name; "" retrieves those without a catalog
1861         * @param schemaPattern
1862         *            a schema name pattern; "" retrieves those without a schema
1863         * @param tableNamePattern
1864         *            a table name pattern
1865         * @param columnNamePattern
1866         *            a column name pattern
1867         * @return ResultSet each row is a column description
1868         * @throws SQLException
1869         *             if a database access error occurs
1870         * @see #getSearchStringEscape
1871         */
1872        public java.sql.ResultSet getColumns(final String catalog,
1873                        final String schemaPattern, final String tableNamePattern,
1874                        String columnNamePattern) throws SQLException {
1875 
1876                if (columnNamePattern == null) {
1877                        if (this.conn.getNullNamePatternMatchesAll()) {
1878                                columnNamePattern = "%";
1879                        } else {
1880                                throw SQLError.createSQLException(
1881                                                "Column name pattern can not be NULL or empty.",
1882                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
1883                        }
1884                }
1885 
1886                final String colPattern = columnNamePattern;
1887 
1888                Field[] fields = new Field[18];
1889                fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 255);
1890                fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 0);
1891                fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 255);
1892                fields[3] = new Field("", "COLUMN_NAME", Types.CHAR, 32);
1893                fields[4] = new Field("", "DATA_TYPE", Types.SMALLINT, 5);
1894                fields[5] = new Field("", "TYPE_NAME", Types.CHAR, 16);
1895                fields[6] = new Field("", "COLUMN_SIZE", Types.INTEGER, Integer
1896                                .toString(Integer.MAX_VALUE).length());
1897                fields[7] = new Field("", "BUFFER_LENGTH", Types.INTEGER, 10);
1898                fields[8] = new Field("", "DECIMAL_DIGITS", Types.INTEGER, 10);
1899                fields[9] = new Field("", "NUM_PREC_RADIX", Types.INTEGER, 10);
1900                fields[10] = new Field("", "NULLABLE", Types.INTEGER, 10);
1901                fields[11] = new Field("", "REMARKS", Types.CHAR, 0);
1902                fields[12] = new Field("", "COLUMN_DEF", Types.CHAR, 0);
1903                fields[13] = new Field("", "SQL_DATA_TYPE", Types.INTEGER, 10);
1904                fields[14] = new Field("", "SQL_DATETIME_SUB", Types.INTEGER, 10);
1905                fields[15] = new Field("", "CHAR_OCTET_LENGTH", Types.INTEGER, Integer
1906                                .toString(Integer.MAX_VALUE).length());
1907                fields[16] = new Field("", "ORDINAL_POSITION", Types.INTEGER, 10);
1908                fields[17] = new Field("", "IS_NULLABLE", Types.CHAR, 3);
1909 
1910                final ArrayList rows = new ArrayList();
1911                final Statement stmt = this.conn.getMetadataSafeStatement();
1912 
1913                try {
1914 
1915                        new IterateBlock(getCatalogIterator(catalog)) {
1916                                void forEach(Object catalogStr) throws SQLException {
1917 
1918                                        ArrayList tableNameList = new ArrayList();
1919 
1920                                        if (tableNamePattern == null) {
1921                                                // Select from all tables
1922                                                java.sql.ResultSet tables = null;
1923 
1924                                                try {
1925                                                        tables = getTables(catalog, schemaPattern, "%",
1926                                                                        new String[0]);
1927 
1928                                                        while (tables.next()) {
1929                                                                String tableNameFromList = tables
1930                                                                                .getString("TABLE_NAME");
1931                                                                tableNameList.add(tableNameFromList);
1932                                                        }
1933                                                } finally {
1934                                                        if (tables != null) {
1935                                                                try {
1936                                                                        tables.close();
1937                                                                } catch (Exception sqlEx) {
1938                                                                        AssertionFailedException
1939                                                                                        .shouldNotHappen(sqlEx);
1940                                                                }
1941 
1942                                                                tables = null;
1943                                                        }
1944                                                }
1945                                        } else {
1946                                                java.sql.ResultSet tables = null;
1947 
1948                                                try {
1949                                                        tables = getTables(catalog, schemaPattern,
1950                                                                        tableNamePattern, new String[0]);
1951 
1952                                                        while (tables.next()) {
1953                                                                String tableNameFromList = tables
1954                                                                                .getString("TABLE_NAME");
1955                                                                tableNameList.add(tableNameFromList);
1956                                                        }
1957                                                } finally {
1958                                                        if (tables != null) {
1959                                                                try {
1960                                                                        tables.close();
1961                                                                } catch (SQLException sqlEx) {
1962                                                                        AssertionFailedException
1963                                                                                        .shouldNotHappen(sqlEx);
1964                                                                }
1965 
1966                                                                tables = null;
1967                                                        }
1968                                                }
1969                                        }
1970 
1971                                        java.util.Iterator tableNames = tableNameList.iterator();
1972 
1973                                        while (tableNames.hasNext()) {
1974                                                String tableName = (String) tableNames.next();
1975 
1976                                                ResultSet results = null;
1977 
1978                                                try {
1979                                                        StringBuffer queryBuf = new StringBuffer("SHOW ");
1980 
1981                                                        if (conn.versionMeetsMinimum(4, 1, 0)) {
1982                                                                queryBuf.append("FULL ");
1983                                                        }
1984 
1985                                                        queryBuf.append("COLUMNS FROM ");
1986                                                        queryBuf.append(quotedId);
1987                                                        queryBuf.append(tableName);
1988                                                        queryBuf.append(quotedId);
1989                                                        queryBuf.append(" FROM ");
1990                                                        queryBuf.append(quotedId);
1991                                                        queryBuf.append(catalogStr.toString());
1992                                                        queryBuf.append(quotedId);
1993                                                        queryBuf.append(" LIKE '");
1994                                                        queryBuf.append(colPattern);
1995                                                        queryBuf.append("'");
1996 
1997                                                        // Return correct ordinals if column name pattern is
1998                                                        // not '%'
1999                                                        // Currently, MySQL doesn't show enough data to do
2000                                                        // this, so we do it the 'hard' way...Once _SYSTEM
2001                                                        // tables are in, this should be much easier
2002                                                        boolean fixUpOrdinalsRequired = false;
2003                                                        Map ordinalFixUpMap = null;
2004 
2005                                                        if (!colPattern.equals("%")) {
2006                                                                fixUpOrdinalsRequired = true;
2007 
2008                                                                StringBuffer fullColumnQueryBuf = new StringBuffer(
2009                                                                                "SHOW ");
2010 
2011                                                                if (conn.versionMeetsMinimum(4, 1, 0)) {
2012                                                                        fullColumnQueryBuf.append("FULL ");
2013                                                                }
2014 
2015                                                                fullColumnQueryBuf.append("COLUMNS FROM ");
2016                                                                fullColumnQueryBuf.append(quotedId);
2017                                                                fullColumnQueryBuf.append(tableName);
2018                                                                fullColumnQueryBuf.append(quotedId);
2019                                                                fullColumnQueryBuf.append(" FROM ");
2020                                                                fullColumnQueryBuf.append(quotedId);
2021                                                                fullColumnQueryBuf
2022                                                                                .append(catalogStr.toString());
2023                                                                fullColumnQueryBuf.append(quotedId);
2024 
2025                                                                results = stmt.executeQuery(fullColumnQueryBuf
2026                                                                                .toString());
2027 
2028                                                                ordinalFixUpMap = new HashMap();
2029 
2030                                                                int fullOrdinalPos = 1;
2031 
2032                                                                while (results.next()) {
2033                                                                        String fullOrdColName = results
2034                                                                                        .getString("Field");
2035 
2036                                                                        ordinalFixUpMap.put(fullOrdColName,
2037                                                                                        new Integer(fullOrdinalPos++));
2038                                                                }
2039                                                        }
2040 
2041                                                        results = stmt.executeQuery(queryBuf.toString());
2042 
2043                                                        int ordPos = 1;
2044 
2045                                                        while (results.next()) {
2046                                                                byte[][] rowVal = new byte[18][];
2047                                                                rowVal[0] = s2b(catalog); // TABLE_CAT
2048                                                                rowVal[1] = null; // TABLE_SCHEM (No schemas
2049                                                                // in MySQL)
2050 
2051                                                                rowVal[2] = s2b(tableName); // TABLE_NAME
2052                                                                rowVal[3] = results.getBytes("Field");
2053 
2054                                                                TypeDescriptor typeDesc = new TypeDescriptor(
2055                                                                                results.getString("Type"), results
2056                                                                                                .getString("Null"));
2057 
2058                                                                rowVal[4] = Short.toString(typeDesc.dataType)
2059                                                                                .getBytes();
2060 
2061                                                                // DATA_TYPE (jdbc)
2062                                                                rowVal[5] = s2b(typeDesc.typeName); // TYPE_NAME
2063                                                                // (native)
2064                                                                rowVal[6] = s2b(Integer
2065                                                                                .toString(typeDesc.columnSize));
2066                                                                rowVal[7] = s2b(Integer
2067                                                                                .toString(typeDesc.bufferLength));
2068                                                                rowVal[8] = s2b(Integer
2069                                                                                .toString(typeDesc.decimalDigits));
2070                                                                rowVal[9] = s2b(Integer
2071                                                                                .toString(typeDesc.numPrecRadix));
2072                                                                rowVal[10] = s2b(Integer
2073                                                                                .toString(typeDesc.nullability));
2074 
2075                                                                //
2076                                                                // Doesn't always have this field, depending on
2077                                                                // version
2078                                                                //
2079                                                                //
2080                                                                // REMARK column
2081                                                                //
2082                                                                try {
2083                                                                        if (conn.versionMeetsMinimum(4, 1, 0)) {
2084                                                                                rowVal[11] = results
2085                                                                                                .getBytes("Comment");
2086                                                                        } else {
2087                                                                                rowVal[11] = results.getBytes("Extra");
2088                                                                        }
2089                                                                } catch (Exception E) {
2090                                                                        rowVal[11] = new byte[0];
2091                                                                }
2092 
2093                                                                // COLUMN_DEF
2094                                                                rowVal[12] = results.getBytes("Default");
2095 
2096                                                                rowVal[13] = new byte[] { (byte) '0' }; // SQL_DATA_TYPE
2097                                                                rowVal[14] = new byte[] { (byte) '0' }; // SQL_DATE_TIME_SUB
2098                                                                rowVal[15] = rowVal[6]; // CHAR_OCTET_LENGTH
2099 
2100                                                                // ORDINAL_POSITION
2101                                                                if (!fixUpOrdinalsRequired) {
2102                                                                        rowVal[16] = Integer.toString(ordPos++)
2103                                                                                        .getBytes();
2104                                                                } else {
2105                                                                        String origColName = results
2106                                                                                        .getString("Field");
2107                                                                        Integer realOrdinal = (Integer) ordinalFixUpMap
2108                                                                                        .get(origColName);
2109 
2110                                                                        if (realOrdinal != null) {
2111                                                                                rowVal[16] = realOrdinal.toString()
2112                                                                                                .getBytes();
2113                                                                        } else {
2114                                                                                throw SQLError.createSQLException(
2115                                                                                                "Can not find column in full column list to determine true ordinal position.",
2116                                                                                                SQLError.SQL_STATE_GENERAL_ERROR);
2117                                                                        }
2118                                                                }
2119 
2120                                                                rowVal[17] = s2b(typeDesc.isNullable);
2121 
2122                                                                rows.add(rowVal);
2123                                                        }
2124                                                } finally {
2125                                                        if (results != null) {
2126                                                                try {
2127                                                                        results.close();
2128                                                                } catch (Exception ex) {
2129                                                                        ;
2130                                                                }
2131 
2132                                                                results = null;
2133                                                        }
2134                                                }
2135                                        }
2136                                }
2137                        }.doForAll();
2138                } finally {
2139                        if (stmt != null) {
2140                                stmt.close();
2141                        }
2142                }
2143 
2144                java.sql.ResultSet results = buildResultSet(fields, rows);
2145 
2146                return results;
2147        }
2148 
2149        /**
2150         * JDBC 2.0 Return the connection that produced this metadata object.
2151         * 
2152         * @return the connection that produced this metadata object.
2153         * @throws SQLException
2154         *             if a database error occurs
2155         */
2156        public java.sql.Connection getConnection() throws SQLException {
2157                return this.conn;
2158        }
2159 
2160        /**
2161         * Get a description of the foreign key columns in the foreign key table
2162         * that reference the primary key columns of the primary key table (describe
2163         * how one table imports another's key.) This should normally return a
2164         * single foreign key/primary key pair (most tables only import a foreign
2165         * key from a table once.) They are ordered by FKTABLE_CAT, FKTABLE_SCHEM,
2166         * FKTABLE_NAME, and KEY_SEQ.
2167         * <P>
2168         * Each foreign key column description has the following columns:
2169         * <OL>
2170         * <li> <B>PKTABLE_CAT</B> String => primary key table catalog (may be
2171         * null) </li>
2172         * <li> <B>PKTABLE_SCHEM</B> String => primary key table schema (may be
2173         * null) </li>
2174         * <li> <B>PKTABLE_NAME</B> String => primary key table name </li>
2175         * <li> <B>PKCOLUMN_NAME</B> String => primary key column name </li>
2176         * <li> <B>FKTABLE_CAT</B> String => foreign key table catalog (may be
2177         * null) being exported (may be null) </li>
2178         * <li> <B>FKTABLE_SCHEM</B> String => foreign key table schema (may be
2179         * null) being exported (may be null) </li>
2180         * <li> <B>FKTABLE_NAME</B> String => foreign key table name being exported
2181         * </li>
2182         * <li> <B>FKCOLUMN_NAME</B> String => foreign key column name being
2183         * exported </li>
2184         * <li> <B>KEY_SEQ</B> short => sequence number within foreign key </li>
2185         * <li> <B>UPDATE_RULE</B> short => What happens to foreign key when
2186         * primary is updated:
2187         * <UL>
2188         * <li> importedKeyCascade - change imported key to agree with primary key
2189         * update </li>
2190         * <li> importedKeyRestrict - do not allow update of primary key if it has
2191         * been imported </li>
2192         * <li> importedKeySetNull - change imported key to NULL if its primary key
2193         * has been updated </li>
2194         * </ul>
2195         * </li>
2196         * <li> <B>DELETE_RULE</B> short => What happens to the foreign key when
2197         * primary is deleted.
2198         * <UL>
2199         * <li> importedKeyCascade - delete rows that import a deleted key </li>
2200         * <li> importedKeyRestrict - do not allow delete of primary key if it has
2201         * been imported </li>
2202         * <li> importedKeySetNull - change imported key to NULL if its primary key
2203         * has been deleted </li>
2204         * </ul>
2205         * </li>
2206         * <li> <B>FK_NAME</B> String => foreign key identifier (may be null) </li>
2207         * <li> <B>PK_NAME</B> String => primary key identifier (may be null) </li>
2208         * </ol>
2209         * </p>
2210         * 
2211         * @param primaryCatalog
2212         *            a catalog name; "" retrieves those without a catalog
2213         * @param primarySchema
2214         *            a schema name pattern; "" retrieves those without a schema
2215         * @param primaryTable
2216         *            a table name
2217         * @param foreignCatalog
2218         *            a catalog name; "" retrieves those without a catalog
2219         * @param foreignSchema
2220         *            a schema name pattern; "" retrieves those without a schema
2221         * @param foreignTable
2222         *            a table name
2223         * @return ResultSet each row is a foreign key column description
2224         * @throws SQLException
2225         *             if a database access error occurs
2226         */
2227        public java.sql.ResultSet getCrossReference(final String primaryCatalog,
2228                        final String primarySchema, final String primaryTable,
2229                        final String foreignCatalog, final String foreignSchema,
2230                        final String foreignTable) throws SQLException {
2231                if (primaryTable == null) {
2232                        throw SQLError.createSQLException("Table not specified.",
2233                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2234                }
2235 
2236                Field[] fields = new Field[14];
2237                fields[0] = new Field("", "PKTABLE_CAT", Types.CHAR, 255);
2238                fields[1] = new Field("", "PKTABLE_SCHEM", Types.CHAR, 0);
2239                fields[2] = new Field("", "PKTABLE_NAME", Types.CHAR, 255);
2240                fields[3] = new Field("", "PKCOLUMN_NAME", Types.CHAR, 32);
2241                fields[4] = new Field("", "FKTABLE_CAT", Types.CHAR, 255);
2242                fields[5] = new Field("", "FKTABLE_SCHEM", Types.CHAR, 0);
2243                fields[6] = new Field("", "FKTABLE_NAME", Types.CHAR, 255);
2244                fields[7] = new Field("", "FKCOLUMN_NAME", Types.CHAR, 32);
2245                fields[8] = new Field("", "KEY_SEQ", Types.SMALLINT, 2);
2246                fields[9] = new Field("", "UPDATE_RULE", Types.SMALLINT, 2);
2247                fields[10] = new Field("", "DELETE_RULE", Types.SMALLINT, 2);
2248                fields[11] = new Field("", "FK_NAME", Types.CHAR, 0);
2249                fields[12] = new Field("", "PK_NAME", Types.CHAR, 0);
2250                fields[13] = new Field("", "DEFERRABILITY", Types.INTEGER, 2);
2251 
2252                final ArrayList tuples = new ArrayList();
2253 
2254                if (this.conn.versionMeetsMinimum(3, 23, 0)) {
2255 
2256                        final Statement stmt = this.conn.getMetadataSafeStatement();
2257 
2258                        try {
2259 
2260                                new IterateBlock(getCatalogIterator(foreignCatalog)) {
2261                                        void forEach(Object catalogStr) throws SQLException {
2262 
2263                                                ResultSet fkresults = null;
2264 
2265                                                try {
2266 
2267                                                        /*
2268                                                         * Get foreign key information for table
2269                                                         */
2270                                                        if (conn.versionMeetsMinimum(3, 23, 50)) {
2271                                                                fkresults = extractForeignKeyFromCreateTable(
2272                                                                                catalogStr.toString(), null);
2273                                                        } else {
2274                                                                StringBuffer queryBuf = new StringBuffer(
2275                                                                                "SHOW TABLE STATUS FROM ");
2276                                                                queryBuf.append(quotedId);
2277                                                                queryBuf.append(catalogStr.toString());
2278                                                                queryBuf.append(quotedId);
2279 
2280                                                                fkresults = stmt.executeQuery(queryBuf
2281                                                                                .toString());
2282                                                        }
2283 
2284                                                        String foreignTableWithCase = getTableNameWithCase(foreignTable);
2285                                                        String primaryTableWithCase = getTableNameWithCase(primaryTable);
2286 
2287                                                        /*
2288                                                         * Parse imported foreign key information
2289                                                         */
2290 
2291                                                        String dummy;
2292 
2293                                                        while (fkresults.next()) {
2294                                                                String tableType = fkresults.getString("Type");
2295 
2296                                                                if ((tableType != null)
2297                                                                                && (tableType
2298                                                                                                .equalsIgnoreCase("innodb") || tableType
2299                                                                                                .equalsIgnoreCase(SUPPORTS_FK))) {
2300                                                                        String comment = fkresults.getString(
2301                                                                                        "Comment").trim();
2302 
2303                                                                        if (comment != null) {
2304                                                                                StringTokenizer commentTokens = new StringTokenizer(
2305                                                                                                comment, ";", false);
2306 
2307                                                                                if (commentTokens.hasMoreTokens()) {
2308                                                                                        dummy = commentTokens.nextToken();
2309 
2310                                                                                        // Skip InnoDB comment
2311                                                                                }
2312 
2313                                                                                while (commentTokens.hasMoreTokens()) {
2314                                                                                        String keys = commentTokens
2315                                                                                                        .nextToken();
2316                                                                                        LocalAndReferencedColumns parsedInfo = parseTableStatusIntoLocalAndReferencedColumns(keys);
2317 
2318                                                                                        int keySeq = 0;
2319 
2320                                                                                        Iterator referencingColumns = parsedInfo.localColumnsList
2321                                                                                                        .iterator();
2322                                                                                        Iterator referencedColumns = parsedInfo.referencedColumnsList
2323                                                                                                        .iterator();
2324 
2325                                                                                        while (referencingColumns.hasNext()) {
2326                                                                                                String referencingColumn = removeQuotedId(referencingColumns
2327                                                                                                                .next().toString());
2328 
2329                                                                                                // one tuple for each table
2330                                                                                                // between
2331                                                                                                // parenthesis
2332                                                                                                byte[][] tuple = new byte[14][];
2333                                                                                                tuple[4] = ((foreignCatalog == null) ? null
2334                                                                                                                : s2b(foreignCatalog));
2335                                                                                                tuple[5] = ((foreignSchema == null) ? null
2336                                                                                                                : s2b(foreignSchema));
2337                                                                                                dummy = fkresults
2338                                                                                                                .getString("Name"); // FKTABLE_NAME
2339 
2340                                                                                                if (dummy
2341                                                                                                                .compareTo(foreignTableWithCase) != 0) {
2342                                                                                                        continue;
2343                                                                                                }
2344 
2345                                                                                                tuple[6] = s2b(dummy);
2346 
2347                                                                                                tuple[7] = s2b(referencingColumn); // FKCOLUMN_NAME
2348                                                                                                tuple[0] = ((primaryCatalog == null) ? null
2349                                                                                                                : s2b(primaryCatalog));
2350                                                                                                tuple[1] = ((primarySchema == null) ? null
2351                                                                                                                : s2b(primarySchema));
2352 
2353                                                                                                // Skip foreign key if it
2354                                                                                                // doesn't refer to
2355                                                                                                // the right table
2356                                                                                                if (parsedInfo.referencedTable
2357                                                                                                                .compareTo(primaryTableWithCase) != 0) {
2358                                                                                                        continue;
2359                                                                                                }
2360 
2361                                                                                                tuple[2] = s2b(parsedInfo.referencedTable); // PKTABLE_NAME
2362                                                                                                tuple[3] = s2b(removeQuotedId(referencedColumns
2363                                                                                                                .next().toString())); // PKCOLUMN_NAME
2364                                                                                                tuple[8] = Integer.toString(
2365                                                                                                                keySeq).getBytes(); // KEY_SEQ
2366 
2367                                                                                                int[] actions = getForeignKeyActions(keys);
2368 
2369                                                                                                tuple[9] = Integer.toString(
2370                                                                                                                actions[1]).getBytes();
2371                                                                                                tuple[10] = Integer.toString(
2372                                                                                                                actions[0]).getBytes();
2373                                                                                                tuple[11] = null; // FK_NAME
2374                                                                                                tuple[12] = null; // PK_NAME
2375                                                                                                tuple[13] = Integer
2376                                                                                                                .toString(
2377                                                                                                                                java.sql.DatabaseMetaData.importedKeyNotDeferrable)
2378                                                                                                                .getBytes();
2379                                                                                                tuples.add(tuple);
2380                                                                                                keySeq++;
2381                                                                                        }
2382                                                                                }
2383                                                                        }
2384                                                                }
2385                                                        }
2386 
2387                                                } finally {
2388                                                        if (fkresults != null) {
2389                                                                try {
2390                                                                        fkresults.close();
2391                                                                } catch (Exception sqlEx) {
2392                                                                        AssertionFailedException
2393                                                                                        .shouldNotHappen(sqlEx);
2394                                                                }
2395 
2396                                                                fkresults = null;
2397                                                        }
2398                                                }
2399                                        }
2400                                }.doForAll();
2401                        } finally {
2402                                if (stmt != null) {
2403                                        stmt.close();
2404                                }
2405                        }
2406                }
2407 
2408                java.sql.ResultSet results = buildResultSet(fields, tuples);
2409 
2410                return results;
2411        }
2412 
2413        /**
2414         * @see DatabaseMetaData#getDatabaseMajorVersion()
2415         */
2416        public int getDatabaseMajorVersion() throws SQLException {
2417                return this.conn.getServerMajorVersion();
2418        }
2419 
2420        /**
2421         * @see DatabaseMetaData#getDatabaseMinorVersion()
2422         */
2423        public int getDatabaseMinorVersion() throws SQLException {
2424                return this.conn.getServerMinorVersion();
2425        }
2426 
2427        /**
2428         * What's the name of this database product?
2429         * 
2430         * @return database product name
2431         * @throws SQLException
2432         *             DOCUMENT ME!
2433         */
2434        public String getDatabaseProductName() throws SQLException {
2435                return "MySQL";
2436        }
2437 
2438        /**
2439         * What's the version of this database product?
2440         * 
2441         * @return database version
2442         * @throws SQLException
2443         *             DOCUMENT ME!
2444         */
2445        public String getDatabaseProductVersion() throws SQLException {
2446                return this.conn.getServerVersion();
2447        }
2448 
2449        /**
2450         * What's the database's default transaction isolation level? The values are
2451         * defined in java.sql.Connection.
2452         * 
2453         * @return the default isolation level
2454         * @throws SQLException
2455         *             if a database access error occurs
2456         * @see Connection
2457         */
2458        public int getDefaultTransactionIsolation() throws SQLException {
2459                if (this.conn.supportsIsolationLevel()) {
2460                        return java.sql.Connection.TRANSACTION_READ_COMMITTED;
2461                }
2462 
2463                return java.sql.Connection.TRANSACTION_NONE;
2464        }
2465 
2466        /**
2467         * What's this JDBC driver's major version number?
2468         * 
2469         * @return JDBC driver major version
2470         */
2471        public int getDriverMajorVersion() {
2472                return NonRegisteringDriver.getMajorVersionInternal();
2473        }
2474 
2475        /**
2476         * What's this JDBC driver's minor version number?
2477         * 
2478         * @return JDBC driver minor version number
2479         */
2480        public int getDriverMinorVersion() {
2481                return NonRegisteringDriver.getMinorVersionInternal();
2482        }
2483 
2484        /**
2485         * What's the name of this JDBC driver?
2486         * 
2487         * @return JDBC driver name
2488         * @throws SQLException
2489         *             DOCUMENT ME!
2490         */
2491        public String getDriverName() throws SQLException {
2492                return "MySQL-AB JDBC Driver";
2493        }
2494 
2495        /**
2496         * What's the version of this JDBC driver?
2497         * 
2498         * @return JDBC driver version
2499         * @throws java.sql.SQLException
2500         *             DOCUMENT ME!
2501         */
2502        public String getDriverVersion() throws java.sql.SQLException {
2503                return "mysql-connector-java-5.0.3 ( $Date: 2005-11-17 09:14:47 -0600 (Thu, 17 Nov 2005) $, $Revision: 4560 $ )";
2504        }
2505 
2506        /**
2507         * Get a description of a foreign key columns that reference a table's
2508         * primary key columns (the foreign keys exported by a table). They are
2509         * ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.
2510         * <P>
2511         * Each foreign key column description has the following columns:
2512         * <OL>
2513         * <li> <B>PKTABLE_CAT</B> String => primary key table catalog (may be
2514         * null) </li>
2515         * <li> <B>PKTABLE_SCHEM</B> String => primary key table schema (may be
2516         * null) </li>
2517         * <li> <B>PKTABLE_NAME</B> String => primary key table name </li>
2518         * <li> <B>PKCOLUMN_NAME</B> String => primary key column name </li>
2519         * <li> <B>FKTABLE_CAT</B> String => foreign key table catalog (may be
2520         * null) being exported (may be null) </li>
2521         * <li> <B>FKTABLE_SCHEM</B> String => foreign key table schema (may be
2522         * null) being exported (may be null) </li>
2523         * <li> <B>FKTABLE_NAME</B> String => foreign key table name being exported
2524         * </li>
2525         * <li> <B>FKCOLUMN_NAME</B> String => foreign key column name being
2526         * exported </li>
2527         * <li> <B>KEY_SEQ</B> short => sequence number within foreign key </li>
2528         * <li> <B>UPDATE_RULE</B> short => What happens to foreign key when
2529         * primary is updated:
2530         * <UL>
2531         * <li> importedKeyCascade - change imported key to agree with primary key
2532         * update </li>
2533         * <li> importedKeyRestrict - do not allow update of primary key if it has
2534         * been imported </li>
2535         * <li> importedKeySetNull - change imported key to NULL if its primary key
2536         * has been updated </li>
2537         * </ul>
2538         * </li>
2539         * <li> <B>DELETE_RULE</B> short => What happens to the foreign key when
2540         * primary is deleted.
2541         * <UL>
2542         * <li> importedKeyCascade - delete rows that import a deleted key </li>
2543         * <li> importedKeyRestrict - do not allow delete of primary key if it has
2544         * been imported </li>
2545         * <li> importedKeySetNull - change imported key to NULL if its primary key
2546         * has been deleted </li>
2547         * </ul>
2548         * </li>
2549         * <li> <B>FK_NAME</B> String => foreign key identifier (may be null) </li>
2550         * <li> <B>PK_NAME</B> String => primary key identifier (may be null) </li>
2551         * </ol>
2552         * </p>
2553         * 
2554         * @param catalog
2555         *            a catalog name; "" retrieves those without a catalog
2556         * @param schema
2557         *            a schema name pattern; "" retrieves those without a schema
2558         * @param table
2559         *            a table name
2560         * @return ResultSet each row is a foreign key column description
2561         * @throws SQLException
2562         *             if a database access error occurs
2563         * @see #getImportedKeys
2564         */
2565        public java.sql.ResultSet getExportedKeys(String catalog, String schema,
2566                        final String table) throws SQLException {
2567                if (table == null) {
2568                        throw SQLError.createSQLException("Table not specified.",
2569                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2570                }
2571 
2572                Field[] fields = new Field[14];
2573                fields[0] = new Field("", "PKTABLE_CAT", Types.CHAR, 255);
2574                fields[1] = new Field("", "PKTABLE_SCHEM", Types.CHAR, 0);
2575                fields[2] = new Field("", "PKTABLE_NAME", Types.CHAR, 255);
2576                fields[3] = new Field("", "PKCOLUMN_NAME", Types.CHAR, 32);
2577                fields[4] = new Field("", "FKTABLE_CAT", Types.CHAR, 255);
2578                fields[5] = new Field("", "FKTABLE_SCHEM", Types.CHAR, 0);
2579                fields[6] = new Field("", "FKTABLE_NAME", Types.CHAR, 255);
2580                fields[7] = new Field("", "FKCOLUMN_NAME", Types.CHAR, 32);
2581                fields[8] = new Field("", "KEY_SEQ", Types.SMALLINT, 2);
2582                fields[9] = new Field("", "UPDATE_RULE", Types.SMALLINT, 2);
2583                fields[10] = new Field("", "DELETE_RULE", Types.SMALLINT, 2);
2584                fields[11] = new Field("", "FK_NAME", Types.CHAR, 255);
2585                fields[12] = new Field("", "PK_NAME", Types.CHAR, 0);
2586                fields[13] = new Field("", "DEFERRABILITY", Types.INTEGER, 2);
2587 
2588                final ArrayList rows = new ArrayList();
2589 
2590                if (this.conn.versionMeetsMinimum(3, 23, 0)) {
2591 
2592                        final Statement stmt = this.conn.getMetadataSafeStatement();
2593 
2594                        try {
2595 
2596                                new IterateBlock(getCatalogIterator(catalog)) {
2597                                        void forEach(Object catalogStr) throws SQLException {
2598                                                ResultSet fkresults = null;
2599 
2600                                                try {
2601 
2602                                                        /*
2603                                                         * Get foreign key information for table
2604                                                         */
2605                                                        if (conn.versionMeetsMinimum(3, 23, 50)) {
2606                                                                // we can use 'SHOW CREATE TABLE'
2607 
2608                                                                fkresults = extractForeignKeyFromCreateTable(
2609                                                                                catalogStr.toString(), null);
2610                                                        } else {
2611                                                                StringBuffer queryBuf = new StringBuffer(
2612                                                                                "SHOW TABLE STATUS FROM ");
2613                                                                queryBuf.append(quotedId);
2614                                                                queryBuf.append(catalogStr.toString());
2615                                                                queryBuf.append(quotedId);
2616 
2617                                                                fkresults = stmt.executeQuery(queryBuf
2618                                                                                .toString());
2619                                                        }
2620 
2621                                                        // lower-case table name might be turned on
2622                                                        String tableNameWithCase = getTableNameWithCase(table);
2623 
2624                                                        /*
2625                                                         * Parse imported foreign key information
2626                                                         */
2627 
2628                                                        while (fkresults.next()) {
2629                                                                String tableType = fkresults.getString("Type");
2630 
2631                                                                if ((tableType != null)
2632                                                                                && (tableType
2633                                                                                                .equalsIgnoreCase("innodb") || tableType
2634                                                                                                .equalsIgnoreCase(SUPPORTS_FK))) {
2635                                                                        String comment = fkresults.getString(
2636                                                                                        "Comment").trim();
2637 
2638                                                                        if (comment != null) {
2639                                                                                StringTokenizer commentTokens = new StringTokenizer(
2640                                                                                                comment, ";", false);
2641 
2642                                                                                if (commentTokens.hasMoreTokens()) {
2643                                                                                        commentTokens.nextToken(); // Skip
2644                                                                                        // InnoDB
2645                                                                                        // comment
2646 
2647                                                                                        while (commentTokens
2648                                                                                                        .hasMoreTokens()) {
2649                                                                                                String keys = commentTokens
2650                                                                                                                .nextToken();
2651                                                                                                getExportKeyResults(
2652                                                                                                                catalogStr.toString(),
2653                                                                                                                tableNameWithCase,
2654                                                                                                                keys,
2655                                                                                                                rows,
2656                                                                                                                fkresults
2657                                                                                                                                .getString("Name"));
2658                                                                                        }
2659                                                                                }
2660                                                                        }
2661                                                                }
2662                                                        }
2663 
2664                                                } finally {
2665                                                        if (fkresults != null) {
2666                                                                try {
2667                                                                        fkresults.close();
2668                                                                } catch (SQLException sqlEx) {
2669                                                                        AssertionFailedException
2670                                                                                        .shouldNotHappen(sqlEx);
2671                                                                }
2672 
2673                                                                fkresults = null;
2674                                                        }
2675                                                }
2676                                        }
2677                                }.doForAll();
2678                        } finally {
2679                                if (stmt != null) {
2680                                        stmt.close();
2681                                }
2682                        }
2683                }
2684 
2685                java.sql.ResultSet results = buildResultSet(fields, rows);
2686 
2687                return results;
2688        }
2689 
2690        /**
2691         * Adds to the tuples list the exported keys of exportingTable based on the
2692         * keysComment from the 'show table status' sql command. KeysComment is that
2693         * part of the comment field that follows the "InnoDB free ...;" prefix.
2694         * 
2695         * @param catalog
2696         *            the database to use
2697         * @param exportingTable
2698         *            the table keys are being exported from
2699         * @param keysComment
2700         *            the comment from 'show table status'
2701         * @param tuples
2702         *            the rows to add results to
2703         * @param fkTableName
2704         *            the foreign key table name
2705         * @throws SQLException
2706         *             if a database access error occurs
2707         */
2708        private void getExportKeyResults(String catalog, String exportingTable,
2709                        String keysComment, List tuples, String fkTableName)
2710                        throws SQLException {
2711                getResultsImpl(catalog, exportingTable, keysComment, tuples,
2712                                fkTableName, true);
2713        }
2714 
2715        /**
2716         * Get all the "extra" characters that can be used in unquoted identifier
2717         * names (those beyond a-z, 0-9 and _).
2718         * 
2719         * @return the string containing the extra characters
2720         * @throws SQLException
2721         *             DOCUMENT ME!
2722         */
2723        public String getExtraNameCharacters() throws SQLException {
2724                return "#@";
2725        }
2726 
2727        /**
2728         * Returns the DELETE and UPDATE foreign key actions from the given 'SHOW
2729         * TABLE STATUS' string, with the DELETE action being the first item in the
2730         * array, and the UPDATE action being the second.
2731         * 
2732         * @param commentString
2733         *            the comment from 'SHOW TABLE STATUS'
2734         * @return int[] [0] = delete action, [1] = update action
2735         */
2736        private int[] getForeignKeyActions(String commentString) {
2737                int[] actions = new int[] {
2738                                java.sql.DatabaseMetaData.importedKeyNoAction,
2739                                java.sql.DatabaseMetaData.importedKeyNoAction };
2740 
2741                int lastParenIndex = commentString.lastIndexOf(")");
2742 
2743                if (lastParenIndex != (commentString.length() - 1)) {
2744                        String cascadeOptions = commentString.substring(lastParenIndex + 1)
2745                                        .trim().toUpperCase(Locale.ENGLISH);
2746 
2747                        actions[0] = getCascadeDeleteOption(cascadeOptions);
2748                        actions[1] = getCascadeUpdateOption(cascadeOptions);
2749                }
2750 
2751                return actions;
2752        }
2753 
2754        /**
2755         * What's the string used to quote SQL identifiers? This returns a space " "
2756         * if identifier quoting isn't supported. A JDBC compliant driver always
2757         * uses a double quote character.
2758         * 
2759         * @return the quoting string
2760         * @throws SQLException
2761         *             DOCUMENT ME!
2762         */
2763        public String getIdentifierQuoteString() throws SQLException {
2764                if (this.conn.supportsQuotedIdentifiers()) {
2765                        if (!this.conn.useAnsiQuotedIdentifiers()) {
2766                                return "`";
2767                        }
2768 
2769                        return "\"";
2770                }
2771 
2772                return " ";
2773        }
2774 
2775        /**
2776         * Get a description of the primary key columns that are referenced by a
2777         * table's foreign key columns (the primary keys imported by a table). They
2778         * are ordered by PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.
2779         * <P>
2780         * Each primary key column description has the following columns:
2781         * <OL>
2782         * <li> <B>PKTABLE_CAT</B> String => primary key table catalog being
2783         * imported (may be null) </li>
2784         * <li> <B>PKTABLE_SCHEM</B> String => primary key table schema being
2785         * imported (may be null) </li>
2786         * <li> <B>PKTABLE_NAME</B> String => primary key table name being imported
2787         * </li>
2788         * <li> <B>PKCOLUMN_NAME</B> String => primary key column name being
2789         * imported </li>
2790         * <li> <B>FKTABLE_CAT</B> String => foreign key table catalog (may be
2791         * null) </li>
2792         * <li> <B>FKTABLE_SCHEM</B> String => foreign key table schema (may be
2793         * null) </li>
2794         * <li> <B>FKTABLE_NAME</B> String => foreign key table name </li>
2795         * <li> <B>FKCOLUMN_NAME</B> String => foreign key column name </li>
2796         * <li> <B>KEY_SEQ</B> short => sequence number within foreign key </li>
2797         * <li> <B>UPDATE_RULE</B> short => What happens to foreign key when
2798         * primary is updated:
2799         * <UL>
2800         * <li> importedKeyCascade - change imported key to agree with primary key
2801         * update </li>
2802         * <li> importedKeyRestrict - do not allow update of primary key if it has
2803         * been imported </li>
2804         * <li> importedKeySetNull - change imported key to NULL if its primary key
2805         * has been updated </li>
2806         * </ul>
2807         * </li>
2808         * <li> <B>DELETE_RULE</B> short => What happens to the foreign key when
2809         * primary is deleted.
2810         * <UL>
2811         * <li> importedKeyCascade - delete rows that import a deleted key </li>
2812         * <li> importedKeyRestrict - do not allow delete of primary key if it has
2813         * been imported </li>
2814         * <li> importedKeySetNull - change imported key to NULL if its primary key
2815         * has been deleted </li>
2816         * </ul>
2817         * </li>
2818         * <li> <B>FK_NAME</B> String => foreign key name (may be null) </li>
2819         * <li> <B>PK_NAME</B> String => primary key name (may be null) </li>
2820         * </ol>
2821         * </p>
2822         * 
2823         * @param catalog
2824         *            a catalog name; "" retrieves those without a catalog
2825         * @param schema
2826         *            a schema name pattern; "" retrieves those without a schema
2827         * @param table
2828         *            a table name
2829         * @return ResultSet each row is a primary key column description
2830         * @throws SQLException
2831         *             if a database access error occurs
2832         * @see #getExportedKeys
2833         */
2834        public java.sql.ResultSet getImportedKeys(String catalog, String schema,
2835                        final String table) throws SQLException {
2836                if (table == null) {
2837                        throw SQLError.createSQLException("Table not specified.",
2838                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2839                }
2840 
2841                Field[] fields = new Field[14];
2842                fields[0] = new Field("", "PKTABLE_CAT", Types.CHAR, 255);
2843                fields[1] = new Field("", "PKTABLE_SCHEM", Types.CHAR, 0);
2844                fields[2] = new Field("", "PKTABLE_NAME", Types.CHAR, 255);
2845                fields[3] = new Field("", "PKCOLUMN_NAME", Types.CHAR, 32);
2846                fields[4] = new Field("", "FKTABLE_CAT", Types.CHAR, 255);
2847                fields[5] = new Field("", "FKTABLE_SCHEM", Types.CHAR, 0);
2848                fields[6] = new Field("", "FKTABLE_NAME", Types.CHAR, 255);
2849                fields[7] = new Field("", "FKCOLUMN_NAME", Types.CHAR, 32);
2850                fields[8] = new Field("", "KEY_SEQ", Types.SMALLINT, 2);
2851                fields[9] = new Field("", "UPDATE_RULE", Types.SMALLINT, 2);
2852                fields[10] = new Field("", "DELETE_RULE", Types.SMALLINT, 2);
2853                fields[11] = new Field("", "FK_NAME", Types.CHAR, 255);
2854                fields[12] = new Field("", "PK_NAME", Types.CHAR, 0);
2855                fields[13] = new Field("", "DEFERRABILITY", Types.INTEGER, 2);
2856 
2857                final ArrayList rows = new ArrayList();
2858 
2859                if (this.conn.versionMeetsMinimum(3, 23, 0)) {
2860 
2861                        final Statement stmt = this.conn.getMetadataSafeStatement();
2862 
2863                        try {
2864 
2865                                new IterateBlock(getCatalogIterator(catalog)) {
2866                                        void forEach(Object catalogStr) throws SQLException {
2867                                                ResultSet fkresults = null;
2868 
2869                                                try {
2870 
2871                                                        /*
2872                                                         * Get foreign key information for table
2873                                                         */
2874                                                        if (conn.versionMeetsMinimum(3, 23, 50)) {
2875                                                                // we can use 'SHOW CREATE TABLE'
2876 
2877                                                                fkresults = extractForeignKeyFromCreateTable(
2878                                                                                catalogStr.toString(), table);
2879                                                        } else {
2880                                                                StringBuffer queryBuf = new StringBuffer(
2881                                                                                "SHOW TABLE STATUS ");
2882                                                                queryBuf.append(" FROM ");
2883                                                                queryBuf.append(quotedId);
2884                                                                queryBuf.append(catalogStr.toString());
2885                                                                queryBuf.append(quotedId);
2886                                                                queryBuf.append(" LIKE '");
2887                                                                queryBuf.append(table);
2888                                                                queryBuf.append("'");
2889 
2890                                                                fkresults = stmt.executeQuery(queryBuf
2891                                                                                .toString());
2892                                                        }
2893 
2894                                                        /*
2895                                                         * Parse imported foreign key information
2896                                                         */
2897 
2898                                                        while (fkresults.next()) {
2899                                                                String tableType = fkresults.getString("Type");
2900 
2901                                                                if ((tableType != null)
2902                                                                                && (tableType
2903                                                                                                .equalsIgnoreCase("innodb") || tableType
2904                                                                                                .equalsIgnoreCase(SUPPORTS_FK))) {
2905                                                                        String comment = fkresults.getString(
2906                                                                                        "Comment").trim();
2907 
2908                                                                        if (comment != null) {
2909                                                                                StringTokenizer commentTokens = new StringTokenizer(
2910                                                                                                comment, ";", false);
2911 
2912                                                                                if (commentTokens.hasMoreTokens()) {
2913                                                                                        commentTokens.nextToken(); // Skip
2914                                                                                        // InnoDB
2915                                                                                        // comment
2916 
2917                                                                                        while (commentTokens
2918                                                                                                        .hasMoreTokens()) {
2919                                                                                                String keys = commentTokens
2920                                                                                                                .nextToken();
2921                                                                                                getImportKeyResults(catalogStr
2922                                                                                                                .toString(), table,
2923                                                                                                                keys, rows);
2924                                                                                        }
2925                                                                                }
2926                                                                        }
2927                                                                }
2928                                                        }
2929                                                } finally {
2930                                                        if (fkresults != null) {
2931                                                                try {
2932                                                                        fkresults.close();
2933                                                                } catch (SQLException sqlEx) {
2934                                                                        AssertionFailedException
2935                                                                                        .shouldNotHappen(sqlEx);
2936                                                                }
2937 
2938                                                                fkresults = null;
2939                                                        }
2940                                                }
2941                                        }
2942                                }.doForAll();
2943                        } finally {
2944                                if (stmt != null) {
2945                                        stmt.close();
2946                                }
2947                        }
2948                }
2949 
2950                java.sql.ResultSet results = buildResultSet(fields, rows);
2951 
2952                return results;
2953        }
2954 
2955        /**
2956         * Populates the tuples list with the imported keys of importingTable based
2957         * on the keysComment from the 'show table status' sql command. KeysComment
2958         * is that part of the comment field that follows the "InnoDB free ...;"
2959         * prefix.
2960         * 
2961         * @param catalog
2962         *            the database to use
2963         * @param importingTable
2964         *            the table keys are being imported to
2965         * @param keysComment
2966         *            the comment from 'show table status'
2967         * @param tuples
2968         *            the rows to add results to
2969         * @throws SQLException
2970         *             if a database access error occurs
2971         */
2972        private void getImportKeyResults(String catalog, String importingTable,
2973                        String keysComment, List tuples) throws SQLException {
2974                getResultsImpl(catalog, importingTable, keysComment, tuples, null,
2975                                false);
2976        }
2977 
2978        /**
2979         * Get a description of a table's indices and statistics. They are ordered
2980         * by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.
2981         * <P>
2982         * Each index column description has the following columns:
2983         * <OL>
2984         * <li> <B>TABLE_CAT</B> String => table catalog (may be null) </li>
2985         * <li> <B>TABLE_SCHEM</B> String => table schema (may be null) </li>
2986         * <li> <B>TABLE_NAME</B> String => table name </li>
2987         * <li> <B>NON_UNIQUE</B> boolean => Can index values be non-unique? false
2988         * when TYPE is tableIndexStatistic </li>
2989         * <li> <B>INDEX_QUALIFIER</B> String => index catalog (may be null); null
2990         * when TYPE is tableIndexStatistic </li>
2991         * <li> <B>INDEX_NAME</B> String => index name; null when TYPE is
2992         * tableIndexStatistic </li>
2993         * <li> <B>TYPE</B> short => index type:
2994         * <UL>
2995         * <li> tableIndexStatistic - this identifies table statistics that are
2996         * returned in conjuction with a table's index descriptions </li>
2997         * <li> tableIndexClustered - this is a clustered index </li>
2998         * <li> tableIndexHashed - this is a hashed index </li>
2999         * <li> tableIndexOther - this is some other style of index </li>
3000         * </ul>
3001         * </li>
3002         * <li> <B>ORDINAL_POSITION</B> short => column sequence number within
3003         * index; zero when TYPE is tableIndexStatistic </li>
3004         * <li> <B>COLUMN_NAME</B> String => column name; null when TYPE is
3005         * tableIndexStatistic </li>
3006         * <li> <B>ASC_OR_DESC</B> String => column sort sequence, "A" =>
3007         * ascending, "D" => descending, may be null if sort sequence is not
3008         * supported; null when TYPE is tableIndexStatistic </li>
3009         * <li> <B>CARDINALITY</B> int => When TYPE is tableIndexStatisic then this
3010         * is the number of rows in the table; otherwise it is the number of unique
3011         * values in the index. </li>
3012         * <li> <B>PAGES</B> int => When TYPE is tableIndexStatisic then this is
3013         * the number of pages used for the table, otherwise it is the number of
3014         * pages used for the current index. </li>
3015         * <li> <B>FILTER_CONDITION</B> String => Filter condition, if any. (may be
3016         * null) </li>
3017         * </ol>
3018         * </p>
3019         * 
3020         * @param catalog
3021         *            a catalog name; "" retrieves those without a catalog
3022         * @param schema
3023         *            a schema name pattern; "" retrieves those without a schema
3024         * @param table
3025         *            a table name
3026         * @param unique
3027         *            when true, return only indices for unique values; when false,
3028         *            return indices regardless of whether unique or not
3029         * @param approximate
3030         *            when true, result is allowed to reflect approximate or out of
3031         *            data values; when false, results are requested to be accurate
3032         * @return ResultSet each row is an index column description
3033         * @throws SQLException
3034         *             DOCUMENT ME!
3035         */
3036        public java.sql.ResultSet getIndexInfo(String catalog, String schema,
3037                        final String table, final boolean unique, boolean approximate)
3038                        throws SQLException {
3039                /*
3040                 * MySQL stores index information in the following fields: Table
3041                 * Non_unique Key_name Seq_in_index Column_name Collation Cardinality
3042                 * Sub_part
3043                 */
3044 
3045                Field[] fields = new Field[13];
3046                fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 255);
3047                fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 0);
3048                fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 255);
3049                fields[3] = new Field("", "NON_UNIQUE", Types.CHAR, 4);
3050                fields[4] = new Field("", "INDEX_QUALIFIER", Types.CHAR, 1);
3051                fields[5] = new Field("", "INDEX_NAME", Types.CHAR, 32);
3052                fields[6] = new Field("", "TYPE", Types.CHAR, 32);
3053                fields[7] = new Field("", "ORDINAL_POSITION", Types.SMALLINT, 5);
3054                fields[8] = new Field("", "COLUMN_NAME", Types.CHAR, 32);
3055                fields[9] = new Field("", "ASC_OR_DESC", Types.CHAR, 1);
3056                fields[10] = new Field("", "CARDINALITY", Types.INTEGER, 10);
3057                fields[11] = new Field("", "PAGES", Types.INTEGER, 10);
3058                fields[12] = new Field("", "FILTER_CONDITION", Types.CHAR, 32);
3059 
3060                final ArrayList rows = new ArrayList();
3061                final Statement stmt = this.conn.getMetadataSafeStatement();
3062 
3063                try {
3064 
3065                        new IterateBlock(getCatalogIterator(catalog)) {
3066                                void forEach(Object catalogStr) throws SQLException {
3067 
3068                                        ResultSet results = null;
3069 
3070                                        try {
3071                                                StringBuffer queryBuf = new StringBuffer(
3072                                                                "SHOW INDEX FROM ");
3073                                                queryBuf.append(quotedId);
3074                                                queryBuf.append(table);
3075                                                queryBuf.append(quotedId);
3076                                                queryBuf.append(" FROM ");
3077                                                queryBuf.append(quotedId);
3078                                                queryBuf.append(catalogStr.toString());
3079                                                queryBuf.append(quotedId);
3080 
3081                                                try {
3082                                                        results = stmt.executeQuery(queryBuf.toString());
3083                                                } catch (SQLException sqlEx) {
3084                                                        int errorCode = sqlEx.getErrorCode();
3085 
3086                                                        // If SQLState is 42S02, ignore this SQLException
3087                                                        // it means the table doesn't exist....
3088                                                        if (!"42S02".equals(sqlEx.getSQLState())) {
3089                                                                // Sometimes not mapped correctly for pre-4.1
3090                                                                // so use error code instead.
3091                                                                if (errorCode != MysqlErrorNumbers.ER_NO_SUCH_TABLE) {
3092                                                                        throw sqlEx;
3093                                                                }
3094                                                        }
3095                                                }
3096 
3097                                                while (results != null && results.next()) {
3098                                                        byte[][] row = new byte[14][];
3099                                                        row[0] = ((catalogStr.toString() == null) ? new byte[0]
3100                                                                        : s2b(catalogStr.toString()));
3101                                                        ;
3102                                                        row[1] = null;
3103                                                        row[2] = results.getBytes("Table");
3104 
3105                                                        boolean indexIsUnique = results
3106                                                                        .getInt("Non_unique") == 0;
3107 
3108                                                        row[3] = (!indexIsUnique ? s2b("true")
3109                                                                        : s2b("false"));
3110                                                        row[4] = new byte[0];
3111                                                        row[5] = results.getBytes("Key_name");
3112                                                        row[6] = Integer.toString(
3113                                                                        java.sql.DatabaseMetaData.tableIndexOther)
3114                                                                        .getBytes();
3115                                                        row[7] = results.getBytes("Seq_in_index");
3116                                                        row[8] = results.getBytes("Column_name");
3117                                                        row[9] = results.getBytes("Collation");
3118                                                        row[10] = results.getBytes("Cardinality");
3119                                                        row[11] = s2b("0");
3120                                                        row[12] = null;
3121 
3122                                                        if (unique) {
3123                                                                if (indexIsUnique) {
3124                                                                        rows.add(row);
3125                                                                }
3126                                                        } else {
3127                                                                // All rows match
3128                                                                rows.add(row);
3129                                                        }
3130                                                }
3131                                        } finally {
3132                                                if (results != null) {
3133                                                        try {
3134                                                                results.close();
3135                                                        } catch (Exception ex) {
3136                                                                ;
3137                                                        }
3138 
3139                                                        results = null;
3140                                                }
3141                                        }
3142                                }
3143                        }.doForAll();
3144 
3145                        java.sql.ResultSet indexInfo = buildResultSet(fields, rows);
3146 
3147                        return indexInfo;
3148                } finally {
3149                        if (stmt != null) {
3150                                stmt.close();
3151                        }
3152                }
3153        }
3154 
3155        /**
3156         * @see DatabaseMetaData#getJDBCMajorVersion()
3157         */
3158        public int getJDBCMajorVersion() throws SQLException {
3159                return 3;
3160        }
3161 
3162        /**
3163         * @see DatabaseMetaData#getJDBCMinorVersion()
3164         */
3165        public int getJDBCMinorVersion() throws SQLException {
3166                return 0;
3167        }
3168 
3169        /**
3170         * How many hex characters can you have in an inline binary literal?
3171         * 
3172         * @return max literal length
3173         * @throws SQLException
3174         *             DOCUMENT ME!
3175         */
3176        public int getMaxBinaryLiteralLength() throws SQLException {
3177                return 16777208;
3178        }
3179 
3180        /**
3181         * What's the maximum length of a catalog name?
3182         * 
3183         * @return max name length in bytes
3184         * @throws SQLException
3185         *             DOCUMENT ME!
3186         */
3187        public int getMaxCatalogNameLength() throws SQLException {
3188                return 32;
3189        }
3190 
3191        /**
3192         * What's the max length for a character literal?
3193         * 
3194         * @return max literal length
3195         * @throws SQLException
3196         *             DOCUMENT ME!
3197         */
3198        public int getMaxCharLiteralLength() throws SQLException {
3199                return 16777208;
3200        }
3201 
3202        /**
3203         * What's the limit on column name length?
3204         * 
3205         * @return max literal length
3206         * @throws SQLException
3207         *             DOCUMENT ME!
3208         */
3209        public int getMaxColumnNameLength() throws SQLException {
3210                return 64;
3211        }
3212 
3213        /**
3214         * What's the maximum number of columns in a "GROUP BY" clause?
3215         * 
3216         * @return max number of columns
3217         * @throws SQLException
3218         *             DOCUMENT ME!
3219         */
3220        public int getMaxColumnsInGroupBy() throws SQLException {
3221                return 64;
3222        }
3223 
3224        /**
3225         * What's the maximum number of columns allowed in an index?
3226         * 
3227         * @return max columns
3228         * @throws SQLException
3229         *             DOCUMENT ME!
3230         */
3231        public int getMaxColumnsInIndex() throws SQLException {
3232                return 16;
3233        }
3234 
3235        /**
3236         * What's the maximum number of columns in an "ORDER BY" clause?
3237         * 
3238         * @return max columns
3239         * @throws SQLException
3240         *             DOCUMENT ME!
3241         */
3242        public int getMaxColumnsInOrderBy() throws SQLException {
3243                return 64;
3244        }
3245 
3246        /**
3247         * What's the maximum number of columns in a "SELECT" list?
3248         * 
3249         * @return max columns
3250         * @throws SQLException
3251         *             DOCUMENT ME!
3252         */
3253        public int getMaxColumnsInSelect() throws SQLException {
3254                return 256;
3255        }
3256 
3257        /**
3258         * What's maximum number of columns in a table?
3259         * 
3260         * @return max columns
3261         * @throws SQLException
3262         *             DOCUMENT ME!
3263         */
3264        public int getMaxColumnsInTable() throws SQLException {
3265                return 512;
3266        }
3267 
3268        /**
3269         * How many active connections can we have at a time to this database?
3270         * 
3271         * @return max connections
3272         * @throws SQLException
3273         *             DOCUMENT ME!
3274         */
3275        public int getMaxConnections() throws SQLException {
3276                return 0;
3277        }
3278 
3279        /**
3280         * What's the maximum cursor name length?
3281         * 
3282         * @return max cursor name length in bytes
3283         * @throws SQLException
3284         *             DOCUMENT ME!
3285         */
3286        public int getMaxCursorNameLength() throws SQLException {
3287                return 64;
3288        }
3289 
3290        /**
3291         * What's the maximum length of an index (in bytes)?
3292         * 
3293         * @return max index length in bytes
3294         * @throws SQLException
3295         *             DOCUMENT ME!
3296         */
3297        public int getMaxIndexLength() throws SQLException {
3298                return 256;
3299        }
3300 
3301        /**
3302         * What's the maximum length of a procedure name?
3303         * 
3304         * @return max name length in bytes
3305         * @throws SQLException
3306         *             DOCUMENT ME!
3307         */
3308        public int getMaxProcedureNameLength() throws SQLException {
3309                return 0;
3310        }
3311 
3312        /**
3313         * What's the maximum length of a single row?
3314         * 
3315         * @return max row size in bytes
3316         * @throws SQLException
3317         *             DOCUMENT ME!
3318         */
3319        public int getMaxRowSize() throws SQLException {
3320                return Integer.MAX_VALUE - 8; // Max buffer size - HEADER
3321        }
3322 
3323        /**
3324         * What's the maximum length allowed for a schema name?
3325         * 
3326         * @return max name length in bytes
3327         * @throws SQLException
3328         *             DOCUMENT ME!
3329         */
3330        public int getMaxSchemaNameLength() throws SQLException {
3331                return 0;
3332        }
3333 
3334        /**
3335         * What's the maximum length of a SQL statement?
3336         * 
3337         * @return max length in bytes
3338         * @throws SQLException
3339         *             DOCUMENT ME!
3340         */
3341        public int getMaxStatementLength() throws SQLException {
3342                return MysqlIO.getMaxBuf() - 4; // Max buffer - header
3343        }
3344 
3345        /**
3346         * How many active statements can we have open at one time to this database?
3347         * 
3348         * @return the maximum
3349         * @throws SQLException
3350         *             DOCUMENT ME!
3351         */
3352        public int getMaxStatements() throws SQLException {
3353                return 0;
3354        }
3355 
3356        /**
3357         * What's the maximum length of a table name?
3358         * 
3359         * @return max name length in bytes
3360         * @throws SQLException
3361         *             DOCUMENT ME!
3362         */
3363        public int getMaxTableNameLength() throws SQLException {
3364                return 64;
3365        }
3366 
3367        /**
3368         * What's the maximum number of tables in a SELECT?
3369         * 
3370         * @return the maximum
3371         * @throws SQLException
3372         *             DOCUMENT ME!
3373         */
3374        public int getMaxTablesInSelect() throws SQLException {
3375                return 256;
3376        }
3377 
3378        /**
3379         * What's the maximum length of a user name?
3380         * 
3381         * @return max name length in bytes
3382         * @throws SQLException
3383         *             DOCUMENT ME!
3384         */
3385        public int getMaxUserNameLength() throws SQLException {
3386                return 16;
3387        }
3388 
3389        /**
3390         * Get a comma separated list of math functions.
3391         * 
3392         * @return the list
3393         * @throws SQLException
3394         *             DOCUMENT ME!
3395         */
3396        public String getNumericFunctions() throws SQLException {
3397                return "ABS,ACOS,ASIN,ATAN,ATAN2,BIT_COUNT,CEILING,COS,"
3398                                + "COT,DEGREES,EXP,FLOOR,LOG,LOG10,MAX,MIN,MOD,PI,POW,"
3399                                + "POWER,RADIANS,RAND,ROUND,SIN,SQRT,TAN,TRUNCATE";
3400        }
3401 
3402        /**
3403         * Get a description of a table's primary key columns. They are ordered by
3404         * COLUMN_NAME.
3405         * <P>
3406         * Each column description has the following columns:
3407         * <OL>
3408         * <li> <B>TABLE_CAT</B> String => table catalog (may be null) </li>
3409         * <li> <B>TABLE_SCHEM</B> String => table schema (may be null) </li>
3410         * <li> <B>TABLE_NAME</B> String => table name </li>
3411         * <li> <B>COLUMN_NAME</B> String => column name </li>
3412         * <li> <B>KEY_SEQ</B> short => sequence number within primary key </li>
3413         * <li> <B>PK_NAME</B> String => primary key name (may be null) </li>
3414         * </ol>
3415         * </p>
3416         * 
3417         * @param catalog
3418         *            a catalog name; "" retrieves those without a catalog
3419         * @param schema
3420         *            a schema name pattern; "" retrieves those without a schema
3421         * @param table
3422         *            a table name
3423         * @return ResultSet each row is a primary key column description
3424         * @throws SQLException
3425         *             DOCUMENT ME!
3426         */
3427        public java.sql.ResultSet getPrimaryKeys(String catalog, String schema,
3428                        final String table) throws SQLException {
3429                Field[] fields = new Field[6];
3430                fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 255);
3431                fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 0);
3432                fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 255);
3433                fields[3] = new Field("", "COLUMN_NAME", Types.CHAR, 32);
3434                fields[4] = new Field("", "KEY_SEQ", Types.SMALLINT, 5);
3435                fields[5] = new Field("", "PK_NAME", Types.CHAR, 32);
3436 
3437                if (table == null) {
3438                        throw SQLError.createSQLException("Table not specified.",
3439                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
3440                }
3441 
3442                final ArrayList rows = new ArrayList();
3443                final Statement stmt = this.conn.getMetadataSafeStatement();
3444 
3445                try {
3446 
3447                        new IterateBlock(getCatalogIterator(catalog)) {
3448                                void forEach(Object catalogStr) throws SQLException {
3449                                        ResultSet rs = null;
3450 
3451                                        try {
3452 
3453                                                StringBuffer queryBuf = new StringBuffer(
3454                                                                "SHOW KEYS FROM ");
3455                                                queryBuf.append(quotedId);
3456                                                queryBuf.append(table);
3457                                                queryBuf.append(quotedId);
3458                                                queryBuf.append(" FROM ");
3459                                                queryBuf.append(quotedId);
3460                                                queryBuf.append(catalogStr.toString());
3461                                                queryBuf.append(quotedId);
3462 
3463                                                rs = stmt.executeQuery(queryBuf.toString());
3464 
3465                                                ArrayList tuples = new ArrayList();
3466                                                TreeMap sortMap = new TreeMap();
3467 
3468                                                while (rs.next()) {
3469                                                        String keyType = rs.getString("Key_name");
3470 
3471                                                        if (keyType != null) {
3472                                                                if (keyType.equalsIgnoreCase("PRIMARY")
3473                                                                                || keyType.equalsIgnoreCase("PRI")) {
3474                                                                        byte[][] tuple = new byte[6][];
3475                                                                        tuple[0] = ((catalogStr.toString() == null) ? new byte[0]
3476                                                                                        : s2b(catalogStr.toString()));
3477                                                                        tuple[1] = null;
3478                                                                        tuple[2] = s2b(table);
3479 
3480                                                                        String columnName = rs
3481                                                                                        .getString("Column_name");
3482                                                                        tuple[3] = s2b(columnName);
3483                                                                        tuple[4] = s2b(rs.getString("Seq_in_index"));
3484                                                                        tuple[5] = s2b(keyType);
3485                                                                        sortMap.put(columnName, tuple);
3486                                                                }
3487                                                        }
3488                                                }
3489 
3490                                                // Now pull out in column name sorted order
3491                                                Iterator sortedIterator = sortMap.values().iterator();
3492 
3493                                                while (sortedIterator.hasNext()) {
3494                                                        rows.add(sortedIterator.next());
3495                                                }
3496 
3497                                        } finally {
3498                                                if (rs != null) {
3499                                                        try {
3500                                                                rs.close();
3501                                                        } catch (Exception ex) {
3502                                                                ;
3503                                                        }
3504 
3505                                                        rs = null;
3506                                                }
3507                                        }
3508                                }
3509                        }.doForAll();
3510                } finally {
3511                        if (stmt != null) {
3512                                stmt.close();
3513                        }
3514                }
3515 
3516                java.sql.ResultSet results = buildResultSet(fields, rows);
3517 
3518                return results;
3519        }
3520 
3521        /**
3522         * Get a description of a catalog's stored procedure parameters and result
3523         * columns.
3524         * <P>
3525         * Only descriptions matching the schema, procedure and parameter name
3526         * criteria are returned. They are ordered by PROCEDURE_SCHEM and
3527         * PROCEDURE_NAME. Within this, the return value, if any, is first. Next are
3528         * the parameter descriptions in call order. The column descriptions follow
3529         * in column number order.
3530         * </p>
3531         * <P>
3532         * Each row in the ResultSet is a parameter desription or column description
3533         * with the following fields:
3534         * <OL>
3535         * <li> <B>PROCEDURE_CAT</B> String => procedure catalog (may be null)
3536         * </li>
3537         * <li> <B>PROCEDURE_SCHEM</B> String => procedure schema (may be null)
3538         * </li>
3539         * <li> <B>PROCEDURE_NAME</B> String => procedure name </li>
3540         * <li> <B>COLUMN_NAME</B> String => column/parameter name </li>
3541         * <li> <B>COLUMN_TYPE</B> Short => kind of column/parameter:
3542         * <UL>
3543         * <li> procedureColumnUnknown - nobody knows </li>
3544         * <li> procedureColumnIn - IN parameter </li>
3545         * <li> procedureColumnInOut - INOUT parameter </li>
3546         * <li> procedureColumnOut - OUT parameter </li>
3547         * <li> procedureColumnReturn - procedure return value </li>
3548         * <li> procedureColumnResult - result column in ResultSet </li>
3549         * </ul>
3550         * </li>
3551         * <li> <B>DATA_TYPE</B> short => SQL type from java.sql.Types </li>
3552         * <li> <B>TYPE_NAME</B> String => SQL type name </li>
3553         * <li> <B>PRECISION</B> int => precision </li>
3554         * <li> <B>LENGTH</B> int => length in bytes of data </li>
3555         * <li> <B>SCALE</B> short => scale </li>
3556         * <li> <B>RADIX</B> short => radix </li>
3557         * <li> <B>NULLABLE</B> short => can it contain NULL?
3558         * <UL>
3559         * <li> procedureNoNulls - does not allow NULL values </li>
3560         * <li> procedureNullable - allows NULL values </li>
3561         * <li> procedureNullableUnknown - nullability unknown </li>
3562         * </ul>
3563         * </li>
3564         * <li> <B>REMARKS</B> String => comment describing parameter/column </li>
3565         * </ol>
3566         * </p>
3567         * <P>
3568         * <B>Note:</B> Some databases may not return the column descriptions for a
3569         * procedure. Additional columns beyond REMARKS can be defined by the
3570         * database.
3571         * </p>
3572         * 
3573         * @param catalog
3574         *            a catalog name; "" retrieves those without a catalog
3575         * @param schemaPattern
3576         *            a schema name pattern; "" retrieves those without a schema
3577         * @param procedureNamePattern
3578         *            a procedure name pattern
3579         * @param columnNamePattern
3580         *            a column name pattern
3581         * @return ResultSet each row is a stored procedure parameter or column
3582         *         description
3583         * @throws SQLException
3584         *             if a database access error occurs
3585         * @see #getSearchStringEscape
3586         */
3587        public java.sql.ResultSet getProcedureColumns(String catalog,
3588                        String schemaPattern, String procedureNamePattern,
3589                        String columnNamePattern) throws SQLException {
3590 
3591                Field[] fields = new Field[13];
3592 
3593                fields[0] = new Field("", "PROCEDURE_CAT", Types.CHAR, 0);
3594                fields[1] = new Field("", "PROCEDURE_SCHEM", Types.CHAR, 0);
3595                fields[2] = new Field("", "PROCEDURE_NAME", Types.CHAR, 0);
3596                fields[3] = new Field("", "COLUMN_NAME", Types.CHAR, 0);
3597                fields[4] = new Field("", "COLUMN_TYPE", Types.CHAR, 0);
3598                fields[5] = new Field("", "DATA_TYPE", Types.SMALLINT, 0);
3599                fields[6] = new Field("", "TYPE_NAME", Types.CHAR, 0);
3600                fields[7] = new Field("", "PRECISION", Types.INTEGER, 0);
3601                fields[8] = new Field("", "LENGTH", Types.INTEGER, 0);
3602                fields[9] = new Field("", "SCALE", Types.SMALLINT, 0);
3603                fields[10] = new Field("", "RADIX", Types.SMALLINT, 0);
3604                fields[11] = new Field("", "NULLABLE", Types.SMALLINT, 0);
3605                fields[12] = new Field("", "REMARKS", Types.CHAR, 0);
3606 
3607                List proceduresToExtractList = new ArrayList();
3608 
3609                if (supportsStoredProcedures()) {
3610                        if ((procedureNamePattern.indexOf("%") == -1)
3611                                        && (procedureNamePattern.indexOf("?") == -1)) {
3612                                proceduresToExtractList.add(procedureNamePattern);
3613                        } else {
3614                                PreparedStatement procedureNameStmt = null;
3615                                ResultSet procedureNameRs = null;
3616 
3617                                try {
3618 
3619                                        procedureNameRs = getProcedures(catalog, schemaPattern,
3620                                                        procedureNamePattern);
3621 
3622                                        while (procedureNameRs.next()) {
3623                                                proceduresToExtractList.add(procedureNameRs
3624                                                                .getString(3));
3625                                        }
3626 
3627                                        // Required to be sorted in name-order by JDBC spec,
3628                                        // in 'normal' case getProcedures takes care of this for us,
3629                                        // but if system tables are inaccessible, we need to sort...
3630                                        // so just do this to be safe...
3631                                        Collections.sort(proceduresToExtractList);
3632                                } finally {
3633                                        SQLException rethrowSqlEx = null;
3634 
3635                                        if (procedureNameRs != null) {
3636                                                try {
3637                                                        procedureNameRs.close();
3638                                                } catch (SQLException sqlEx) {
3639                                                        rethrowSqlEx = sqlEx;
3640                                                }
3641                                        }
3642 
3643                                        if (procedureNameStmt != null) {
3644                                                try {
3645                                                        procedureNameStmt.close();
3646                                                } catch (SQLException sqlEx) {
3647                                                        rethrowSqlEx = sqlEx;
3648                                                }
3649                                        }
3650 
3651                                        if (rethrowSqlEx != null) {
3652                                                throw rethrowSqlEx;
3653                                        }
3654                                }
3655                        }
3656                }
3657 
3658                ArrayList resultRows = new ArrayList();
3659 
3660                for (Iterator iter = proceduresToExtractList.iterator(); iter.hasNext();) {
3661                        String procName = (String) iter.next();
3662 
3663                        getCallStmtParameterTypes(catalog, procName, columnNamePattern,
3664                                        resultRows);
3665                }
3666 
3667                return buildResultSet(fields, resultRows);
3668        }
3669 
3670        /**
3671         * Get a description of stored procedures available in a catalog.
3672         * <P>
3673         * Only procedure descriptions matching the schema and procedure name
3674         * criteria are returned. They are ordered by PROCEDURE_SCHEM, and
3675         * PROCEDURE_NAME.
3676         * </p>
3677         * <P>
3678         * Each procedure description has the the following columns:
3679         * <OL>
3680         * <li> <B>PROCEDURE_CAT</B> String => procedure catalog (may be null)
3681         * </li>
3682         * <li> <B>PROCEDURE_SCHEM</B> String => procedure schema (may be null)
3683         * </li>
3684         * <li> <B>PROCEDURE_NAME</B> String => procedure name </li>
3685         * <li> reserved for future use </li>
3686         * <li> reserved for future use </li>
3687         * <li> reserved for future use </li>
3688         * <li> <B>REMARKS</B> String => explanatory comment on the procedure </li>
3689         * <li> <B>PROCEDURE_TYPE</B> short => kind of procedure:
3690         * <UL>
3691         * <li> procedureResultUnknown - May return a result </li>
3692         * <li> procedureNoResult - Does not return a result </li>
3693         * <li> procedureReturnsResult - Returns a result </li>
3694         * </ul>
3695         * </li>
3696         * </ol>
3697         * </p>
3698         * 
3699         * @param catalog
3700         *            a catalog name; "" retrieves those without a catalog
3701         * @param schemaPattern
3702         *            a schema name pattern; "" retrieves those without a schema
3703         * @param procedureNamePattern
3704         *            a procedure name pattern
3705         * @return ResultSet each row is a procedure description
3706         * @throws SQLException
3707         *             if a database access error occurs
3708         * @see #getSearchStringEscape
3709         */
3710        public java.sql.ResultSet getProcedures(String catalog,
3711                        String schemaPattern, String procedureNamePattern)
3712                        throws SQLException {
3713                if ((procedureNamePattern == null)
3714                                || (procedureNamePattern.length() == 0)) {
3715                        if (this.conn.getNullNamePatternMatchesAll()) {
3716                                procedureNamePattern = "%";
3717                        } else {
3718                                throw SQLError.createSQLException(
3719                                                "Procedure name pattern can not be NULL or empty.",
3720                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
3721                        }
3722                }
3723 
3724                Field[] fields = new Field[8];
3725                fields[0] = new Field("", "PROCEDURE_CAT", Types.CHAR, 0);
3726                fields[1] = new Field("", "PROCEDURE_SCHEM", Types.CHAR, 0);
3727                fields[2] = new Field("", "PROCEDURE_NAME", Types.CHAR, 0);
3728                fields[3] = new Field("", "reserved1", Types.CHAR, 0);
3729                fields[4] = new Field("", "reserved2", Types.CHAR, 0);
3730                fields[5] = new Field("", "reserved3", Types.CHAR, 0);
3731                fields[6] = new Field("", "REMARKS", Types.CHAR, 0);
3732                fields[7] = new Field("", "PROCEDURE_TYPE", Types.SMALLINT, 0);
3733 
3734                final ArrayList procedureRows = new ArrayList();
3735 
3736                if (supportsStoredProcedures()) {
3737                        final String procNamePattern = procedureNamePattern;
3738 
3739                        final Map procedureRowsOrderedByName = new TreeMap();
3740 
3741                        new IterateBlock(getCatalogIterator(catalog)) {
3742                                void forEach(Object catalogStr) throws SQLException {
3743                                        String db = catalogStr.toString();
3744 
3745                                        boolean fromSelect = false;
3746                                        ResultSet proceduresRs = null;
3747                                        boolean needsClientFiltering = true;
3748                                        PreparedStatement proceduresStmt = conn
3749                                                        .clientPrepareStatement("SELECT name, type FROM mysql.proc WHERE name like ? and db <=> ? ORDER BY name");
3750 
3751                                        try {
3752                                                //
3753                                                // Try using system tables first, as this is a little
3754                                                // bit more efficient....
3755                                                //
3756 
3757                                                boolean hasTypeColumn = false;
3758 
3759                                                if (db != null) {
3760                                                        proceduresStmt.setString(2, db);
3761                                                } else {
3762                                                        proceduresStmt.setNull(2, Types.VARCHAR);
3763                                                }
3764 
3765                                                int nameIndex = 1;
3766 
3767                                                if (proceduresStmt.getMaxRows() != 0) {
3768                                                        proceduresStmt.setMaxRows(0);
3769                                                }
3770 
3771                                                proceduresStmt.setString(1, procNamePattern);
3772 
3773                                                try {
3774                                                        proceduresRs = proceduresStmt.executeQuery();
3775                                                        fromSelect = true;
3776                                                        needsClientFiltering = false;
3777                                                        hasTypeColumn = true;
3778                                                } catch (SQLException sqlEx) {
3779 
3780                                                        //
3781                                                        // Okay, system tables aren't accessible, so use
3782                                                        // 'SHOW
3783                                                        // ....'....
3784                                                        //
3785                                                        proceduresStmt.close();
3786 
3787                                                        fromSelect = false;
3788 
3789                                                        if (conn.versionMeetsMinimum(5, 0, 1)) {
3790                                                                nameIndex = 2;
3791                                                        } else {
3792                                                                nameIndex = 1;
3793                                                        }
3794 
3795                                                        proceduresStmt = conn
3796                                                                        .clientPrepareStatement("SHOW PROCEDURE STATUS LIKE ?");
3797 
3798                                                        if (proceduresStmt.getMaxRows() != 0) {
3799                                                                proceduresStmt.setMaxRows(0);
3800                                                        }
3801 
3802                                                        proceduresStmt.setString(1, procNamePattern);
3803 
3804                                                        proceduresRs = proceduresStmt.executeQuery();
3805                                                }
3806 
3807                                                convertToJdbcProcedureList(fromSelect, db,
3808                                                                proceduresRs, needsClientFiltering, db,
3809                                                                procedureRowsOrderedByName, nameIndex);
3810 
3811                                                if (!hasTypeColumn) {
3812                                                        // need to go after functions too...
3813                                                        if (proceduresStmt != null) {
3814                                                                proceduresStmt.close();
3815                                                        }
3816 
3817                                                        proceduresStmt = conn
3818                                                                        .clientPrepareStatement("SHOW FUNCTION STATUS LIKE ?");
3819 
3820                                                        if (proceduresStmt.getMaxRows() != 0) {
3821                                                                proceduresStmt.setMaxRows(0);
3822                                                        }
3823 
3824                                                        proceduresStmt.setString(1, procNamePattern);
3825 
3826                                                        proceduresRs = proceduresStmt.executeQuery();
3827 
3828                                                        convertToJdbcFunctionList(db, proceduresRs,
3829                                                                        needsClientFiltering, db,
3830                                                                        procedureRowsOrderedByName, nameIndex);
3831 
3832                                                }
3833 
3834                                                // Now, sort them
3835 
3836                                                Iterator proceduresIter = procedureRowsOrderedByName
3837                                                                .values().iterator();
3838 
3839                                                while (proceduresIter.hasNext()) {
3840                                                        procedureRows.add(proceduresIter.next());
3841                                                }
3842                                        } finally {
3843                                                SQLException rethrowSqlEx = null;
3844 
3845                                                if (proceduresRs != null) {
3846                                                        try {
3847                                                                proceduresRs.close();
3848                                                        } catch (SQLException sqlEx) {
3849                                                                rethrowSqlEx = sqlEx;
3850                                                        }
3851                                                }
3852 
3853                                                if (proceduresStmt != null) {
3854                                                        try {
3855                                                                proceduresStmt.close();
3856                                                        } catch (SQLException sqlEx) {
3857                                                                rethrowSqlEx = sqlEx;
3858                                                        }
3859                                                }
3860 
3861                                                if (rethrowSqlEx != null) {
3862                                                        throw rethrowSqlEx;
3863                                                }
3864                                        }
3865                                }
3866                        }.doForAll();
3867                }
3868 
3869                return buildResultSet(fields, procedureRows);
3870        }
3871 
3872        /**
3873         * What's the database vendor's preferred term for "procedure"?
3874         * 
3875         * @return the vendor term
3876         * @throws SQLException
3877         *             if an error occurs (don't know why it would in this case...)
3878         */
3879        public String getProcedureTerm() throws SQLException {
3880                return "PROCEDURE";
3881        }
3882 
3883        /**
3884         * @see DatabaseMetaData#getResultSetHoldability()
3885         */
3886        public int getResultSetHoldability() throws SQLException {
3887                return ResultSet.HOLD_CURSORS_OVER_COMMIT;
3888        }
3889 
3890        private void getResultsImpl(String catalog, String table,
3891                        String keysComment, List tuples, String fkTableName,
3892                        boolean isExport) throws SQLException {
3893 
3894                LocalAndReferencedColumns parsedInfo = parseTableStatusIntoLocalAndReferencedColumns(keysComment);
3895 
3896                if (isExport && !parsedInfo.referencedTable.equals(table)) {
3897                        return;
3898                }
3899 
3900                if (parsedInfo.localColumnsList.size() != parsedInfo.referencedColumnsList
3901                                .size()) {
3902                        throw SQLError.createSQLException(
3903                                        "Error parsing foreign keys definition,"
3904                                                        + "number of local and referenced columns is not the same.",
3905                                        SQLError.SQL_STATE_GENERAL_ERROR);
3906                }
3907 
3908                Iterator localColumnNames = parsedInfo.localColumnsList.iterator();
3909                Iterator referColumnNames = parsedInfo.referencedColumnsList.iterator();
3910 
3911                int keySeqIndex = 1;
3912 
3913                while (localColumnNames.hasNext()) {
3914                        byte[][] tuple = new byte[14][];
3915                        String lColumnName = removeQuotedId(localColumnNames.next()
3916                                        .toString());
3917                        String rColumnName = removeQuotedId(referColumnNames.next()
3918                                        .toString());
3919                        tuple[FKTABLE_CAT] = ((catalog == null) ? new byte[0]
3920                                        : s2b(catalog));
3921                        tuple[FKTABLE_SCHEM] = null;
3922                        tuple[FKTABLE_NAME] = s2b((isExport) ? fkTableName : table);
3923                        tuple[FKCOLUMN_NAME] = s2b(lColumnName);
3924                        tuple[PKTABLE_CAT] = s2b(parsedInfo.referencedCatalog);
3925                        tuple[PKTABLE_SCHEM] = null;
3926                        tuple[PKTABLE_NAME] = s2b((isExport) ? table
3927                                        : parsedInfo.referencedTable);
3928                        tuple[PKCOLUMN_NAME] = s2b(rColumnName);
3929                        tuple[KEY_SEQ] = s2b(Integer.toString(keySeqIndex++));
3930 
3931                        int[] actions = getForeignKeyActions(keysComment);
3932 
3933                        tuple[UPDATE_RULE] = s2b(Integer.toString(actions[1]));
3934                        tuple[DELETE_RULE] = s2b(Integer.toString(actions[0]));
3935                        tuple[FK_NAME] = s2b(parsedInfo.constraintName);
3936                        tuple[PK_NAME] = null; // not available from show table status
3937                        tuple[DEFERRABILITY] = s2b(Integer
3938                                        .toString(java.sql.DatabaseMetaData.importedKeyNotDeferrable));
3939                        tuples.add(tuple);
3940                }
3941        }
3942 
3943        /**
3944         * Get the schema names available in this database. The results are ordered
3945         * by schema name.
3946         * <P>
3947         * The schema column is:
3948         * <OL>
3949         * <li> <B>TABLE_SCHEM</B> String => schema name </li>
3950         * </ol>
3951         * </p>
3952         * 
3953         * @return ResultSet each row has a single String column that is a schema
3954         *         name
3955         * @throws SQLException
3956         *             DOCUMENT ME!
3957         */
3958        public java.sql.ResultSet getSchemas() throws SQLException {
3959                Field[] fields = new Field[1];
3960                fields[0] = new Field("", "TABLE_SCHEM", java.sql.Types.CHAR, 0);
3961 
3962                ArrayList tuples = new ArrayList();
3963                java.sql.ResultSet results = buildResultSet(fields, tuples);
3964 
3965                return results;
3966        }
3967 
3968        /**
3969         * What's the database vendor's preferred term for "schema"?
3970         * 
3971         * @return the vendor term
3972         * @throws SQLException
3973         *             DOCUMENT ME!
3974         */
3975        public String getSchemaTerm() throws SQLException {
3976                return "";
3977        }
3978 
3979        /**
3980         * This is the string that can be used to escape '_' or '%' in the string
3981         * pattern style catalog search parameters.
3982         * <P>
3983         * The '_' character represents any single character.
3984         * </p>
3985         * <P>
3986         * The '%' character represents any sequence of zero or more characters.
3987         * </p>
3988         * 
3989         * @return the string used to escape wildcard characters
3990         * @throws SQLException
3991         *             DOCUMENT ME!
3992         */
3993        public String getSearchStringEscape() throws SQLException {
3994                return "\\";
3995        }
3996 
3997        /**
3998         * Get a comma separated list of all a database's SQL keywords that are NOT
3999         * also SQL92 keywords.
4000         * 
4001         * @return the list
4002         * @throws SQLException
4003         *             DOCUMENT ME!
4004         */
4005        public String getSQLKeywords() throws SQLException {
4006                return "AUTO_INCREMENT,BINARY,BLOB,ENUM,INFILE,LOAD,MEDIUMINT,OPTION,OUTFILE,REPLACE,SET,TEXT,UNSIGNED,ZEROFILL";
4007 
4008                /*
4009                 * [20:44] root@test> select GROUP_CONCAT(reserved.a) from reserved left
4010                 * join sql92 on (reserved.a=sql92.a) where sql92.a IS NULL GROUP BY
4011                 * (reserved.b) \G ************************** 1. row
4012                 * *************************** GROUP_CONCAT(reserved.a):
4013                 * RETURN,REQUIRE,REPLACE,REPEAT,RENAME,
4014                 * REGEXP,PURGE,SPECIFIC,SPATIAL,SONAME,SHOW,SEPARATOR,SENSITIVE,
4015                 * SECOND_MICROSECOND,RLIKE,MOD,MINUTE_SECOND,MINUTE_MICROSECOND,
4016                 * MIDDLEINT,MEDIUMTEXT,MEDIUMINT,MEDIUMBLOB,MASTER_SERVER_ID,
4017                 * LOW_PRIORITY,LOOP,LONGTEXT,OUTFILE,OUT,OPTIONALLY,OPTIMIZE,
4018                 * NO_WRITE_TO_BINLOG,LONGBLOB,ZEROFILL,UTC_DATE,USER_RESOURCES,USE,
4019                 * UNSIGNED,UNLOCK,UNDO,UTC_TIME,UTC_TIMESTAMP,YEAR_MONTH,XOR,WHILE,
4020                 * VARCHARACTER,VARBINARY,TINYTEXT,SQL_T
4021                 */
4022        }
4023 
4024        /**
4025         * @see DatabaseMetaData#getSQLStateType()
4026         */
4027        public int getSQLStateType() throws SQLException {
4028                if (this.conn.versionMeetsMinimum(4, 1, 0)) {
4029                        return DatabaseMetaData.sqlStateSQL99;
4030                }
4031 
4032                if (this.conn.getUseSqlStateCodes()) {
4033                        return DatabaseMetaData.sqlStateSQL99;
4034                }
4035 
4036                return DatabaseMetaData.sqlStateXOpen;
4037        }
4038 
4039        /**
4040         * Get a comma separated list of string functions.
4041         * 
4042         * @return the list
4043         * @throws SQLException
4044         *             DOCUMENT ME!
4045         */
4046        public String getStringFunctions() throws SQLException {
4047                return "ASCII,BIN,BIT_LENGTH,CHAR,CHARACTER_LENGTH,CHAR_LENGTH,CONCAT,"
4048                                + "CONCAT_WS,CONV,ELT,EXPORT_SET,FIELD,FIND_IN_SET,HEX,INSERT,"
4049                                + "INSTR,LCASE,LEFT,LENGTH,LOAD_FILE,LOCATE,LOCATE,LOWER,LPAD,"
4050                                + "LTRIM,MAKE_SET,MATCH,MID,OCT,OCTET_LENGTH,ORD,POSITION,"
4051                                + "QUOTE,REPEAT,REPLACE,REVERSE,RIGHT,RPAD,RTRIM,SOUNDEX,"
4052                                + "SPACE,STRCMP,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING,"
4053                                + "SUBSTRING_INDEX,TRIM,UCASE,UPPER";
4054        }
4055 
4056        /**
4057         * @see DatabaseMetaData#getSuperTables(String, String, String)
4058         */
4059        public java.sql.ResultSet getSuperTables(String arg0, String arg1,
4060                        String arg2) throws SQLException {
4061                Field[] fields = new Field[4];
4062                fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 32);
4063                fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 32);
4064                fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 32);
4065                fields[3] = new Field("", "SUPERTABLE_NAME", Types.CHAR, 32);
4066 
4067                return buildResultSet(fields, new ArrayList());
4068        }
4069 
4070        /**
4071         * @see DatabaseMetaData#getSuperTypes(String, String, String)
4072         */
4073        public java.sql.ResultSet getSuperTypes(String arg0, String arg1,
4074                        String arg2) throws SQLException {
4075                Field[] fields = new Field[6];
4076                fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 32);
4077                fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 32);
4078                fields[2] = new Field("", "TYPE_NAME", Types.CHAR, 32);
4079                fields[3] = new Field("", "SUPERTYPE_CAT", Types.CHAR, 32);
4080                fields[4] = new Field("", "SUPERTYPE_SCHEM", Types.CHAR, 32);
4081                fields[5] = new Field("", "SUPERTYPE_NAME", Types.CHAR, 32);
4082 
4083                return buildResultSet(fields, new ArrayList());
4084        }
4085 
4086        /**
4087         * Get a comma separated list of system functions.
4088         * 
4089         * @return the list
4090         * @throws SQLException
4091         *             DOCUMENT ME!
4092         */
4093        public String getSystemFunctions() throws SQLException {
4094                return "DATABASE,USER,SYSTEM_USER,SESSION_USER,PASSWORD,ENCRYPT,LAST_INSERT_ID,VERSION";
4095        }
4096 
4097        private String getTableNameWithCase(String table) {
4098                String tableNameWithCase = (this.conn.lowerCaseTableNames() ? table
4099                                .toLowerCase() : table);
4100 
4101                return tableNameWithCase;
4102        }
4103 
4104        /**
4105         * Get a description of the access rights for each table available in a
4106         * catalog.
4107         * <P>
4108         * Only privileges matching the schema and table name criteria are returned.
4109         * They are ordered by TABLE_SCHEM, TABLE_NAME, and PRIVILEGE.
4110         * </p>
4111         * <P>
4112         * Each privilige description has the following columns:
4113         * <OL>
4114         * <li> <B>TABLE_CAT</B> String => table catalog (may be null) </li>
4115         * <li> <B>TABLE_SCHEM</B> String => table schema (may be null) </li>
4116         * <li> <B>TABLE_NAME</B> String => table name </li>
4117         * <li> <B>COLUMN_NAME</B> String => column name </li>
4118         * <li> <B>GRANTOR</B> => grantor of access (may be null) </li>
4119         * <li> <B>GRANTEE</B> String => grantee of access </li>
4120         * <li> <B>PRIVILEGE</B> String => name of access (SELECT, INSERT, UPDATE,
4121         * REFRENCES, ...) </li>
4122         * <li> <B>IS_GRANTABLE</B> String => "YES" if grantee is permitted to
4123         * grant to others; "NO" if not; null if unknown </li>
4124         * </ol>
4125         * </p>
4126         * 
4127         * @param catalog
4128         *            a catalog name; "" retrieves those without a catalog
4129         * @param schemaPattern
4130         *            a schema name pattern; "" retrieves those without a schema
4131         * @param tableNamePattern
4132         *            a table name pattern
4133         * @return ResultSet each row is a table privilege description
4134         * @throws SQLException
4135         *             if a database access error occurs
4136         * @see #getSearchStringEscape
4137         */
4138        public java.sql.ResultSet getTablePrivileges(String catalog,
4139                        String schemaPattern, String tableNamePattern) throws SQLException {
4140 
4141                if (tableNamePattern == null) {
4142                        if (this.conn.getNullNamePatternMatchesAll()) {
4143                                tableNamePattern = "%";
4144                        } else {
4145                                throw SQLError.createSQLException(
4146                                                "Table name pattern can not be NULL or empty.",
4147                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
4148                        }
4149                }
4150 
4151                Field[] fields = new Field[7];
4152                fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 64);
4153                fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 1);
4154                fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 64);
4155                fields[3] = new Field("", "GRANTOR", Types.CHAR, 77);
4156                fields[4] = new Field("", "GRANTEE", Types.CHAR, 77);
4157                fields[5] = new Field("", "PRIVILEGE", Types.CHAR, 64);
4158                fields[6] = new Field("", "IS_GRANTABLE", Types.CHAR, 3);
4159 
4160                StringBuffer grantQuery = new StringBuffer(
4161                                "SELECT host,db,table_name,grantor,user,table_priv from mysql.tables_priv ");
4162                grantQuery.append(" WHERE ");
4163 
4164                if ((catalog != null) && (catalog.length() != 0)) {
4165                        grantQuery.append(" db='");
4166                        grantQuery.append(catalog);
4167                        grantQuery.append("' AND ");
4168                }
4169 
4170                grantQuery.append("table_name like '");
4171                grantQuery.append(tableNamePattern);
4172                grantQuery.append("'");
4173 
4174                ResultSet results = null;
4175                ArrayList grantRows = new ArrayList();
4176                Statement stmt = null;
4177 
4178                try {
4179                        stmt = this.conn.createStatement();
4180                        stmt.setEscapeProcessing(false);
4181 
4182                        results = stmt.executeQuery(grantQuery.toString());
4183 
4184                        while (results.next()) {
4185                                String host = results.getString(1);
4186                                String db = results.getString(2);
4187                                String table = results.getString(3);
4188                                String grantor = results.getString(4);
4189                                String user = results.getString(5);
4190 
4191                                if ((user == null) || (user.length() == 0)) {
4192                                        user = "%";
4193                                }
4194 
4195                                StringBuffer fullUser = new StringBuffer(user);
4196 
4197                                if ((host != null) && this.conn.getUseHostsInPrivileges()) {
4198                                        fullUser.append("@");
4199                                        fullUser.append(host);
4200                                }
4201 
4202                                String allPrivileges = results.getString(6);
4203 
4204                                if (allPrivileges != null) {
4205                                        allPrivileges = allPrivileges.toUpperCase(Locale.ENGLISH);
4206 
4207                                        StringTokenizer st = new StringTokenizer(allPrivileges, ",");
4208 
4209                                        while (st.hasMoreTokens()) {
4210                                                String privilege = st.nextToken().trim();
4211 
4212                                                // Loop through every column in the table
4213                                                java.sql.ResultSet columnResults = null;
4214 
4215                                                try {
4216                                                        columnResults = getColumns(catalog, schemaPattern,
4217                                                                        table, "%");
4218 
4219                                                        while (columnResults.next()) {
4220                                                                byte[][] tuple = new byte[8][];
4221                                                                tuple[0] = s2b(db);
4222                                                                tuple[1] = null;
4223                                                                tuple[2] = s2b(table);
4224 
4225                                                                if (grantor != null) {
4226                                                                        tuple[3] = s2b(grantor);
4227                                                                } else {
4228                                                                        tuple[3] = null;
4229                                                                }
4230 
4231                                                                tuple[4] = s2b(fullUser.toString());
4232                                                                tuple[5] = s2b(privilege);
4233                                                                tuple[6] = null;
4234                                                                grantRows.add(tuple);
4235                                                        }
4236                                                } finally {
4237                                                        if (columnResults != null) {
4238                                                                try {
4239                                                                        columnResults.close();
4240                                                                } catch (Exception ex) {
4241                                                                        ;
4242                                                                }
4243                                                        }
4244                                                }
4245                                        }
4246                                }
4247                        }
4248                } finally {
4249                        if (results != null) {
4250                                try {
4251                                        results.close();
4252                                } catch (Exception ex) {
4253                                        ;
4254                                }
4255 
4256                                results = null;
4257                        }
4258 
4259                        if (stmt != null) {
4260                                try {
4261                                        stmt.close();
4262                                } catch (Exception ex) {
4263                                        ;
4264                                }
4265 
4266                                stmt = null;
4267                        }
4268                }
4269 
4270                return buildResultSet(fields, grantRows);
4271        }
4272 
4273        /**
4274         * Get a description of tables available in a catalog.
4275         * <P>
4276         * Only table descriptions matching the catalog, schema, table name and type
4277         * criteria are returned. They are ordered by TABLE_TYPE, TABLE_SCHEM and
4278         * TABLE_NAME.
4279         * </p>
4280         * <P>
4281         * Each table description has the following columns:
4282         * <OL>
4283         * <li> <B>TABLE_CAT</B> String => table catalog (may be null) </li>
4284         * <li> <B>TABLE_SCHEM</B> String => table schema (may be null) </li>
4285         * <li> <B>TABLE_NAME</B> String => table name </li>
4286         * <li> <B>TABLE_TYPE</B> String => table type. Typical types are "TABLE",
4287         * "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS",
4288         * "SYNONYM". </li>
4289         * <li> <B>REMARKS</B> String => explanatory comment on the table </li>
4290         * </ol>
4291         * </p>
4292         * <P>
4293         * <B>Note:</B> Some databases may not return information for all tables.
4294         * </p>
4295         * 
4296         * @param catalog
4297         *            a catalog name; "" retrieves those without a catalog
4298         * @param schemaPattern
4299         *            a schema name pattern; "" retrieves those without a schema
4300         * @param tableNamePattern
4301         *            a table name pattern
4302         * @param types
4303         *            a list of table types to include; null returns all types
4304         * @return ResultSet each row is a table description
4305         * @throws SQLException
4306         *             DOCUMENT ME!
4307         * @see #getSearchStringEscape
4308         */
4309        public java.sql.ResultSet getTables(String catalog, String schemaPattern,
4310                        String tableNamePattern, final String[] types) throws SQLException {
4311 
4312                if (tableNamePattern == null) {
4313                        if (this.conn.getNullNamePatternMatchesAll()) {
4314                                tableNamePattern = "%";
4315                        } else {
4316                                throw SQLError.createSQLException(
4317                                                "Table name pattern can not be NULL or empty.",
4318                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
4319                        }
4320                }
4321 
4322                Field[] fields = new Field[5];
4323                fields[0] = new Field("", "TABLE_CAT", java.sql.Types.VARCHAR, 255);
4324                fields[1] = new Field("", "TABLE_SCHEM", java.sql.Types.VARCHAR, 0);
4325                fields[2] = new Field("", "TABLE_NAME", java.sql.Types.VARCHAR, 255);
4326                fields[3] = new Field("", "TABLE_TYPE", java.sql.Types.VARCHAR, 5);
4327                fields[4] = new Field("", "REMARKS", java.sql.Types.VARCHAR, 0);
4328 
4329                final ArrayList tuples = new ArrayList();
4330 
4331                final Statement stmt = this.conn.getMetadataSafeStatement();
4332 
4333                final String tableNamePat = tableNamePattern;
4334 
4335                try {
4336 
4337                        new IterateBlock(getCatalogIterator(catalog)) {
4338                                void forEach(Object catalogStr) throws SQLException {
4339                                        ResultSet results = null;
4340 
4341                                        try {
4342 
4343                                                if (!conn.versionMeetsMinimum(5, 0, 2)) {
4344                                                        results = stmt
4345                                                                        .executeQuery("SHOW TABLES FROM "
4346                                                                                        + quotedId + catalogStr.toString()
4347                                                                                        + quotedId + " LIKE '"
4348                                                                                        + tableNamePat + "'");
4349                                                } else {
4350                                                        results = stmt
4351                                                                        .executeQuery("SHOW FULL TABLES FROM "
4352                                                                                        + quotedId + catalogStr.toString()
4353                                                                                        + quotedId + " LIKE '"
4354                                                                                        + tableNamePat + "'");
4355                                                }
4356 
4357                                                boolean shouldReportTables = false;
4358                                                boolean shouldReportViews = false;
4359 
4360                                                if (types == null || types.length == 0) {
4361                                                        shouldReportTables = true;
4362                                                        shouldReportViews = true;
4363                                                } else {
4364                                                        for (int i = 0; i < types.length; i++) {
4365                                                                if ("TABLE".equalsIgnoreCase(types[i])) {
4366                                                                        shouldReportTables = true;
4367                                                                }
4368 
4369                                                                if ("VIEW".equalsIgnoreCase(types[i])) {
4370                                                                        shouldReportViews = true;
4371                                                                }
4372                                                        }
4373                                                }
4374 
4375                                                int typeColumnIndex = 0;
4376                                                boolean hasTableTypes = false;
4377 
4378                                                if (conn.versionMeetsMinimum(5, 0, 2)) {
4379                                                        try {
4380                                                                // Both column names have been in use in the
4381                                                                // source tree
4382                                                                // so far....
4383                                                                typeColumnIndex = results
4384                                                                                .findColumn("table_type");
4385                                                                hasTableTypes = true;
4386                                                        } catch (SQLException sqlEx) {
4387 
4388                                                                // We should probably check SQLState here, but
4389                                                                // that
4390                                                                // can change depending on the server version
4391                                                                // and
4392                                                                // user properties, however, we'll get a 'true'
4393                                                                // SQLException when we actually try to find the
4394                                                                // 'Type' column
4395                                                                // 
4396                                                                try {
4397                                                                        typeColumnIndex = results
4398                                                                                        .findColumn("Type");
4399                                                                        hasTableTypes = true;
4400                                                                } catch (SQLException sqlEx2) {
4401                                                                        hasTableTypes = false;
4402                                                                }
4403                                                        }
4404                                                }
4405 
4406                                                TreeMap tablesOrderedByName = null;
4407                                                TreeMap viewsOrderedByName = null;
4408 
4409                                                while (results.next()) {
4410                                                        byte[][] row = new byte[5][];
4411                                                        row[0] = (catalogStr.toString() == null) ? null
4412                                                                        : s2b(catalogStr.toString());
4413                                                        row[1] = null;
4414                                                        row[2] = results.getBytes(1);
4415                                                        row[4] = new byte[0];
4416 
4417                                                        if (hasTableTypes) {
4418                                                                String tableType = results
4419                                                                                .getString(typeColumnIndex);
4420 
4421                                                                if (("table".equalsIgnoreCase(tableType) || "base table"
4422                                                                                .equalsIgnoreCase(tableType))
4423                                                                                && shouldReportTables) {
4424                                                                        row[3] = TABLE_AS_BYTES;
4425 
4426                                                                        if (tablesOrderedByName == null) {
4427                                                                                tablesOrderedByName = new TreeMap();
4428                                                                        }
4429 
4430                                                                        tablesOrderedByName.put(results
4431                                                                                        .getString(1), row);
4432                                                                } else if ("view".equalsIgnoreCase(tableType)
4433                                                                                && shouldReportViews) {
4434                                                                        row[3] = VIEW_AS_BYTES;
4435 
4436                                                                        if (viewsOrderedByName == null) {
4437                                                                                viewsOrderedByName = new TreeMap();
4438                                                                        }
4439 
4440                                                                        viewsOrderedByName.put(
4441                                                                                        results.getString(1), row);
4442                                                                } else if (!hasTableTypes) {
4443                                                                        // punt?
4444                                                                        row[3] = TABLE_AS_BYTES;
4445 
4446                                                                        if (tablesOrderedByName == null) {
4447                                                                                tablesOrderedByName = new TreeMap();
4448                                                                        }
4449 
4450                                                                        tablesOrderedByName.put(results
4451                                                                                        .getString(1), row);
4452                                                                }
4453                                                        } else {
4454                                                                if (shouldReportTables) {
4455                                                                        // Pre-MySQL-5.0.1, tables only
4456                                                                        row[3] = TABLE_AS_BYTES;
4457 
4458                                                                        if (tablesOrderedByName == null) {
4459                                                                                tablesOrderedByName = new TreeMap();
4460                                                                        }
4461 
4462                                                                        tablesOrderedByName.put(results
4463                                                                                        .getString(1), row);
4464                                                                }
4465                                                        }
4466                                                }
4467 
4468                                                // They are ordered by TABLE_TYPE,
4469                                                // * TABLE_SCHEM and TABLE_NAME.
4470 
4471                                                if (tablesOrderedByName != null) {
4472                                                        Iterator tablesIter = tablesOrderedByName.values()
4473                                                                        .iterator();
4474 
4475                                                        while (tablesIter.hasNext()) {
4476                                                                tuples.add(tablesIter.next());
4477                                                        }
4478                                                }
4479 
4480                                                if (viewsOrderedByName != null) {
4481                                                        Iterator viewsIter = viewsOrderedByName.values()
4482                                                                        .iterator();
4483 
4484                                                        while (viewsIter.hasNext()) {
4485                                                                tuples.add(viewsIter.next());
4486                                                        }
4487                                                }
4488 
4489                                        } finally {
4490                                                if (results != null) {
4491                                                        try {
4492                                                                results.close();
4493                                                        } catch (Exception ex) {
4494                                                                ;
4495                                                        }
4496 
4497                                                        results = null;
4498                                                }
4499 
4500                                        }
4501                                }
4502                        }.doForAll();
4503                } finally {
4504                        if (stmt != null) {
4505                                stmt.close();
4506                        }
4507                }
4508 
4509                java.sql.ResultSet tables = buildResultSet(fields, tuples);
4510 
4511                return tables;
4512        }
4513 
4514        /**
4515         * Get the table types available in this database. The results are ordered
4516         * by table type.
4517         * <P>
4518         * The table type is:
4519         * <OL>
4520         * <li> <B>TABLE_TYPE</B> String => table type. Typical types are "TABLE",
4521         * "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS",
4522         * "SYNONYM". </li>
4523         * </ol>
4524         * </p>
4525         * 
4526         * @return ResultSet each row has a single String column that is a table
4527         *         type
4528         * @throws SQLException
4529         *             DOCUMENT ME!
4530         */
4531        public java.sql.ResultSet getTableTypes() throws SQLException {
4532                ArrayList tuples = new ArrayList();
4533                Field[] fields = new Field[1];
4534                fields[0] = new Field("", "TABLE_TYPE", Types.VARCHAR, 5);
4535 
4536                byte[][] tableTypeRow = new byte[1][];
4537                tableTypeRow[0] = TABLE_AS_BYTES;
4538                tuples.add(tableTypeRow);
4539 
4540                if (this.conn.versionMeetsMinimum(5, 0, 1)) {
4541                        byte[][] viewTypeRow = new byte[1][];
4542                        viewTypeRow[0] = VIEW_AS_BYTES;
4543                        tuples.add(viewTypeRow);
4544                }
4545 
4546                byte[][] tempTypeRow = new byte[1][];
4547                tempTypeRow[0] = s2b("LOCAL TEMPORARY");
4548                tuples.add(tempTypeRow);
4549 
4550                return buildResultSet(fields, tuples);
4551        }
4552 
4553        /**
4554         * Get a comma separated list of time and date functions.
4555         * 
4556         * @return the list
4557         * @throws SQLException
4558         *             DOCUMENT ME!
4559         */
4560        public String getTimeDateFunctions() throws SQLException {
4561                return "DAYOFWEEK,WEEKDAY,DAYOFMONTH,DAYOFYEAR,MONTH,DAYNAME,"
4562                                + "MONTHNAME,QUARTER,WEEK,YEAR,HOUR,MINUTE,SECOND,PERIOD_ADD,"
4563                                + "PERIOD_DIFF,TO_DAYS,FROM_DAYS,DATE_FORMAT,TIME_FORMAT,"
4564                                + "CURDATE,CURRENT_DATE,CURTIME,CURRENT_TIME,NOW,SYSDATE,"
4565                                + "CURRENT_TIMESTAMP,UNIX_TIMESTAMP,FROM_UNIXTIME,"
4566                                + "SEC_TO_TIME,TIME_TO_SEC";
4567        }
4568 
4569        /**
4570         * Get a description of all the standard SQL types supported by this
4571         * database. They are ordered by DATA_TYPE and then by how closely the data
4572         * type maps to the corresponding JDBC SQL type.
4573         * <P>
4574         * Each type description has the following columns:
4575         * <OL>
4576         * <li> <B>TYPE_NAME</B> String => Type name </li>
4577         * <li> <B>DATA_TYPE</B> short => SQL data type from java.sql.Types </li>
4578         * <li> <B>PRECISION</B> int => maximum precision </li>
4579         * <li> <B>LITERAL_PREFIX</B> String => prefix used to quote a literal (may
4580         * be null) </li>
4581         * <li> <B>LITERAL_SUFFIX</B> String => suffix used to quote a literal (may
4582         * be null) </li>
4583         * <li> <B>CREATE_PARAMS</B> String => parameters used in creating the type
4584         * (may be null) </li>
4585         * <li> <B>NULLABLE</B> short => can you use NULL for this type?
4586         * <UL>
4587         * <li> typeNoNulls - does not allow NULL values </li>
4588         * <li> typeNullable - allows NULL values </li>
4589         * <li> typeNullableUnknown - nullability unknown </li>
4590         * </ul>
4591         * </li>
4592         * <li> <B>CASE_SENSITIVE</B> boolean=> is it case sensitive? </li>
4593         * <li> <B>SEARCHABLE</B> short => can you use "WHERE" based on this type:
4594         * <UL>
4595         * <li> typePredNone - No support </li>
4596         * <li> typePredChar - Only supported with WHERE .. LIKE </li>
4597         * <li> typePredBasic - Supported except for WHERE .. LIKE </li>
4598         * <li> typeSearchable - Supported for all WHERE .. </li>
4599         * </ul>
4600         * </li>
4601         * <li> <B>UNSIGNED_ATTRIBUTE</B> boolean => is it unsigned? </li>
4602         * <li> <B>FIXED_PREC_SCALE</B> boolean => can it be a money value? </li>
4603         * <li> <B>AUTO_INCREMENT</B> boolean => can it be used for an
4604         * auto-increment value? </li>
4605         * <li> <B>LOCAL_TYPE_NAME</B> String => localized version of type name
4606         * (may be null) </li>
4607         * <li> <B>MINIMUM_SCALE</B> short => minimum scale supported </li>
4608         * <li> <B>MAXIMUM_SCALE</B> short => maximum scale supported </li>
4609         * <li> <B>SQL_DATA_TYPE</B> int => unused </li>
4610         * <li> <B>SQL_DATETIME_SUB</B> int => unused </li>
4611         * <li> <B>NUM_PREC_RADIX</B> int => usually 2 or 10 </li>
4612         * </ol>
4613         * </p>
4614         * 
4615         * @return ResultSet each row is a SQL type description
4616         * @throws SQLException
4617         *             DOCUMENT ME!
4618         */
4619        /**
4620         * Get a description of all the standard SQL types supported by this
4621         * database. They are ordered by DATA_TYPE and then by how closely the data
4622         * type maps to the corresponding JDBC SQL type.
4623         * <P>
4624         * Each type description has the following columns:
4625         * <OL>
4626         * <li> <B>TYPE_NAME</B> String => Type name </li>
4627         * <li> <B>DATA_TYPE</B> short => SQL data type from java.sql.Types </li>
4628         * <li> <B>PRECISION</B> int => maximum precision </li>
4629         * <li> <B>LITERAL_PREFIX</B> String => prefix used to quote a literal (may
4630         * be null) </li>
4631         * <li> <B>LITERAL_SUFFIX</B> String => suffix used to quote a literal (may
4632         * be null) </li>
4633         * <li> <B>CREATE_PARAMS</B> String => parameters used in creating the type
4634         * (may be null) </li>
4635         * <li> <B>NULLABLE</B> short => can you use NULL for this type?
4636         * <UL>
4637         * <li> typeNoNulls - does not allow NULL values </li>
4638         * <li> typeNullable - allows NULL values </li>
4639         * <li> typeNullableUnknown - nullability unknown </li>
4640         * </ul>
4641         * </li>
4642         * <li> <B>CASE_SENSITIVE</B> boolean=> is it case sensitive? </li>
4643         * <li> <B>SEARCHABLE</B> short => can you use "WHERE" based on this type:
4644         * <UL>
4645         * <li> typePredNone - No support </li>
4646         * <li> typePredChar - Only supported with WHERE .. LIKE </li>
4647         * <li> typePredBasic - Supported except for WHERE .. LIKE </li>
4648         * <li> typeSearchable - Supported for all WHERE .. </li>
4649         * </ul>
4650         * </li>
4651         * <li> <B>UNSIGNED_ATTRIBUTE</B> boolean => is it unsigned? </li>
4652         * <li> <B>FIXED_PREC_SCALE</B> boolean => can it be a money value? </li>
4653         * <li> <B>AUTO_INCREMENT</B> boolean => can it be used for an
4654         * auto-increment value? </li>
4655         * <li> <B>LOCAL_TYPE_NAME</B> String => localized version of type name
4656         * (may be null) </li>
4657         * <li> <B>MINIMUM_SCALE</B> short => minimum scale supported </li>
4658         * <li> <B>MAXIMUM_SCALE</B> short => maximum scale supported </li>
4659         * <li> <B>SQL_DATA_TYPE</B> int => unused </li>
4660         * <li> <B>SQL_DATETIME_SUB</B> int => unused </li>
4661         * <li> <B>NUM_PREC_RADIX</B> int => usually 2 or 10 </li>
4662         * </ol>
4663         * </p>
4664         * 
4665         * @return ResultSet each row is a SQL type description
4666         * @throws SQLException
4667         *             DOCUMENT ME!
4668         */
4669        public java.sql.ResultSet getTypeInfo() throws SQLException {
4670                Field[] fields = new Field[18];
4671                fields[0] = new Field("", "TYPE_NAME", Types.CHAR, 32);
4672                fields[1] = new Field("", "DATA_TYPE", Types.SMALLINT, 5);
4673                fields[2] = new Field("", "PRECISION", Types.INTEGER, 10);
4674                fields[3] = new Field("", "LITERAL_PREFIX", Types.CHAR, 4);
4675                fields[4] = new Field("", "LITERAL_SUFFIX", Types.CHAR, 4);
4676                fields[5] = new Field("", "CREATE_PARAMS", Types.CHAR, 32);
4677                fields[6] = new Field("", "NULLABLE", Types.SMALLINT, 5);
4678                fields[7] = new Field("", "CASE_SENSITIVE", Types.CHAR, 3);
4679                fields[8] = new Field("", "SEARCHABLE", Types.SMALLINT, 3);
4680                fields[9] = new Field("", "UNSIGNED_ATTRIBUTE", Types.CHAR, 3);
4681                fields[10] = new Field("", "FIXED_PREC_SCALE", Types.CHAR, 3);
4682                fields[11] = new Field("", "AUTO_INCREMENT", Types.CHAR, 3);
4683                fields[12] = new Field("", "LOCAL_TYPE_NAME", Types.CHAR, 32);
4684                fields[13] = new Field("", "MINIMUM_SCALE", Types.SMALLINT, 5);
4685                fields[14] = new Field("", "MAXIMUM_SCALE", Types.SMALLINT, 5);
4686                fields[15] = new Field("", "SQL_DATA_TYPE", Types.INTEGER, 10);
4687                fields[16] = new Field("", "SQL_DATETIME_SUB", Types.INTEGER, 10);
4688                fields[17] = new Field("", "NUM_PREC_RADIX", Types.INTEGER, 10);
4689 
4690                byte[][] rowVal = null;
4691                ArrayList tuples = new ArrayList();
4692 
4693                /*
4694                 * The following are ordered by java.sql.Types, and then by how closely
4695                 * the MySQL type matches the JDBC Type (per spec)
4696                 */
4697                /*
4698                 * MySQL Type: BIT (silently converted to TINYINT(1)) JDBC Type: BIT
4699                 */
4700                rowVal = new byte[18][];
4701                rowVal[0] = s2b("BIT");
4702                rowVal[1] = Integer.toString(java.sql.Types.BIT).getBytes();
4703 
4704                // JDBC Data type
4705                rowVal[2] = s2b("1"); // Precision
4706                rowVal[3] = s2b(""); // Literal Prefix
4707                rowVal[4] = s2b(""); // Literal Suffix
4708                rowVal[5] = s2b(""); // Create Params
4709                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4710                                .getBytes();
4711 
4712                // Nullable
4713                rowVal[7] = s2b("true"); // Case Sensitive
4714                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4715                                .getBytes();
4716 
4717                // Searchable
4718                rowVal[9] = s2b("false"); // Unsignable
4719                rowVal[10] = s2b("false"); // Fixed Prec Scale
4720                rowVal[11] = s2b("false"); // Auto Increment
4721                rowVal[12] = s2b("BIT"); // Locale Type Name
4722                rowVal[13] = s2b("0"); // Minimum Scale
4723                rowVal[14] = s2b("0"); // Maximum Scale
4724                rowVal[15] = s2b("0"); // SQL Data Type (not used)
4725                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4726                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4727                tuples.add(rowVal);
4728 
4729                /*
4730                 * MySQL Type: BOOL (silently converted to TINYINT(1)) JDBC Type: BIT
4731                 */
4732                rowVal = new byte[18][];
4733                rowVal[0] = s2b("BOOL");
4734                rowVal[1] = Integer.toString(java.sql.Types.BIT).getBytes();
4735 
4736                // JDBC Data type
4737                rowVal[2] = s2b("1"); // Precision
4738                rowVal[3] = s2b(""); // Literal Prefix
4739                rowVal[4] = s2b(""); // Literal Suffix
4740                rowVal[5] = s2b(""); // Create Params
4741                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4742                                .getBytes();
4743 
4744                // Nullable
4745                rowVal[7] = s2b("true"); // Case Sensitive
4746                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4747                                .getBytes();
4748 
4749                // Searchable
4750                rowVal[9] = s2b("false"); // Unsignable
4751                rowVal[10] = s2b("false"); // Fixed Prec Scale
4752                rowVal[11] = s2b("false"); // Auto Increment
4753                rowVal[12] = s2b("BOOL"); // Locale Type Name
4754                rowVal[13] = s2b("0"); // Minimum Scale
4755                rowVal[14] = s2b("0"); // Maximum Scale
4756                rowVal[15] = s2b("0"); // SQL Data Type (not used)
4757                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4758                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4759                tuples.add(rowVal);
4760 
4761                /*
4762                 * MySQL Type: TINYINT JDBC Type: TINYINT
4763                 */
4764                rowVal = new byte[18][];
4765                rowVal[0] = s2b("TINYINT");
4766                rowVal[1] = Integer.toString(java.sql.Types.TINYINT).getBytes();
4767 
4768                // JDBC Data type
4769                rowVal[2] = s2b("3"); // Precision
4770                rowVal[3] = s2b(""); // Literal Prefix
4771                rowVal[4] = s2b(""); // Literal Suffix
4772                rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params
4773                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4774                                .getBytes();
4775 
4776                // Nullable
4777                rowVal[7] = s2b("false"); // Case Sensitive
4778                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4779                                .getBytes();
4780 
4781                // Searchable
4782                rowVal[9] = s2b("true"); // Unsignable
4783                rowVal[10] = s2b("false"); // Fixed Prec Scale
4784                rowVal[11] = s2b("true"); // Auto Increment
4785                rowVal[12] = s2b("TINYINT"); // Locale Type Name
4786                rowVal[13] = s2b("0"); // Minimum Scale
4787                rowVal[14] = s2b("0"); // Maximum Scale
4788                rowVal[15] = s2b("0"); // SQL Data Type (not used)
4789                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4790                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4791                tuples.add(rowVal);
4792 
4793                /*
4794                 * MySQL Type: BIGINT JDBC Type: BIGINT
4795                 */
4796                rowVal = new byte[18][];
4797                rowVal[0] = s2b("BIGINT");
4798                rowVal[1] = Integer.toString(java.sql.Types.BIGINT).getBytes();
4799 
4800                // JDBC Data type
4801                rowVal[2] = s2b("19"); // Precision
4802                rowVal[3] = s2b(""); // Literal Prefix
4803                rowVal[4] = s2b(""); // Literal Suffix
4804                rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params
4805                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4806                                .getBytes();
4807 
4808                // Nullable
4809                rowVal[7] = s2b("false"); // Case Sensitive
4810                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4811                                .getBytes();
4812 
4813                // Searchable
4814                rowVal[9] = s2b("true"); // Unsignable
4815                rowVal[10] = s2b("false"); // Fixed Prec Scale
4816                rowVal[11] = s2b("true"); // Auto Increment
4817                rowVal[12] = s2b("BIGINT"); // Locale Type Name
4818                rowVal[13] = s2b("0"); // Minimum Scale
4819                rowVal[14] = s2b("0"); // Maximum Scale
4820                rowVal[15] = s2b("0"); // SQL Data Type (not used)
4821                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4822                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4823                tuples.add(rowVal);
4824 
4825                /*
4826                 * MySQL Type: LONG VARBINARY JDBC Type: LONGVARBINARY
4827                 */
4828                rowVal = new byte[18][];
4829                rowVal[0] = s2b("LONG VARBINARY");
4830                rowVal[1] = Integer.toString(java.sql.Types.LONGVARBINARY).getBytes();
4831 
4832                // JDBC Data type
4833                rowVal[2] = s2b("16777215"); // Precision
4834                rowVal[3] = s2b("'"); // Literal Prefix
4835                rowVal[4] = s2b("'"); // Literal Suffix
4836                rowVal[5] = s2b(""); // Create Params
4837                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4838                                .getBytes();
4839 
4840                // Nullable
4841                rowVal[7] = s2b("true"); // Case Sensitive
4842                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4843                                .getBytes();
4844 
4845                // Searchable
4846                rowVal[9] = s2b("false"); // Unsignable
4847                rowVal[10] = s2b("false"); // Fixed Prec Scale
4848                rowVal[11] = s2b("false"); // Auto Increment
4849                rowVal[12] = s2b("LONG VARBINARY"); // Locale Type Name
4850                rowVal[13] = s2b("0"); // Minimum Scale
4851                rowVal[14] = s2b("0"); // Maximum Scale
4852                rowVal[15] = s2b("0"); // SQL Data Type (not used)
4853                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4854                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4855                tuples.add(rowVal);
4856 
4857                /*
4858                 * MySQL Type: MEDIUMBLOB JDBC Type: LONGVARBINARY
4859                 */
4860                rowVal = new byte[18][];
4861                rowVal[0] = s2b("MEDIUMBLOB");
4862                rowVal[1] = Integer.toString(java.sql.Types.LONGVARBINARY).getBytes();
4863 
4864                // JDBC Data type
4865                rowVal[2] = s2b("16777215"); // Precision
4866                rowVal[3] = s2b("'"); // Literal Prefix
4867                rowVal[4] = s2b("'"); // Literal Suffix
4868                rowVal[5] = s2b(""); // Create Params
4869                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4870                                .getBytes();
4871 
4872                // Nullable
4873                rowVal[7] = s2b("true"); // Case Sensitive
4874                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4875                                .getBytes();
4876 
4877                // Searchable
4878                rowVal[9] = s2b("false"); // Unsignable
4879                rowVal[10] = s2b("false"); // Fixed Prec Scale
4880                rowVal[11] = s2b("false"); // Auto Increment
4881                rowVal[12] = s2b("MEDIUMBLOB"); // Locale Type Name
4882                rowVal[13] = s2b("0"); // Minimum Scale
4883                rowVal[14] = s2b("0"); // Maximum Scale
4884                rowVal[15] = s2b("0"); // SQL Data Type (not used)
4885                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4886                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4887                tuples.add(rowVal);
4888 
4889                /*
4890                 * MySQL Type: LONGBLOB JDBC Type: LONGVARBINARY
4891                 */
4892                rowVal = new byte[18][];
4893                rowVal[0] = s2b("LONGBLOB");
4894                rowVal[1] = Integer.toString(java.sql.Types.LONGVARBINARY).getBytes();
4895 
4896                // JDBC Data type
4897                rowVal[2] = Integer.toString(Integer.MAX_VALUE).getBytes();
4898 
4899                // Precision
4900                rowVal[3] = s2b("'"); // Literal Prefix
4901                rowVal[4] = s2b("'"); // Literal Suffix
4902                rowVal[5] = s2b(""); // Create Params
4903                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4904                                .getBytes();
4905 
4906                // Nullable
4907                rowVal[7] = s2b("true"); // Case Sensitive
4908                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4909                                .getBytes();
4910 
4911                // Searchable
4912                rowVal[9] = s2b("false"); // Unsignable
4913                rowVal[10] = s2b("false"); // Fixed Prec Scale
4914                rowVal[11] = s2b("false"); // Auto Increment
4915                rowVal[12] = s2b("LONGBLOB"); // Locale Type Name
4916                rowVal[13] = s2b("0"); // Minimum Scale
4917                rowVal[14] = s2b("0"); // Maximum Scale
4918                rowVal[15] = s2b("0"); // SQL Data Type (not used)
4919                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4920                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4921                tuples.add(rowVal);
4922 
4923                /*
4924                 * MySQL Type: BLOB JDBC Type: LONGVARBINARY
4925                 */
4926                rowVal = new byte[18][];
4927                rowVal[0] = s2b("BLOB");
4928                rowVal[1] = Integer.toString(java.sql.Types.LONGVARBINARY).getBytes();
4929 
4930                // JDBC Data type
4931                rowVal[2] = s2b("65535"); // Precision
4932                rowVal[3] = s2b("'"); // Literal Prefix
4933                rowVal[4] = s2b("'"); // Literal Suffix
4934                rowVal[5] = s2b(""); // Create Params
4935                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4936                                .getBytes();
4937 
4938                // Nullable
4939                rowVal[7] = s2b("true"); // Case Sensitive
4940                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4941                                .getBytes();
4942 
4943                // Searchable
4944                rowVal[9] = s2b("false"); // Unsignable
4945                rowVal[10] = s2b("false"); // Fixed Prec Scale
4946                rowVal[11] = s2b("false"); // Auto Increment
4947                rowVal[12] = s2b("BLOB"); // Locale Type Name
4948                rowVal[13] = s2b("0"); // Minimum Scale
4949                rowVal[14] = s2b("0"); // Maximum Scale
4950                rowVal[15] = s2b("0"); // SQL Data Type (not used)
4951                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4952                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4953                tuples.add(rowVal);
4954 
4955                /*
4956                 * MySQL Type: TINYBLOB JDBC Type: LONGVARBINARY
4957                 */
4958                rowVal = new byte[18][];
4959                rowVal[0] = s2b("TINYBLOB");
4960                rowVal[1] = Integer.toString(java.sql.Types.LONGVARBINARY).getBytes();
4961 
4962                // JDBC Data type
4963                rowVal[2] = s2b("255"); // Precision
4964                rowVal[3] = s2b("'"); // Literal Prefix
4965                rowVal[4] = s2b("'"); // Literal Suffix
4966                rowVal[5] = s2b(""); // Create Params
4967                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4968                                .getBytes();
4969 
4970                // Nullable
4971                rowVal[7] = s2b("true"); // Case Sensitive
4972                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4973                                .getBytes();
4974 
4975                // Searchable
4976                rowVal[9] = s2b("false"); // Unsignable
4977                rowVal[10] = s2b("false"); // Fixed Prec Scale
4978                rowVal[11] = s2b("false"); // Auto Increment
4979                rowVal[12] = s2b("TINYBLOB"); // Locale Type Name
4980                rowVal[13] = s2b("0"); // Minimum Scale
4981                rowVal[14] = s2b("0"); // Maximum Scale
4982                rowVal[15] = s2b("0"); // SQL Data Type (not used)
4983                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4984                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4985                tuples.add(rowVal);
4986 
4987                /*
4988                 * MySQL Type: VARBINARY (sliently converted to VARCHAR(M) BINARY) JDBC
4989                 * Type: VARBINARY
4990                 */
4991                rowVal = new byte[18][];
4992                rowVal[0] = s2b("VARBINARY");
4993                rowVal[1] = Integer.toString(java.sql.Types.VARBINARY).getBytes();
4994 
4995                // JDBC Data type
4996                rowVal[2] = s2b("255"); // Precision
4997                rowVal[3] = s2b("'"); // Literal Prefix
4998                rowVal[4] = s2b("'"); // Literal Suffix
4999                rowVal[5] = s2b("(M)"); // Create Params
5000                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5001                                .getBytes();
5002 
5003                // Nullable
5004                rowVal[7] = s2b("true"); // Case Sensitive
5005                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5006                                .getBytes();
5007 
5008                // Searchable
5009                rowVal[9] = s2b("false"); // Unsignable
5010                rowVal[10] = s2b("false"); // Fixed Prec Scale
5011                rowVal[11] = s2b("false"); // Auto Increment
5012                rowVal[12] = s2b("VARBINARY"); // Locale Type Name
5013                rowVal[13] = s2b("0"); // Minimum Scale
5014                rowVal[14] = s2b("0"); // Maximum Scale
5015                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5016                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5017                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5018                tuples.add(rowVal);
5019 
5020                /*
5021                 * MySQL Type: BINARY (silently converted to CHAR(M) BINARY) JDBC Type:
5022                 * BINARY
5023                 */
5024                rowVal = new byte[18][];
5025                rowVal[0] = s2b("BINARY");
5026                rowVal[1] = Integer.toString(java.sql.Types.BINARY).getBytes();
5027 
5028                // JDBC Data type
5029                rowVal[2] = s2b("255"); // Precision
5030                rowVal[3] = s2b("'"); // Literal Prefix
5031                rowVal[4] = s2b("'"); // Literal Suffix
5032                rowVal[5] = s2b("(M)"); // Create Params
5033                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5034                                .getBytes();
5035 
5036                // Nullable
5037                rowVal[7] = s2b("true"); // Case Sensitive
5038                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5039                                .getBytes();
5040 
5041                // Searchable
5042                rowVal[9] = s2b("false"); // Unsignable
5043                rowVal[10] = s2b("false"); // Fixed Prec Scale
5044                rowVal[11] = s2b("false"); // Auto Increment
5045                rowVal[12] = s2b("BINARY"); // Locale Type Name
5046                rowVal[13] = s2b("0"); // Minimum Scale
5047                rowVal[14] = s2b("0"); // Maximum Scale
5048                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5049                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5050                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5051                tuples.add(rowVal);
5052 
5053                /*
5054                 * MySQL Type: LONG VARCHAR JDBC Type: LONGVARCHAR
5055                 */
5056                rowVal = new byte[18][];
5057                rowVal[0] = s2b("LONG VARCHAR");
5058                rowVal[1] = Integer.toString(java.sql.Types.LONGVARCHAR).getBytes();
5059 
5060                // JDBC Data type
5061                rowVal[2] = s2b("16777215"); // Precision
5062                rowVal[3] = s2b("'"); // Literal Prefix
5063                rowVal[4] = s2b("'"); // Literal Suffix
5064                rowVal[5] = s2b(""); // Create Params
5065                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5066                                .getBytes();
5067 
5068                // Nullable
5069                rowVal[7] = s2b("false"); // Case Sensitive
5070                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5071                                .getBytes();
5072 
5073                // Searchable
5074                rowVal[9] = s2b("false"); // Unsignable
5075                rowVal[10] = s2b("false"); // Fixed Prec Scale
5076                rowVal[11] = s2b("false"); // Auto Increment
5077                rowVal[12] = s2b("LONG VARCHAR"); // Locale Type Name
5078                rowVal[13] = s2b("0"); // Minimum Scale
5079                rowVal[14] = s2b("0"); // Maximum Scale
5080                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5081                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5082                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5083                tuples.add(rowVal);
5084 
5085                /*
5086                 * MySQL Type: MEDIUMTEXT JDBC Type: LONGVARCHAR
5087                 */
5088                rowVal = new byte[18][];
5089                rowVal[0] = s2b("MEDIUMTEXT");
5090                rowVal[1] = Integer.toString(java.sql.Types.LONGVARCHAR).getBytes();
5091 
5092                // JDBC Data type
5093                rowVal[2] = s2b("16777215"); // Precision
5094                rowVal[3] = s2b("'"); // Literal Prefix
5095                rowVal[4] = s2b("'"); // Literal Suffix
5096                rowVal[5] = s2b(""); // Create Params
5097                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5098                                .getBytes();
5099 
5100                // Nullable
5101                rowVal[7] = s2b("false"); // Case Sensitive
5102                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5103                                .getBytes();
5104 
5105                // Searchable
5106                rowVal[9] = s2b("false"); // Unsignable
5107                rowVal[10] = s2b("false"); // Fixed Prec Scale
5108                rowVal[11] = s2b("false"); // Auto Increment
5109                rowVal[12] = s2b("MEDIUMTEXT"); // Locale Type Name
5110                rowVal[13] = s2b("0"); // Minimum Scale
5111                rowVal[14] = s2b("0"); // Maximum Scale
5112                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5113                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5114                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5115                tuples.add(rowVal);
5116 
5117                /*
5118                 * MySQL Type: LONGTEXT JDBC Type: LONGVARCHAR
5119                 */
5120                rowVal = new byte[18][];
5121                rowVal[0] = s2b("LONGTEXT");
5122                rowVal[1] = Integer.toString(java.sql.Types.LONGVARCHAR).getBytes();
5123 
5124                // JDBC Data type
5125                rowVal[2] = Integer.toString(Integer.MAX_VALUE).getBytes();
5126 
5127                // Precision
5128                rowVal[3] = s2b("'"); // Literal Prefix
5129                rowVal[4] = s2b("'"); // Literal Suffix
5130                rowVal[5] = s2b(""); // Create Params
5131                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5132                                .getBytes();
5133 
5134                // Nullable
5135                rowVal[7] = s2b("false"); // Case Sensitive
5136                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5137                                .getBytes();
5138 
5139                // Searchable
5140                rowVal[9] = s2b("false"); // Unsignable
5141                rowVal[10] = s2b("false"); // Fixed Prec Scale
5142                rowVal[11] = s2b("false"); // Auto Increment
5143                rowVal[12] = s2b("LONGTEXT"); // Locale Type Name
5144                rowVal[13] = s2b("0"); // Minimum Scale
5145                rowVal[14] = s2b("0"); // Maximum Scale
5146                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5147                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5148                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5149                tuples.add(rowVal);
5150 
5151                /*
5152                 * MySQL Type: TEXT JDBC Type: LONGVARCHAR
5153                 */
5154                rowVal = new byte[18][];
5155                rowVal[0] = s2b("TEXT");
5156                rowVal[1] = Integer.toString(java.sql.Types.LONGVARCHAR).getBytes();
5157 
5158                // JDBC Data type
5159                rowVal[2] = s2b("65535"); // Precision
5160                rowVal[3] = s2b("'"); // Literal Prefix
5161                rowVal[4] = s2b("'"); // Literal Suffix
5162                rowVal[5] = s2b(""); // Create Params
5163                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5164                                .getBytes();
5165 
5166                // Nullable
5167                rowVal[7] = s2b("false"); // Case Sensitive
5168                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5169                                .getBytes();
5170 
5171                // Searchable
5172                rowVal[9] = s2b("false"); // Unsignable
5173                rowVal[10] = s2b("false"); // Fixed Prec Scale
5174                rowVal[11] = s2b("false"); // Auto Increment
5175                rowVal[12] = s2b("TEXT"); // Locale Type Name
5176                rowVal[13] = s2b("0"); // Minimum Scale
5177                rowVal[14] = s2b("0"); // Maximum Scale
5178                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5179                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5180                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5181                tuples.add(rowVal);
5182 
5183                /*
5184                 * MySQL Type: TINYTEXT JDBC Type: LONGVARCHAR
5185                 */
5186                rowVal = new byte[18][];
5187                rowVal[0] = s2b("TINYTEXT");
5188                rowVal[1] = Integer.toString(java.sql.Types.LONGVARCHAR).getBytes();
5189 
5190                // JDBC Data type
5191                rowVal[2] = s2b("255"); // Precision
5192                rowVal[3] = s2b("'"); // Literal Prefix
5193                rowVal[4] = s2b("'"); // Literal Suffix
5194                rowVal[5] = s2b(""); // Create Params
5195                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5196                                .getBytes();
5197 
5198                // Nullable
5199                rowVal[7] = s2b("false"); // Case Sensitive
5200                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5201                                .getBytes();
5202 
5203                // Searchable
5204                rowVal[9] = s2b("false"); // Unsignable
5205                rowVal[10] = s2b("false"); // Fixed Prec Scale
5206                rowVal[11] = s2b("false"); // Auto Increment
5207                rowVal[12] = s2b("TINYTEXT"); // Locale Type Name
5208                rowVal[13] = s2b("0"); // Minimum Scale
5209                rowVal[14] = s2b("0"); // Maximum Scale
5210                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5211                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5212                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5213                tuples.add(rowVal);
5214 
5215                /*
5216                 * MySQL Type: CHAR JDBC Type: CHAR
5217                 */
5218                rowVal = new byte[18][];
5219                rowVal[0] = s2b("CHAR");
5220                rowVal[1] = Integer.toString(java.sql.Types.CHAR).getBytes();
5221 
5222                // JDBC Data type
5223                rowVal[2] = s2b("255"); // Precision
5224                rowVal[3] = s2b("'"); // Literal Prefix
5225                rowVal[4] = s2b("'"); // Literal Suffix
5226                rowVal[5] = s2b("(M)"); // Create Params
5227                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5228                                .getBytes();
5229 
5230                // Nullable
5231                rowVal[7] = s2b("false"); // Case Sensitive
5232                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5233                                .getBytes();
5234 
5235                // Searchable
5236                rowVal[9] = s2b("false"); // Unsignable
5237                rowVal[10] = s2b("false"); // Fixed Prec Scale
5238                rowVal[11] = s2b("false"); // Auto Increment
5239                rowVal[12] = s2b("CHAR"); // Locale Type Name
5240                rowVal[13] = s2b("0"); // Minimum Scale
5241                rowVal[14] = s2b("0"); // Maximum Scale
5242                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5243                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5244                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5245                tuples.add(rowVal);
5246 
5247                /*
5248                 * MySQL Type: NUMERIC (silently converted to DECIMAL) JDBC Type:
5249                 * NUMERIC
5250                 */
5251                rowVal = new byte[18][];
5252                rowVal[0] = s2b("NUMERIC");
5253                rowVal[1] = Integer.toString(java.sql.Types.NUMERIC).getBytes();
5254 
5255                // JDBC Data type
5256                rowVal[2] = s2b("17"); // Precision
5257                rowVal[3] = s2b(""); // Literal Prefix
5258                rowVal[4] = s2b(""); // Literal Suffix
5259                rowVal[5] = s2b("[(M[,D])] [ZEROFILL]"); // Create Params
5260                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5261                                .getBytes();
5262 
5263                // Nullable
5264                rowVal[7] = s2b("false"); // Case Sensitive
5265                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5266                                .getBytes();
5267 
5268                // Searchable
5269                rowVal[9] = s2b("false"); // Unsignable
5270                rowVal[10] = s2b("false"); // Fixed Prec Scale
5271                rowVal[11] = s2b("true"); // Auto Increment
5272                rowVal[12] = s2b("NUMERIC"); // Locale Type Name
5273                rowVal[13] = s2b("-308"); // Minimum Scale
5274                rowVal[14] = s2b("308"); // Maximum Scale
5275                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5276                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5277                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5278                tuples.add(rowVal);
5279 
5280                /*
5281                 * MySQL Type: DECIMAL JDBC Type: DECIMAL
5282                 */
5283                rowVal = new byte[18][];
5284                rowVal[0] = s2b("DECIMAL");
5285                rowVal[1] = Integer.toString(java.sql.Types.DECIMAL).getBytes();
5286 
5287                // JDBC Data type
5288                rowVal[2] = s2b("17"); // Precision
5289                rowVal[3] = s2b(""); // Literal Prefix
5290                rowVal[4] = s2b(""); // Literal Suffix
5291                rowVal[5] = s2b("[(M[,D])] [ZEROFILL]"); // Create Params
5292                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5293                                .getBytes();
5294 
5295                // Nullable
5296                rowVal[7] = s2b("false"); // Case Sensitive
5297                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5298                                .getBytes();
5299 
5300                // Searchable
5301                rowVal[9] = s2b("false"); // Unsignable
5302                rowVal[10] = s2b("false"); // Fixed Prec Scale
5303                rowVal[11] = s2b("true"); // Auto Increment
5304                rowVal[12] = s2b("DECIMAL"); // Locale Type Name
5305                rowVal[13] = s2b("-308"); // Minimum Scale
5306                rowVal[14] = s2b("308"); // Maximum Scale
5307                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5308                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5309                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5310                tuples.add(rowVal);
5311 
5312                /*
5313                 * MySQL Type: INTEGER JDBC Type: INTEGER
5314                 */
5315                rowVal = new byte[18][];
5316                rowVal[0] = s2b("INTEGER");
5317                rowVal[1] = Integer.toString(java.sql.Types.INTEGER).getBytes();
5318 
5319                // JDBC Data type
5320                rowVal[2] = s2b("10"); // Precision
5321                rowVal[3] = s2b(""); // Literal Prefix
5322                rowVal[4] = s2b(""); // Literal Suffix
5323                rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params
5324                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5325                                .getBytes();
5326 
5327                // Nullable
5328                rowVal[7] = s2b("false"); // Case Sensitive
5329                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5330                                .getBytes();
5331 
5332                // Searchable
5333                rowVal[9] = s2b("true"); // Unsignable
5334                rowVal[10] = s2b("false"); // Fixed Prec Scale
5335                rowVal[11] = s2b("true"); // Auto Increment
5336                rowVal[12] = s2b("INTEGER"); // Locale Type Name
5337                rowVal[13] = s2b("0"); // Minimum Scale
5338                rowVal[14] = s2b("0"); // Maximum Scale
5339                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5340                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5341                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5342                tuples.add(rowVal);
5343 
5344                /*
5345                 * MySQL Type: INT JDBC Type: INTEGER
5346                 */
5347                rowVal = new byte[18][];
5348                rowVal[0] = s2b("INT");
5349                rowVal[1] = Integer.toString(java.sql.Types.INTEGER).getBytes();
5350 
5351                // JDBC Data type
5352                rowVal[2] = s2b("10"); // Precision
5353                rowVal[3] = s2b(""); // Literal Prefix
5354                rowVal[4] = s2b(""); // Literal Suffix
5355                rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params
5356                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5357                                .getBytes();
5358 
5359                // Nullable
5360                rowVal[7] = s2b("false"); // Case Sensitive
5361                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5362                                .getBytes();
5363 
5364                // Searchable
5365                rowVal[9] = s2b("true"); // Unsignable
5366                rowVal[10] = s2b("false"); // Fixed Prec Scale
5367                rowVal[11] = s2b("true"); // Auto Increment
5368                rowVal[12] = s2b("INT"); // Locale Type Name
5369                rowVal[13] = s2b("0"); // Minimum Scale
5370                rowVal[14] = s2b("0"); // Maximum Scale
5371                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5372                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5373                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5374                tuples.add(rowVal);
5375 
5376                /*
5377                 * MySQL Type: MEDIUMINT JDBC Type: INTEGER
5378                 */
5379                rowVal = new byte[18][];
5380                rowVal[0] = s2b("MEDIUMINT");
5381                rowVal[1] = Integer.toString(java.sql.Types.INTEGER).getBytes();
5382 
5383                // JDBC Data type
5384                rowVal[2] = s2b("7"); // Precision
5385                rowVal[3] = s2b(""); // Literal Prefix
5386                rowVal[4] = s2b(""); // Literal Suffix
5387                rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params
5388                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5389                                .getBytes();
5390 
5391                // Nullable
5392                rowVal[7] = s2b("false"); // Case Sensitive
5393                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5394                                .getBytes();
5395 
5396                // Searchable
5397                rowVal[9] = s2b("true"); // Unsignable
5398                rowVal[10] = s2b("false"); // Fixed Prec Scale
5399                rowVal[11] = s2b("true"); // Auto Increment
5400                rowVal[12] = s2b("MEDIUMINT"); // Locale Type Name
5401                rowVal[13] = s2b("0"); // Minimum Scale
5402                rowVal[14] = s2b("0"); // Maximum Scale
5403                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5404                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5405                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5406                tuples.add(rowVal);
5407 
5408                /*
5409                 * MySQL Type: SMALLINT JDBC Type: SMALLINT
5410                 */
5411                rowVal = new byte[18][];
5412                rowVal[0] = s2b("SMALLINT");
5413                rowVal[1] = Integer.toString(java.sql.Types.SMALLINT).getBytes();
5414 
5415                // JDBC Data type
5416                rowVal[2] = s2b("5"); // Precision
5417                rowVal[3] = s2b(""); // Literal Prefix
5418                rowVal[4] = s2b(""); // Literal Suffix
5419                rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params
5420                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5421                                .getBytes();
5422 
5423                // Nullable
5424                rowVal[7] = s2b("false"); // Case Sensitive
5425                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5426                                .getBytes();
5427 
5428                // Searchable
5429                rowVal[9] = s2b("true"); // Unsignable
5430                rowVal[10] = s2b("false"); // Fixed Prec Scale
5431                rowVal[11] = s2b("true"); // Auto Increment
5432                rowVal[12] = s2b("SMALLINT"); // Locale Type Name
5433                rowVal[13] = s2b("0"); // Minimum Scale
5434                rowVal[14] = s2b("0"); // Maximum Scale
5435                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5436                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5437                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5438                tuples.add(rowVal);
5439 
5440                /*
5441                 * MySQL Type: FLOAT JDBC Type: REAL (this is the SINGLE PERCISION
5442                 * floating point type)
5443                 */
5444                rowVal = new byte[18][];
5445                rowVal[0] = s2b("FLOAT");
5446                rowVal[1] = Integer.toString(java.sql.Types.REAL).getBytes();
5447 
5448                // JDBC Data type
5449                rowVal[2] = s2b("10"); // Precision
5450                rowVal[3] = s2b(""); // Literal Prefix
5451                rowVal[4] = s2b(""); // Literal Suffix
5452                rowVal[5] = s2b("[(M,D)] [ZEROFILL]"); // Create Params
5453                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5454                                .getBytes();
5455 
5456                // Nullable
5457                rowVal[7] = s2b("false"); // Case Sensitive
5458                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5459                                .getBytes();
5460 
5461                // Searchable
5462                rowVal[9] = s2b("false"); // Unsignable
5463                rowVal[10] = s2b("false"); // Fixed Prec Scale
5464                rowVal[11] = s2b("true"); // Auto Increment
5465                rowVal[12] = s2b("FLOAT"); // Locale Type Name
5466                rowVal[13] = s2b("-38"); // Minimum Scale
5467                rowVal[14] = s2b("38"); // Maximum Scale
5468                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5469                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5470                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5471                tuples.add(rowVal);
5472 
5473                /*
5474                 * MySQL Type: DOUBLE JDBC Type: DOUBLE
5475                 */
5476                rowVal = new byte[18][];
5477                rowVal[0] = s2b("DOUBLE");
5478                rowVal[1] = Integer.toString(java.sql.Types.DOUBLE).getBytes();
5479 
5480                // JDBC Data type
5481                rowVal[2] = s2b("17"); // Precision
5482                rowVal[3] = s2b(""); // Literal Prefix
5483                rowVal[4] = s2b(""); // Literal Suffix
5484                rowVal[5] = s2b("[(M,D)] [ZEROFILL]"); // Create Params
5485                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5486                                .getBytes();
5487 
5488                // Nullable
5489                rowVal[7] = s2b("false"); // Case Sensitive
5490                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5491                                .getBytes();
5492 
5493                // Searchable
5494                rowVal[9] = s2b("false"); // Unsignable
5495                rowVal[10] = s2b("false"); // Fixed Prec Scale
5496                rowVal[11] = s2b("true"); // Auto Increment
5497                rowVal[12] = s2b("DOUBLE"); // Locale Type Name
5498                rowVal[13] = s2b("-308"); // Minimum Scale
5499                rowVal[14] = s2b("308"); // Maximum Scale
5500                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5501                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5502                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5503                tuples.add(rowVal);
5504 
5505                /*
5506                 * MySQL Type: DOUBLE PRECISION JDBC Type: DOUBLE
5507                 */
5508                rowVal = new byte[18][];
5509                rowVal[0] = s2b("DOUBLE PRECISION");
5510                rowVal[1] = Integer.toString(java.sql.Types.DOUBLE).getBytes();
5511 
5512                // JDBC Data type
5513                rowVal[2] = s2b("17"); // Precision
5514                rowVal[3] = s2b(""); // Literal Prefix
5515                rowVal[4] = s2b(""); // Literal Suffix
5516                rowVal[5] = s2b("[(M,D)] [ZEROFILL]"); // Create Params
5517                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5518                                .getBytes();
5519 
5520                // Nullable
5521                rowVal[7] = s2b("false"); // Case Sensitive
5522                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5523                                .getBytes();
5524 
5525                // Searchable
5526                rowVal[9] = s2b("false"); // Unsignable
5527                rowVal[10] = s2b("false"); // Fixed Prec Scale
5528                rowVal[11] = s2b("true"); // Auto Increment
5529                rowVal[12] = s2b("DOUBLE PRECISION"); // Locale Type Name
5530                rowVal[13] = s2b("-308"); // Minimum Scale
5531                rowVal[14] = s2b("308"); // Maximum Scale
5532                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5533                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5534                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5535                tuples.add(rowVal);
5536 
5537                /*
5538                 * MySQL Type: REAL (does not map to Types.REAL) JDBC Type: DOUBLE
5539                 */
5540                rowVal = new byte[18][];
5541                rowVal[0] = s2b("REAL");
5542                rowVal[1] = Integer.toString(java.sql.Types.DOUBLE).getBytes();
5543 
5544                // JDBC Data type
5545                rowVal[2] = s2b("17"); // Precision
5546                rowVal[3] = s2b(""); // Literal Prefix
5547                rowVal[4] = s2b(""); // Literal Suffix
5548                rowVal[5] = s2b("[(M,D)] [ZEROFILL]"); // Create Params
5549                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5550                                .getBytes();
5551 
5552                // Nullable
5553                rowVal[7] = s2b("false"); // Case Sensitive
5554                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5555                                .getBytes();
5556 
5557                // Searchable
5558                rowVal[9] = s2b("false"); // Unsignable
5559                rowVal[10] = s2b("false"); // Fixed Prec Scale
5560                rowVal[11] = s2b("true"); // Auto Increment
5561                rowVal[12] = s2b("REAL"); // Locale Type Name
5562                rowVal[13] = s2b("-308"); // Minimum Scale
5563                rowVal[14] = s2b("308"); // Maximum Scale
5564                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5565                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5566                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5567                tuples.add(rowVal);
5568 
5569                /*
5570                 * MySQL Type: VARCHAR JDBC Type: VARCHAR
5571                 */
5572                rowVal = new byte[18][];
5573                rowVal[0] = s2b("VARCHAR");
5574                rowVal[1] = Integer.toString(java.sql.Types.VARCHAR).getBytes();
5575 
5576                // JDBC Data type
5577                rowVal[2] = s2b("255"); // Precision
5578                rowVal[3] = s2b("'"); // Literal Prefix
5579                rowVal[4] = s2b("'"); // Literal Suffix
5580                rowVal[5] = s2b("(M)"); // Create Params
5581                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5582                                .getBytes();
5583 
5584                // Nullable
5585                rowVal[7] = s2b("false"); // Case Sensitive
5586                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5587                                .getBytes();
5588 
5589                // Searchable
5590                rowVal[9] = s2b("false"); // Unsignable
5591                rowVal[10] = s2b("false"); // Fixed Prec Scale
5592                rowVal[11] = s2b("false"); // Auto Increment
5593                rowVal[12] = s2b("VARCHAR"); // Locale Type Name
5594                rowVal[13] = s2b("0"); // Minimum Scale
5595                rowVal[14] = s2b("0"); // Maximum Scale
5596                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5597                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5598                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5599                tuples.add(rowVal);
5600 
5601                /*
5602                 * MySQL Type: ENUM JDBC Type: VARCHAR
5603                 */
5604                rowVal = new byte[18][];
5605                rowVal[0] = s2b("ENUM");
5606                rowVal[1] = Integer.toString(java.sql.Types.VARCHAR).getBytes();
5607 
5608                // JDBC Data type
5609                rowVal[2] = s2b("65535"); // Precision
5610                rowVal[3] = s2b("'"); // Literal Prefix
5611                rowVal[4] = s2b("'"); // Literal Suffix
5612                rowVal[5] = s2b(""); // Create Params
5613                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5614                                .getBytes();
5615 
5616                // Nullable
5617                rowVal[7] = s2b("false"); // Case Sensitive
5618                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5619                                .getBytes();
5620 
5621                // Searchable
5622                rowVal[9] = s2b("false"); // Unsignable
5623                rowVal[10] = s2b("false"); // Fixed Prec Scale
5624                rowVal[11] = s2b("false"); // Auto Increment
5625                rowVal[12] = s2b("ENUM"); // Locale Type Name
5626                rowVal[13] = s2b("0"); // Minimum Scale
5627                rowVal[14] = s2b("0"); // Maximum Scale
5628                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5629                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5630                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5631                tuples.add(rowVal);
5632 
5633                /*
5634                 * MySQL Type: SET JDBC Type: VARCHAR
5635                 */
5636                rowVal = new byte[18][];
5637                rowVal[0] = s2b("SET");
5638                rowVal[1] = Integer.toString(java.sql.Types.VARCHAR).getBytes();
5639 
5640                // JDBC Data type
5641                rowVal[2] = s2b("64"); // Precision
5642                rowVal[3] = s2b("'"); // Literal Prefix
5643                rowVal[4] = s2b("'"); // Literal Suffix
5644                rowVal[5] = s2b(""); // Create Params
5645                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5646                                .getBytes();
5647 
5648                // Nullable
5649                rowVal[7] = s2b("false"); // Case Sensitive
5650                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5651                                .getBytes();
5652 
5653                // Searchable
5654                rowVal[9] = s2b("false"); // Unsignable
5655                rowVal[10] = s2b("false"); // Fixed Prec Scale
5656                rowVal[11] = s2b("false"); // Auto Increment
5657                rowVal[12] = s2b("SET"); // Locale Type Name
5658                rowVal[13] = s2b("0"); // Minimum Scale
5659                rowVal[14] = s2b("0"); // Maximum Scale
5660                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5661                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5662                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5663                tuples.add(rowVal);
5664 
5665                /*
5666                 * MySQL Type: DATE JDBC Type: DATE
5667                 */
5668                rowVal = new byte[18][];
5669                rowVal[0] = s2b("DATE");
5670                rowVal[1] = Integer.toString(java.sql.Types.DATE).getBytes();
5671 
5672                // JDBC Data type
5673                rowVal[2] = s2b("0"); // Precision
5674                rowVal[3] = s2b("'"); // Literal Prefix
5675                rowVal[4] = s2b("'"); // Literal Suffix
5676                rowVal[5] = s2b(""); // Create Params
5677                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5678                                .getBytes();
5679 
5680                // Nullable
5681                rowVal[7] = s2b("false"); // Case Sensitive
5682                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5683                                .getBytes();
5684 
5685                // Searchable
5686                rowVal[9] = s2b("false"); // Unsignable
5687                rowVal[10] = s2b("false"); // Fixed Prec Scale
5688                rowVal[11] = s2b("false"); // Auto Increment
5689                rowVal[12] = s2b("DATE"); // Locale Type Name
5690                rowVal[13] = s2b("0"); // Minimum Scale
5691                rowVal[14] = s2b("0"); // Maximum Scale
5692                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5693                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5694                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5695                tuples.add(rowVal);
5696 
5697                /*
5698                 * MySQL Type: TIME JDBC Type: TIME
5699                 */
5700                rowVal = new byte[18][];
5701                rowVal[0] = s2b("TIME");
5702                rowVal[1] = Integer.toString(java.sql.Types.TIME).getBytes();
5703 
5704                // JDBC Data type
5705                rowVal[2] = s2b("0"); // Precision
5706                rowVal[3] = s2b("'"); // Literal Prefix
5707                rowVal[4] = s2b("'"); // Literal Suffix
5708                rowVal[5] = s2b(""); // Create Params
5709                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5710                                .getBytes();
5711 
5712                // Nullable
5713                rowVal[7] = s2b("false"); // Case Sensitive
5714                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5715                                .getBytes();
5716 
5717                // Searchable
5718                rowVal[9] = s2b("false"); // Unsignable
5719                rowVal[10] = s2b("false"); // Fixed Prec Scale
5720                rowVal[11] = s2b("false"); // Auto Increment
5721                rowVal[12] = s2b("TIME"); // Locale Type Name
5722                rowVal[13] = s2b("0"); // Minimum Scale
5723                rowVal[14] = s2b("0"); // Maximum Scale
5724                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5725                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5726                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5727                tuples.add(rowVal);
5728 
5729                /*
5730                 * MySQL Type: DATETIME JDBC Type: TIMESTAMP
5731                 */
5732                rowVal = new byte[18][];
5733                rowVal[0] = s2b("DATETIME");
5734                rowVal[1] = Integer.toString(java.sql.Types.TIMESTAMP).getBytes();
5735 
5736                // JDBC Data type
5737                rowVal[2] = s2b("0"); // Precision
5738                rowVal[3] = s2b("'"); // Literal Prefix
5739                rowVal[4] = s2b("'"); // Literal Suffix
5740                rowVal[5] = s2b(""); // Create Params
5741                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5742                                .getBytes();
5743 
5744                // Nullable
5745                rowVal[7] = s2b("false"); // Case Sensitive
5746                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5747                                .getBytes();
5748 
5749                // Searchable
5750                rowVal[9] = s2b("false"); // Unsignable
5751                rowVal[10] = s2b("false"); // Fixed Prec Scale
5752                rowVal[11] = s2b("false"); // Auto Increment
5753                rowVal[12] = s2b("DATETIME"); // Locale Type Name
5754                rowVal[13] = s2b("0"); // Minimum Scale
5755                rowVal[14] = s2b("0"); // Maximum Scale
5756                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5757                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5758                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5759                tuples.add(rowVal);
5760 
5761                /*
5762                 * MySQL Type: TIMESTAMP JDBC Type: TIMESTAMP
5763                 */
5764                rowVal = new byte[18][];
5765                rowVal[0] = s2b("TIMESTAMP");
5766                rowVal[1] = Integer.toString(java.sql.Types.TIMESTAMP).getBytes();
5767 
5768                // JDBC Data type
5769                rowVal[2] = s2b("0"); // Precision
5770                rowVal[3] = s2b("'"); // Literal Prefix
5771                rowVal[4] = s2b("'"); // Literal Suffix
5772                rowVal[5] = s2b("[(M)]"); // Create Params
5773                rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
5774                                .getBytes();
5775 
5776                // Nullable
5777                rowVal[7] = s2b("false"); // Case Sensitive
5778                rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
5779                                .getBytes();
5780 
5781                // Searchable
5782                rowVal[9] = s2b("false"); // Unsignable
5783                rowVal[10] = s2b("false"); // Fixed Prec Scale
5784                rowVal[11] = s2b("false"); // Auto Increment
5785                rowVal[12] = s2b("TIMESTAMP"); // Locale Type Name
5786                rowVal[13] = s2b("0"); // Minimum Scale
5787                rowVal[14] = s2b("0"); // Maximum Scale
5788                rowVal[15] = s2b("0"); // SQL Data Type (not used)
5789                rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
5790                rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
5791                tuples.add(rowVal);
5792 
5793                return buildResultSet(fields, tuples);
5794        }
5795 
5796        /**
5797         * JDBC 2.0 Get a description of the user-defined types defined in a
5798         * particular schema. Schema specific UDTs may have type JAVA_OBJECT,
5799         * STRUCT, or DISTINCT.
5800         * <P>
5801         * Only types matching the catalog, schema, type name and type criteria are
5802         * returned. They are ordered by DATA_TYPE, TYPE_SCHEM and TYPE_NAME. The
5803         * type name parameter may be a fully qualified name. In this case, the
5804         * catalog and schemaPattern parameters are ignored.
5805         * </p>
5806         * <P>
5807         * Each type description has the following columns:
5808         * <OL>
5809         * <li> <B>TYPE_CAT</B> String => the type's catalog (may be null) </li>
5810         * <li> <B>TYPE_SCHEM</B> String => type's schema (may be null) </li>
5811         * <li> <B>TYPE_NAME</B> String => type name </li>
5812         * <li> <B>CLASS_NAME</B> String => Java class name </li>
5813         * <li> <B>DATA_TYPE</B> String => type value defined in java.sql.Types.
5814         * One of JAVA_OBJECT, STRUCT, or DISTINCT </li>
5815         * <li> <B>REMARKS</B> String => explanatory comment on the type </li>
5816         * </ol>
5817         * </p>
5818         * <P>
5819         * <B>Note:</B> If the driver does not support UDTs then an empty result
5820         * set is returned.
5821         * </p>
5822         * 
5823         * @param catalog
5824         *            a catalog name; "" retrieves those without a catalog; null
5825         *            means drop catalog name from the selection criteria
5826         * @param schemaPattern
5827         *            a schema name pattern; "" retrieves those without a schema
5828         * @param typeNamePattern
5829         *            a type name pattern; may be a fully qualified name
5830         * @param types
5831         *            a list of user-named types to include (JAVA_OBJECT, STRUCT, or
5832         *            DISTINCT); null returns all types
5833         * @return ResultSet - each row is a type description
5834         * @exception SQLException
5835         *                if a database-access error occurs.
5836         */
5837        public java.sql.ResultSet getUDTs(String catalog, String schemaPattern,
5838                        String typeNamePattern, int[] types) throws SQLException {
5839                Field[] fields = new Field[6];
5840                fields[0] = new Field("", "TYPE_CAT", Types.VARCHAR, 32);
5841                fields[1] = new Field("", "TYPE_SCHEM", Types.VARCHAR, 32);
5842                fields[2] = new Field("", "TYPE_NAME", Types.VARCHAR, 32);
5843                fields[3] = new Field("", "CLASS_NAME", Types.VARCHAR, 32);
5844                fields[4] = new Field("", "DATA_TYPE", Types.VARCHAR, 32);
5845                fields[5] = new Field("", "REMARKS", Types.VARCHAR, 32);
5846 
5847                ArrayList tuples = new ArrayList();
5848 
5849                return buildResultSet(fields, tuples);
5850        }
5851 
5852        /**
5853         * What's the url for this database?
5854         * 
5855         * @return the url or null if it can't be generated
5856         * @throws SQLException
5857         *             DOCUMENT ME!
5858         */
5859        public String getURL() throws SQLException {
5860                return this.conn.getURL();
5861        }
5862 
5863        /**
5864         * What's our user name as known to the database?
5865         * 
5866         * @return our database user name
5867         * @throws SQLException
5868         *             DOCUMENT ME!
5869         */
5870        public String getUserName() throws SQLException {
5871                if (this.conn.getUseHostsInPrivileges()) {
5872                        Statement stmt = null;
5873                        ResultSet rs = null;
5874 
5875                        try {
5876                                stmt = this.conn.createStatement();
5877                                stmt.setEscapeProcessing(false);
5878 
5879                                rs = stmt.executeQuery("SELECT USER()");
5880                                rs.next();
5881 
5882                                return rs.getString(1);
5883                        } finally {
5884                                if (rs != null) {
5885                                        try {
5886                                                rs.close();
5887                                        } catch (Exception ex) {
5888                                                AssertionFailedException.shouldNotHappen(ex);
5889                                        }
5890 
5891                                        rs = null;
5892                                }
5893 
5894                                if (stmt != null) {
5895                                        try {
5896                                                stmt.close();
5897                                        } catch (Exception ex) {
5898                                                AssertionFailedException.shouldNotHappen(ex);
5899                                        }
5900 
5901                                        stmt = null;
5902                                }
5903                        }
5904                }
5905 
5906                return this.conn.getUser();
5907        }
5908 
5909        /**
5910         * Get a description of a table's columns that are automatically updated
5911         * when any value in a row is updated. They are unordered.
5912         * <P>
5913         * Each column description has the following columns:
5914         * <OL>
5915         * <li> <B>SCOPE</B> short => is not used </li>
5916         * <li> <B>COLUMN_NAME</B> String => column name </li>
5917         * <li> <B>DATA_TYPE</B> short => SQL data type from java.sql.Types </li>
5918         * <li> <B>TYPE_NAME</B> String => Data source dependent type name </li>
5919         * <li> <B>COLUMN_SIZE</B> int => precision </li>
5920         * <li> <B>BUFFER_LENGTH</B> int => length of column value in bytes </li>
5921         * <li> <B>DECIMAL_DIGITS</B> short => scale </li>
5922         * <li> <B>PSEUDO_COLUMN</B> short => is this a pseudo column like an
5923         * Oracle ROWID
5924         * <UL>
5925         * <li> versionColumnUnknown - may or may not be pseudo column </li>
5926         * <li> versionColumnNotPseudo - is NOT a pseudo column </li>
5927         * <li> versionColumnPseudo - is a pseudo column </li>
5928         * </ul>
5929         * </li>
5930         * </ol>
5931         * </p>
5932         * 
5933         * @param catalog
5934         *            a catalog name; "" retrieves those without a catalog
5935         * @param schema
5936         *            a schema name; "" retrieves those without a schema
5937         * @param table
5938         *            a table name
5939         * @return ResultSet each row is a column description
5940         * @throws SQLException
5941         *             DOCUMENT ME!
5942         */
5943        public java.sql.ResultSet getVersionColumns(String catalog, String schema,
5944                        String table) throws SQLException {
5945                Field[] fields = new Field[8];
5946                fields[0] = new Field("", "SCOPE", Types.SMALLINT, 5);
5947                fields[1] = new Field("", "COLUMN_NAME", Types.CHAR, 32);
5948                fields[2] = new Field("", "DATA_TYPE", Types.SMALLINT, 5);
5949                fields[3] = new Field("", "TYPE_NAME", Types.CHAR, 16);
5950                fields[4] = new Field("", "COLUMN_SIZE", Types.CHAR, 16);
5951                fields[5] = new Field("", "BUFFER_LENGTH", Types.CHAR, 16);
5952                fields[6] = new Field("", "DECIMAL_DIGITS", Types.CHAR, 16);
5953                fields[7] = new Field("", "PSEUDO_COLUMN", Types.SMALLINT, 5);
5954 
5955                return buildResultSet(fields, new ArrayList());
5956 
5957                // do TIMESTAMP columns count?
5958        }
5959 
5960        /**
5961         * JDBC 2.0 Determine whether or not a visible row insert can be detected by
5962         * calling ResultSet.rowInserted().
5963         * 
5964         * @param type
5965         *            set type, i.e. ResultSet.TYPE_XXX
5966         * @return true if changes are detected by the resultset type
5967         * @exception SQLException
5968         *                if a database-access error occurs.
5969         */
5970        public boolean insertsAreDetected(int type) throws SQLException {
5971                return false;
5972        }
5973 
5974        /**
5975         * Does a catalog appear at the start of a qualified table name? (Otherwise
5976         * it appears at the end)
5977         * 
5978         * @return true if it appears at the start
5979         * @throws SQLException
5980         *             DOCUMENT ME!
5981         */
5982        public boolean isCatalogAtStart() throws SQLException {
5983                return true;
5984        }
5985 
5986        /**
5987         * Is the database in read-only mode?
5988         * 
5989         * @return true if so
5990         * @throws SQLException
5991         *             DOCUMENT ME!
5992         */
5993        public boolean isReadOnly() throws SQLException {
5994                return false;
5995        }
5996 
5997        /**
5998         * @see DatabaseMetaData#locatorsUpdateCopy()
5999         */
6000        public boolean locatorsUpdateCopy() throws SQLException {
6001                return !this.conn.getEmulateLocators();
6002        }
6003 
6004        /**
6005         * Are concatenations between NULL and non-NULL values NULL? A JDBC
6006         * compliant driver always returns true.
6007         * 
6008         * @return true if so
6009         * @throws SQLException
6010         *             DOCUMENT ME!
6011         */
6012        public boolean nullPlusNonNullIsNull() throws SQLException {
6013                return true;
6014        }
6015 
6016        /**
6017         * Are NULL values sorted at the end regardless of sort order?
6018         * 
6019         * @return true if so
6020         * @throws SQLException
6021         *             DOCUMENT ME!
6022         */
6023        public boolean nullsAreSortedAtEnd() throws SQLException {
6024                return false;
6025        }
6026 
6027        /**
6028         * Are NULL values sorted at the start regardless of sort order?
6029         * 
6030         * @return true if so
6031         * @throws SQLException
6032         *             DOCUMENT ME!
6033         */
6034        public boolean nullsAreSortedAtStart() throws SQLException {
6035                return (this.conn.versionMeetsMinimum(4, 0, 2) && !this.conn
6036                                .versionMeetsMinimum(4, 0, 11));
6037        }
6038 
6039        /**
6040         * Are NULL values sorted high?
6041         * 
6042         * @return true if so
6043         * @throws SQLException
6044         *             DOCUMENT ME!
6045         */
6046        public boolean nullsAreSortedHigh() throws SQLException {
6047                return false;
6048        }
6049 
6050        /**
6051         * Are NULL values sorted low?
6052         * 
6053         * @return true if so
6054         * @throws SQLException
6055         *             DOCUMENT ME!
6056         */
6057        public boolean nullsAreSortedLow() throws SQLException {
6058                return !nullsAreSortedHigh();
6059        }
6060 
6061        /**
6062         * DOCUMENT ME!
6063         * 
6064         * @param type
6065         *            DOCUMENT ME!
6066         * @return DOCUMENT ME!
6067         * @throws SQLException
6068         *             DOCUMENT ME!
6069         */
6070        public boolean othersDeletesAreVisible(int type) throws SQLException {
6071                return false;
6072        }
6073 
6074        /**
6075         * DOCUMENT ME!
6076         * 
6077         * @param type
6078         *            DOCUMENT ME!
6079         * @return DOCUMENT ME!
6080         * @throws SQLException
6081         *             DOCUMENT ME!
6082         */
6083        public boolean othersInsertsAreVisible(int type) throws SQLException {
6084                return false;
6085        }
6086 
6087        /**
6088         * JDBC 2.0 Determine whether changes made by others are visible.
6089         * 
6090         * @param type
6091         *            set type, i.e. ResultSet.TYPE_XXX
6092         * @return true if changes are visible for the result set type
6093         * @exception SQLException
6094         *                if a database-access error occurs.
6095         */
6096        public boolean othersUpdatesAreVisible(int type) throws SQLException {
6097                return false;
6098        }
6099 
6100        /**
6101         * DOCUMENT ME!
6102         * 
6103         * @param type
6104         *            DOCUMENT ME!
6105         * @return DOCUMENT ME!
6106         * @throws SQLException
6107         *             DOCUMENT ME!
6108         */
6109        public boolean ownDeletesAreVisible(int type) throws SQLException {
6110                return false;
6111        }
6112 
6113        /**
6114         * DOCUMENT ME!
6115         * 
6116         * @param type
6117         *            DOCUMENT ME!
6118         * @return DOCUMENT ME!
6119         * @throws SQLException
6120         *             DOCUMENT ME!
6121         */
6122        public boolean ownInsertsAreVisible(int type) throws SQLException {
6123                return false;
6124        }
6125 
6126        /**
6127         * JDBC 2.0 Determine whether a result set's own changes visible.
6128         * 
6129         * @param type
6130         *            set type, i.e. ResultSet.TYPE_XXX
6131         * @return true if changes are visible for the result set type
6132         * @exception SQLException
6133         *                if a database-access error occurs.
6134         */
6135        public boolean ownUpdatesAreVisible(int type) throws SQLException {
6136                return false;
6137        }
6138 
6139        private LocalAndReferencedColumns parseTableStatusIntoLocalAndReferencedColumns(
6140                        String keysComment) throws SQLException {
6141                // keys will equal something like this:
6142                // (parent_service_id child_service_id) REFER
6143                // ds/subservices(parent_service_id child_service_id)
6144                //
6145                // simple-columned keys: (m) REFER
6146                // airline/tt(a)
6147                //
6148                // multi-columned keys : (m n) REFER
6149                // airline/vv(a b)
6150                //
6151                // parse of the string into three phases:
6152                // 1: parse the opening parentheses to determine how many results there
6153                // will be
6154                // 2: read in the schema name/table name
6155                // 3: parse the closing parentheses
6156 
6157                String columnsDelimitter = ","; // what version did this change in?
6158 
6159                char quoteChar = this.quotedId.length() == 0 ? 0 : this.quotedId
6160                                .charAt(0);
6161 
6162                int indexOfOpenParenLocalColumns = StringUtils
6163                                .indexOfIgnoreCaseRespectQuotes(0, keysComment, "(", quoteChar,
6164                                                true);
6165 
6166                if (indexOfOpenParenLocalColumns == -1) {
6167                        throw SQLError.createSQLException("Error parsing foreign keys definition,"
6168                                        + " couldn't find start of local columns list.",
6169                                        SQLError.SQL_STATE_GENERAL_ERROR);
6170                }
6171 
6172                String constraintName = removeQuotedId(keysComment.substring(0,
6173                                indexOfOpenParenLocalColumns).trim());
6174                keysComment = keysComment.substring(indexOfOpenParenLocalColumns,
6175                                keysComment.length());
6176 
6177                String keysCommentTrimmed = keysComment.trim();
6178 
6179                int indexOfCloseParenLocalColumns = StringUtils
6180                                .indexOfIgnoreCaseRespectQuotes(0, keysCommentTrimmed, ")",
6181                                                quoteChar, true);
6182 
6183                if (indexOfCloseParenLocalColumns == -1) {
6184                        throw SQLError.createSQLException("Error parsing foreign keys definition,"
6185                                        + " couldn't find end of local columns list.",
6186                                        SQLError.SQL_STATE_GENERAL_ERROR);
6187                }
6188 
6189                String localColumnNamesString = keysCommentTrimmed.substring(1,
6190                                indexOfCloseParenLocalColumns);
6191 
6192                int indexOfRefer = StringUtils.indexOfIgnoreCaseRespectQuotes(0,
6193                                keysCommentTrimmed, "REFER ", this.quotedId.charAt(0), true);
6194 
6195                if (indexOfRefer == -1) {
6196                        throw SQLError.createSQLException("Error parsing foreign keys definition,"
6197                                        + " couldn't find start of referenced tables list.",
6198                                        SQLError.SQL_STATE_GENERAL_ERROR);
6199                }
6200 
6201                int indexOfOpenParenReferCol = StringUtils
6202                                .indexOfIgnoreCaseRespectQuotes(indexOfRefer,
6203                                                keysCommentTrimmed, "(", quoteChar, false);
6204 
6205                if (indexOfOpenParenReferCol == -1) {
6206                        throw SQLError.createSQLException("Error parsing foreign keys definition,"
6207                                        + " couldn't find start of referenced columns list.",
6208                                        SQLError.SQL_STATE_GENERAL_ERROR);
6209                }
6210 
6211                String referCatalogTableString = keysCommentTrimmed.substring(
6212                                indexOfRefer + "REFER ".length(), indexOfOpenParenReferCol);
6213 
6214                int indexOfSlash = StringUtils.indexOfIgnoreCaseRespectQuotes(0,
6215                                referCatalogTableString, "/", this.quotedId.charAt(0), false);
6216 
6217                if (indexOfSlash == -1) {
6218                        throw SQLError.createSQLException("Error parsing foreign keys definition,"
6219                                        + " couldn't find name of referenced catalog.",
6220                                        SQLError.SQL_STATE_GENERAL_ERROR);
6221                }
6222 
6223                String referCatalog = removeQuotedId(referCatalogTableString.substring(
6224                                0, indexOfSlash));
6225                String referTable = removeQuotedId(referCatalogTableString.substring(
6226                                indexOfSlash + 1).trim());
6227 
6228                int indexOfCloseParenRefer = StringUtils
6229                                .indexOfIgnoreCaseRespectQuotes(indexOfOpenParenReferCol,
6230                                                keysCommentTrimmed, ")", quoteChar, true);
6231 
6232                if (indexOfCloseParenRefer == -1) {
6233                        throw SQLError.createSQLException("Error parsing foreign keys definition,"
6234                                        + " couldn't find end of referenced columns list.",
6235                                        SQLError.SQL_STATE_GENERAL_ERROR);
6236                }
6237 
6238                String referColumnNamesString = keysCommentTrimmed.substring(
6239                                indexOfOpenParenReferCol + 1, indexOfCloseParenRefer);
6240 
6241                List referColumnsList = StringUtils.split(referColumnNamesString,
6242                                columnsDelimitter, this.quotedId, this.quotedId, false);
6243                List localColumnsList = StringUtils.split(localColumnNamesString,
6244                                columnsDelimitter, this.quotedId, this.quotedId, false);
6245 
6246                return new LocalAndReferencedColumns(localColumnsList,
6247                                referColumnsList, constraintName, referCatalog, referTable);
6248        }
6249 
6250        private String removeQuotedId(String s) {
6251                if (s == null) {
6252                        return null;
6253                }
6254 
6255                if (this.quotedId.equals("")) {
6256                        return s;
6257                }
6258 
6259                s = s.trim();
6260 
6261                int frontOffset = 0;
6262                int backOffset = s.length();
6263                int quoteLength = this.quotedId.length();
6264 
6265                if (s.startsWith(this.quotedId)) {
6266                        frontOffset = quoteLength;
6267                }
6268 
6269                if (s.endsWith(this.quotedId)) {
6270                        backOffset -= quoteLength;
6271                }
6272 
6273                return s.substring(frontOffset, backOffset);
6274        }
6275 
6276        /**
6277         * Converts the given string to bytes, using the connection's character
6278         * encoding, or if not available, the JVM default encoding.
6279         * 
6280         * @param s
6281         *            DOCUMENT ME!
6282         * @return DOCUMENT ME!
6283         */
6284        private byte[] s2b(String s) throws SQLException {
6285                if (s == null) {
6286                        return null;
6287                }
6288                
6289                if ((this.conn != null) && this.conn.getUseUnicode()) {
6290                        try {
6291                                String encoding = this.conn.getEncoding();
6292 
6293                                if (encoding == null) {
6294                                        return s.getBytes();
6295                                }
6296 
6297                                SingleByteCharsetConverter converter = this.conn
6298                                                .getCharsetConverter(encoding);
6299 
6300                                if (converter != null) {
6301                                        return converter.toBytes(s);
6302                                }
6303 
6304                                return s.getBytes(encoding);
6305                        } catch (java.io.UnsupportedEncodingException E) {
6306                                return s.getBytes();
6307                        }
6308                }
6309 
6310                return s.getBytes();
6311        }
6312 
6313        /**
6314         * Does the database store mixed case unquoted SQL identifiers in lower
6315         * case?
6316         * 
6317         * @return true if so
6318         * @throws SQLException
6319         *             DOCUMENT ME!
6320         */
6321        public boolean storesLowerCaseIdentifiers() throws SQLException {
6322                return this.conn.lowerCaseTableNames();
6323        }
6324 
6325        /**
6326         * Does the database store mixed case quoted SQL identifiers in lower case?
6327         * A JDBC compliant driver will always return false.
6328         * 
6329         * @return true if so
6330         * @throws SQLException
6331         *             DOCUMENT ME!
6332         */
6333        public boolean storesLowerCaseQuotedIdentifiers() throws SQLException {
6334                return this.conn.lowerCaseTableNames();
6335        }
6336 
6337        /**
6338         * Does the database store mixed case unquoted SQL identifiers in mixed
6339         * case?
6340         * 
6341         * @return true if so
6342         * @throws SQLException
6343         *             DOCUMENT ME!
6344         */
6345        public boolean storesMixedCaseIdentifiers() throws SQLException {
6346                return !this.conn.lowerCaseTableNames();
6347        }
6348 
6349        /**
6350         * Does the database store mixed case quoted SQL identifiers in mixed case?
6351         * A JDBC compliant driver will always return false.
6352         * 
6353         * @return true if so
6354         * @throws SQLException
6355         *             DOCUMENT ME!
6356         */
6357        public boolean storesMixedCaseQuotedIdentifiers() throws SQLException {
6358                return !this.conn.lowerCaseTableNames();
6359        }
6360 
6361        /**
6362         * Does the database store mixed case unquoted SQL identifiers in upper
6363         * case?
6364         * 
6365         * @return true if so
6366         * @throws SQLException
6367         *             DOCUMENT ME!
6368         */
6369        public boolean storesUpperCaseIdentifiers() throws SQLException {
6370                return false;
6371        }
6372 
6373        /**
6374         * Does the database store mixed case quoted SQL identifiers in upper case?
6375         * A JDBC compliant driver will always return true.
6376         * 
6377         * @return true if so
6378         * @throws SQLException
6379         *             DOCUMENT ME!
6380         */
6381        public boolean storesUpperCaseQuotedIdentifiers() throws SQLException {
6382                return true; // not actually true, but required by JDBC spec!?
6383        }
6384 
6385        /**
6386         * Is "ALTER TABLE" with add column supported?
6387         * 
6388         * @return true if so
6389         * @throws SQLException
6390         *             DOCUMENT ME!
6391         */
6392        public boolean supportsAlterTableWithAddColumn() throws SQLException {
6393                return true;
6394        }
6395 
6396        /**
6397         * Is "ALTER TABLE" with drop column supported?
6398         * 
6399         * @return true if so
6400         * @throws SQLException
6401         *             DOCUMENT ME!
6402         */
6403        public boolean supportsAlterTableWithDropColumn() throws SQLException {
6404                return true;
6405        }
6406 
6407        /**
6408         * Is the ANSI92 entry level SQL grammar supported? All JDBC compliant
6409         * drivers must return true.
6410         * 
6411         * @return true if so
6412         * @throws SQLException
6413         *             DOCUMENT ME!
6414         */
6415        public boolean supportsANSI92EntryLevelSQL() throws SQLException {
6416                return true;
6417        }
6418 
6419        /**
6420         * Is the ANSI92 full SQL grammar supported?
6421         * 
6422         * @return true if so
6423         * @throws SQLException
6424         *             DOCUMENT ME!
6425         */
6426        public boolean supportsANSI92FullSQL() throws SQLException {
6427                return false;
6428        }
6429 
6430        /**
6431         * Is the ANSI92 intermediate SQL grammar supported?
6432         * 
6433         * @return true if so
6434         * @throws SQLException
6435         *             DOCUMENT ME!
6436         */
6437        public boolean supportsANSI92IntermediateSQL() throws SQLException {
6438                return false;
6439        }
6440 
6441        /**
6442         * JDBC 2.0 Return true if the driver supports batch updates, else return
6443         * false.
6444         * 
6445         * @return DOCUMENT ME!
6446         * @throws SQLException
6447         *             DOCUMENT ME!
6448         */
6449        public boolean supportsBatchUpdates() throws SQLException {
6450                return true;
6451        }
6452 
6453        /**
6454         * Can a catalog name be used in a data manipulation statement?
6455         * 
6456         * @return true if so
6457         * @throws SQLException
6458         *             DOCUMENT ME!
6459         */
6460        public boolean supportsCatalogsInDataManipulation() throws SQLException {
6461                // Servers before 3.22 could not do this
6462                return this.conn.versionMeetsMinimum(3, 22, 0);
6463        }
6464 
6465        /**
6466         * Can a catalog name be used in a index definition statement?
6467         * 
6468         * @return true if so
6469         * @throws SQLException
6470         *             DOCUMENT ME!
6471         */
6472        public boolean supportsCatalogsInIndexDefinitions() throws SQLException {
6473                return false;
6474        }
6475 
6476        /**
6477         * Can a catalog name be used in a privilege definition statement?
6478         * 
6479         * @return true if so
6480         * @throws SQLException
6481         *             DOCUMENT ME!
6482         */
6483        public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException {
6484                return false;
6485        }
6486 
6487        /**
6488         * Can a catalog name be used in a procedure call statement?
6489         * 
6490         * @return true if so
6491         * @throws SQLException
6492         *             DOCUMENT ME!
6493         */
6494        public boolean supportsCatalogsInProcedureCalls() throws SQLException {
6495                return false;
6496        }
6497 
6498        /**
6499         * Can a catalog name be used in a table definition statement?
6500         * 
6501         * @return true if so
6502         * @throws SQLException
6503         *             DOCUMENT ME!
6504         */
6505        public boolean supportsCatalogsInTableDefinitions() throws SQLException {
6506                return false;
6507        }
6508 
6509        /**
6510         * Is column aliasing supported?
6511         * <P>
6512         * If so, the SQL AS clause can be used to provide names for computed
6513         * columns or to provide alias names for columns as required. A JDBC
6514         * compliant driver always returns true.
6515         * </p>
6516         * 
6517         * @return true if so
6518         * @throws SQLException
6519         *             DOCUMENT ME!
6520         */
6521        public boolean supportsColumnAliasing() throws SQLException {
6522                return true;
6523        }
6524 
6525        /**
6526         * Is the CONVERT function between SQL types supported?
6527         * 
6528         * @return true if so
6529         * @throws SQLException
6530         *             DOCUMENT ME!
6531         */
6532        public boolean supportsConvert() throws SQLException {
6533                return false;
6534        }
6535 
6536        /**
6537         * Is CONVERT between the given SQL types supported?
6538         * 
6539         * @param fromType
6540         *            the type to convert from
6541         * @param toType
6542         *            the type to convert to
6543         * @return true if so
6544         * @throws SQLException
6545         *             if an error occurs
6546         * @see Types
6547         */
6548        public boolean supportsConvert(int fromType, int toType)
6549                        throws SQLException {
6550                switch (fromType) {
6551                /*
6552                 * The char/binary types can be converted to pretty much anything.
6553                 */
6554                case java.sql.Types.CHAR:
6555                case java.sql.Types.VARCHAR:
6556                case java.sql.Types.LONGVARCHAR:
6557                case java.sql.Types.BINARY:
6558                case java.sql.Types.VARBINARY:
6559                case java.sql.Types.LONGVARBINARY:
6560 
6561                        switch (toType) {
6562                        case java.sql.Types.DECIMAL:
6563                        case java.sql.Types.NUMERIC:
6564                        case java.sql.Types.REAL:
6565                        case java.sql.Types.TINYINT:
6566                        case java.sql.Types.SMALLINT:
6567                        case java.sql.Types.INTEGER:
6568                        case java.sql.Types.BIGINT:
6569                        case java.sql.Types.FLOAT:
6570                        case java.sql.Types.DOUBLE:
6571                        case java.sql.Types.CHAR:
6572                        case java.sql.Types.VARCHAR:
6573                        case java.sql.Types.LONGVARCHAR:
6574                        case java.sql.Types.BINARY:
6575                        case java.sql.Types.VARBINARY:
6576                        case java.sql.Types.LONGVARBINARY:
6577                        case java.sql.Types.OTHER:
6578                        case java.sql.Types.DATE:
6579                        case java.sql.Types.TIME:
6580                        case java.sql.Types.TIMESTAMP:
6581                                return true;
6582 
6583                        default:
6584                                return false;
6585                        }
6586 
6587                /*
6588                 * We don't handle the BIT type yet.
6589                 */
6590                case java.sql.Types.BIT:
6591                        return false;
6592 
6593                /*
6594                 * The numeric types. Basically they can convert among themselves, and
6595                 * with char/binary types.
6596                 */
6597                case java.sql.Types.DECIMAL:
6598                case java.sql.Types.NUMERIC:
6599                case java.sql.Types.REAL:
6600                case java.sql.Types.TINYINT:
6601                case java.sql.Types.SMALLINT:
6602                case java.sql.Types.INTEGER:
6603                case java.sql.Types.BIGINT:
6604                case java.sql.Types.FLOAT:
6605                case java.sql.Types.DOUBLE:
6606 
6607                        switch (toType) {
6608                        case java.sql.Types.DECIMAL:
6609                        case java.sql.Types.NUMERIC:
6610                        case java.sql.Types.REAL:
6611                        case java.sql.Types.TINYINT:
6612                        case java.sql.Types.SMALLINT:
6613                        case java.sql.Types.INTEGER:
6614                        case java.sql.Types.BIGINT:
6615                        case java.sql.Types.FLOAT:
6616                        case java.sql.Types.DOUBLE:
6617                        case java.sql.Types.CHAR:
6618                        case java.sql.Types.VARCHAR:
6619                        case java.sql.Types.LONGVARCHAR:
6620                        case java.sql.Types.BINARY:
6621                        case java.sql.Types.VARBINARY:
6622                        case java.sql.Types.LONGVARBINARY:
6623                                return true;
6624 
6625                        default:
6626                                return false;
6627                        }
6628 
6629                /* MySQL doesn't support a NULL type. */
6630                case java.sql.Types.NULL:
6631                        return false;
6632 
6633                /*
6634                 * With this driver, this will always be a serialized object, so the
6635                 * char/binary types will work.
6636                 */
6637                case java.sql.Types.OTHER:
6638 
6639                        switch (toType) {
6640                        case java.sql.Types.CHAR:
6641                        case java.sql.Types.VARCHAR:
6642                        case java.sql.Types.LONGVARCHAR:
6643                        case java.sql.Types.BINARY:
6644                        case java.sql.Types.VARBINARY:
6645                        case java.sql.Types.LONGVARBINARY:
6646                                return true;
6647 
6648                        default:
6649                                return false;
6650                        }
6651 
6652                /* Dates can be converted to char/binary types. */
6653                case java.sql.Types.DATE:
6654 
6655                        switch (toType) {
6656                        case java.sql.Types.CHAR:
6657                        case java.sql.Types.VARCHAR:
6658                        case java.sql.Types.LONGVARCHAR:
6659                        case java.sql.Types.BINARY:
6660                        case java.sql.Types.VARBINARY:
6661                        case java.sql.Types.LONGVARBINARY:
6662                                return true;
6663 
6664                        default:
6665                                return false;
6666                        }
6667 
6668                /* Time can be converted to char/binary types */
6669                case java.sql.Types.TIME:
6670 
6671                        switch (toType) {
6672                        case java.sql.Types.CHAR:
6673                        case java.sql.Types.VARCHAR:
6674                        case java.sql.Types.LONGVARCHAR:
6675                        case java.sql.Types.BINARY:
6676                        case java.sql.Types.VARBINARY:
6677                        case java.sql.Types.LONGVARBINARY:
6678                                return true;
6679 
6680                        default:
6681                                return false;
6682                        }
6683 
6684                /*
6685                 * Timestamp can be converted to char/binary types and date/time types
6686                 * (with loss of precision).
6687                 */
6688                case java.sql.Types.TIMESTAMP:
6689 
6690                        switch (toType) {
6691                        case java.sql.Types.CHAR:
6692                        case java.sql.Types.VARCHAR:
6693                        case java.sql.Types.LONGVARCHAR:
6694                        case java.sql.Types.BINARY:
6695                        case java.sql.Types.VARBINARY:
6696                        case java.sql.Types.LONGVARBINARY:
6697                        case java.sql.Types.TIME:
6698                        case java.sql.Types.DATE:
6699                                return true;
6700 
6701                        default:
6702                                return false;
6703                        }
6704 
6705                /* We shouldn't get here! */
6706                default:
6707                        return false; // not sure
6708                }
6709        }
6710 
6711        /**
6712         * Is the ODBC Core SQL grammar supported?
6713         * 
6714         * @return true if so
6715         * @throws SQLException
6716         *             DOCUMENT ME!
6717         */
6718        public boolean supportsCoreSQLGrammar() throws SQLException {
6719                return true;
6720        }
6721 
6722        /**
6723         * Are correlated subqueries supported? A JDBC compliant driver always
6724         * returns true.
6725         * 
6726         * @return true if so
6727         * @throws SQLException
6728         *             DOCUMENT ME!
6729         */
6730        public boolean supportsCorrelatedSubqueries() throws SQLException {
6731                return this.conn.versionMeetsMinimum(4, 1, 0);
6732        }
6733 
6734        /**
6735         * Are both data definition and data manipulation statements within a
6736         * transaction supported?
6737         * 
6738         * @return true if so
6739         * @throws SQLException
6740         *             DOCUMENT ME!
6741         */
6742        public boolean supportsDataDefinitionAndDataManipulationTransactions()
6743                        throws SQLException {
6744                return false;
6745        }
6746 
6747        /**
6748         * Are only data manipulation statements within a transaction supported?
6749         * 
6750         * @return true if so
6751         * @throws SQLException
6752         *             DOCUMENT ME!
6753         */
6754        public boolean supportsDataManipulationTransactionsOnly()
6755                        throws SQLException {
6756                return false;
6757        }
6758 
6759        /**
6760         * If table correlation names are supported, are they restricted to be
6761         * different from the names of the tables? A JDBC compliant driver always
6762         * returns true.
6763         * 
6764         * @return true if so
6765         * @throws SQLException
6766         *             DOCUMENT ME!
6767         */
6768        public boolean supportsDifferentTableCorrelationNames() throws SQLException {
6769                return true;
6770        }
6771 
6772        /**
6773         * Are expressions in "ORDER BY" lists supported?
6774         * 
6775         * @return true if so
6776         * @throws SQLException
6777         *             DOCUMENT ME!
6778         */
6779        public boolean supportsExpressionsInOrderBy() throws SQLException {
6780                return true;
6781        }
6782 
6783        /**
6784         * Is the ODBC Extended SQL grammar supported?
6785         * 
6786         * @return true if so
6787         * @throws SQLException
6788         *             DOCUMENT ME!
6789         */
6790        public boolean supportsExtendedSQLGrammar() throws SQLException {
6791                return false;
6792        }
6793 
6794        /**
6795         * Are full nested outer joins supported?
6796         * 
6797         * @return true if so
6798         * @throws SQLException
6799         *             DOCUMENT ME!
6800         */
6801        public boolean supportsFullOuterJoins() throws SQLException {
6802                return false;
6803        }
6804 
6805        /**
6806         * JDBC 3.0
6807         * 
6808         * @return DOCUMENT ME!
6809         */
6810        public boolean supportsGetGeneratedKeys() {
6811                return true;
6812        }
6813 
6814        /**
6815         * Is some form of "GROUP BY" clause supported?
6816         * 
6817         * @return true if so
6818         * @throws SQLException
6819         *             DOCUMENT ME!
6820         */
6821        public boolean supportsGroupBy() throws SQLException {
6822                return true;
6823        }
6824 
6825        /**
6826         * Can a "GROUP BY" clause add columns not in the SELECT provided it
6827         * specifies all the columns in the SELECT?
6828         * 
6829         * @return true if so
6830         * @throws SQLException
6831         *             DOCUMENT ME!
6832         */
6833        public boolean supportsGroupByBeyondSelect() throws SQLException {
6834                return true;
6835        }
6836 
6837        /**
6838         * Can a "GROUP BY" clause use columns not in the SELECT?
6839         * 
6840         * @return true if so
6841         * @throws SQLException
6842         *             DOCUMENT ME!
6843         */
6844        public boolean supportsGroupByUnrelated() throws SQLException {
6845                return true;
6846        }
6847 
6848        /**
6849         * Is the SQL Integrity Enhancement Facility supported?
6850         * 
6851         * @return true if so
6852         * @throws SQLException
6853         *             DOCUMENT ME!
6854         */
6855        public boolean supportsIntegrityEnhancementFacility() throws SQLException {
6856                if (!this.conn.getOverrideSupportsIntegrityEnhancementFacility()) {
6857                        return false;
6858                } 
6859                
6860                return true;
6861        }
6862 
6863        /**
6864         * Is the escape character in "LIKE" clauses supported? A JDBC compliant
6865         * driver always returns true.
6866         * 
6867         * @return true if so
6868         * @throws SQLException
6869         *             DOCUMENT ME!
6870         */
6871        public boolean supportsLikeEscapeClause() throws SQLException {
6872                return true;
6873        }
6874 
6875        /**
6876         * Is there limited support for outer joins? (This will be true if
6877         * supportFullOuterJoins is true.)
6878         * 
6879         * @return true if so
6880         * @throws SQLException
6881         *             DOCUMENT ME!
6882         */
6883        public boolean supportsLimitedOuterJoins() throws SQLException {
6884                return true;
6885        }
6886 
6887        /**
6888         * Is the ODBC Minimum SQL grammar supported? All JDBC compliant drivers
6889         * must return true.
6890         * 
6891         * @return true if so
6892         * @throws SQLException
6893         *             DOCUMENT ME!
6894         */
6895        public boolean supportsMinimumSQLGrammar() throws SQLException {
6896                return true;
6897        }
6898 
6899        /**
6900         * Does the database support mixed case unquoted SQL identifiers?
6901         * 
6902         * @return true if so
6903         * @throws SQLException
6904         *             DOCUMENT ME!
6905         */
6906        public boolean supportsMixedCaseIdentifiers() throws SQLException {
6907                return !this.conn.lowerCaseTableNames();
6908        }
6909 
6910        /**
6911         * Does the database support mixed case quoted SQL identifiers? A JDBC
6912         * compliant driver will always return true.
6913         * 
6914         * @return true if so
6915         * @throws SQLException
6916         *             DOCUMENT ME!
6917         */
6918        public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException {
6919                return !this.conn.lowerCaseTableNames();
6920        }
6921 
6922        /**
6923         * @see DatabaseMetaData#supportsMultipleOpenResults()
6924         */
6925        public boolean supportsMultipleOpenResults() throws SQLException {
6926                return true;
6927        }
6928 
6929        /**
6930         * Are multiple ResultSets from a single execute supported?
6931         * 
6932         * @return true if so
6933         * @throws SQLException
6934         *             DOCUMENT ME!
6935         */
6936        public boolean supportsMultipleResultSets() throws SQLException {
6937                return false;
6938        }
6939 
6940        /**
6941         * Can we have multiple transactions open at once (on different
6942         * connections)?
6943         * 
6944         * @return true if so
6945         * @throws SQLException
6946         *             DOCUMENT ME!
6947         */
6948        public boolean supportsMultipleTransactions() throws SQLException {
6949                return true;
6950        }
6951 
6952        /**
6953         * @see DatabaseMetaData#supportsNamedParameters()
6954         */
6955        public boolean supportsNamedParameters() throws SQLException {
6956                return false;
6957        }
6958 
6959        /**
6960         * Can columns be defined as non-nullable? A JDBC compliant driver always
6961         * returns true.
6962         * 
6963         * @return true if so
6964         * @throws SQLException
6965         *             DOCUMENT ME!
6966         */
6967        public boolean supportsNonNullableColumns() throws SQLException {
6968                return true;
6969        }
6970 
6971        /**
6972         * Can cursors remain open across commits?
6973         * 
6974         * @return true if so
6975         * @throws SQLException
6976         *             if a database access error occurs
6977         * @see Connection#disableAutoClose
6978         */
6979        public boolean supportsOpenCursorsAcrossCommit() throws SQLException {
6980                return false;
6981        }
6982 
6983        /**
6984         * Can cursors remain open across rollbacks?
6985         * 
6986         * @return true if so
6987         * @throws SQLException
6988         *             if an error occurs
6989         * @see Connection#disableAutoClose
6990         */
6991        public boolean supportsOpenCursorsAcrossRollback() throws SQLException {
6992                return false;
6993        }
6994 
6995        /**
6996         * Can statements remain open across commits?
6997         * 
6998         * @return true if so
6999         * @throws SQLException
7000         *             if an error occurs
7001         * @see Connection#disableAutoClose
7002         */
7003        public boolean supportsOpenStatementsAcrossCommit() throws SQLException {
7004                return false;
7005        }
7006 
7007        /**
7008         * Can statements remain open across rollbacks?
7009         * 
7010         * @return true if so
7011         * @throws SQLException
7012         *             if an error occurs
7013         * @see Connection#disableAutoClose
7014         */
7015        public boolean supportsOpenStatementsAcrossRollback() throws SQLException {
7016                return false;
7017        }
7018 
7019        /**
7020         * Can an "ORDER BY" clause use columns not in the SELECT?
7021         * 
7022         * @return true if so
7023         * @throws SQLException
7024         *             DOCUMENT ME!
7025         */
7026        public boolean supportsOrderByUnrelated() throws SQLException {
7027                return false;
7028        }
7029 
7030        /**
7031         * Is some form of outer join supported?
7032         * 
7033         * @return true if so
7034         * @throws SQLException
7035         *             DOCUMENT ME!
7036         */
7037        public boolean supportsOuterJoins() throws SQLException {
7038                return true;
7039        }
7040 
7041        /**
7042         * Is positioned DELETE supported?
7043         * 
7044         * @return true if so
7045         * @throws SQLException
7046         *             DOCUMENT ME!
7047         */
7048        public boolean supportsPositionedDelete() throws SQLException {
7049                return false;
7050        }
7051 
7052        /**
7053         * Is positioned UPDATE supported?
7054         * 
7055         * @return true if so
7056         * @throws SQLException
7057         *             DOCUMENT ME!
7058         */
7059        public boolean supportsPositionedUpdate() throws SQLException {
7060                return false;
7061        }
7062 
7063        /**
7064         * JDBC 2.0 Does the database support the concurrency type in combination
7065         * with the given result set type?
7066         * 
7067         * @param type
7068         *            defined in java.sql.ResultSet
7069         * @param concurrency
7070         *            type defined in java.sql.ResultSet
7071         * @return true if so
7072         * @exception SQLException
7073         *                if a database-access error occurs.
7074         * @see Connection
7075         */
7076        public boolean supportsResultSetConcurrency(int type, int concurrency)
7077                        throws SQLException {
7078                switch (type) {
7079                case ResultSet.TYPE_SCROLL_INSENSITIVE:
7080                        if ((concurrency == ResultSet.CONCUR_READ_ONLY)
7081                                        || (concurrency == ResultSet.CONCUR_UPDATABLE)) {
7082                                return true;
7083                        } else {
7084                                throw SQLError.createSQLException(
7085                                                "Illegal arguments to supportsResultSetConcurrency()",
7086                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
7087                        }
7088                case ResultSet.TYPE_FORWARD_ONLY:
7089                        if ((concurrency == ResultSet.CONCUR_READ_ONLY)
7090                                        || (concurrency == ResultSet.CONCUR_UPDATABLE)) {
7091                                return true;
7092                        } else {
7093                                throw SQLError.createSQLException(
7094                                                "Illegal arguments to supportsResultSetConcurrency()",
7095                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
7096                        }
7097                case ResultSet.TYPE_SCROLL_SENSITIVE:
7098                        return false;
7099                default:
7100                        throw SQLError.createSQLException(
7101                                        "Illegal arguments to supportsResultSetConcurrency()",
7102                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
7103                }
7104 
7105        }
7106 
7107        /**
7108         * @see DatabaseMetaData#supportsResultSetHoldability(int)
7109         */
7110        public boolean supportsResultSetHoldability(int holdability)
7111                        throws SQLException {
7112                return (holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT);
7113        }
7114 
7115        /**
7116         * JDBC 2.0 Does the database support the given result set type?
7117         * 
7118         * @param type
7119         *            defined in java.sql.ResultSet
7120         * @return true if so
7121         * @exception SQLException
7122         *                if a database-access error occurs.
7123         * @see Connection
7124         */
7125        public boolean supportsResultSetType(int type) throws SQLException {
7126                return (type == ResultSet.TYPE_SCROLL_INSENSITIVE);
7127        }
7128 
7129        /**
7130         * @see DatabaseMetaData#supportsSavepoints()
7131         */
7132        public boolean supportsSavepoints() throws SQLException {
7133 
7134                return (this.conn.versionMeetsMinimum(4, 0, 14) || this.conn
7135                                .versionMeetsMinimum(4, 1, 1));
7136        }
7137 
7138        /**
7139         * Can a schema name be used in a data manipulation statement?
7140         * 
7141         * @return true if so
7142         * @throws SQLException
7143         *             DOCUMENT ME!
7144         */
7145        public boolean supportsSchemasInDataManipulation() throws SQLException {
7146                return false;
7147        }
7148 
7149        /**
7150         * Can a schema name be used in an index definition statement?
7151         * 
7152         * @return true if so
7153         * @throws SQLException
7154         *             DOCUMENT ME!
7155         */
7156        public boolean supportsSchemasInIndexDefinitions() throws SQLException {
7157                return false;
7158        }
7159 
7160        /**
7161         * Can a schema name be used in a privilege definition statement?
7162         * 
7163         * @return true if so
7164         * @throws SQLException
7165         *             DOCUMENT ME!
7166         */
7167        public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException {
7168                return false;
7169        }
7170 
7171        /**
7172         * Can a schema name be used in a procedure call statement?
7173         * 
7174         * @return true if so
7175         * @throws SQLException
7176         *             DOCUMENT ME!
7177         */
7178        public boolean supportsSchemasInProcedureCalls() throws SQLException {
7179                return false;
7180        }
7181 
7182        /**
7183         * Can a schema name be used in a table definition statement?
7184         * 
7185         * @return true if so
7186         * @throws SQLException
7187         *             DOCUMENT ME!
7188         */
7189        public boolean supportsSchemasInTableDefinitions() throws SQLException {
7190                return false;
7191        }
7192 
7193        /**
7194         * Is SELECT for UPDATE supported?
7195         * 
7196         * @return true if so
7197         * @throws SQLException
7198         *             DOCUMENT ME!
7199         */
7200        public boolean supportsSelectForUpdate() throws SQLException {
7201                return this.conn.versionMeetsMinimum(4, 0, 0);
7202        }
7203 
7204        /**
7205         * @see DatabaseMetaData#supportsStatementPooling()
7206         */
7207        public boolean supportsStatementPooling() throws SQLException {
7208                return false;
7209        }
7210 
7211        /**
7212         * Are stored procedure calls using the stored procedure escape syntax
7213         * supported?
7214         * 
7215         * @return true if so
7216         * @throws SQLException
7217         *             DOCUMENT ME!
7218         */
7219        public boolean supportsStoredProcedures() throws SQLException {
7220                return this.conn.versionMeetsMinimum(5, 0, 0);
7221        }
7222 
7223        /**
7224         * Are subqueries in comparison expressions supported? A JDBC compliant
7225         * driver always returns true.
7226         * 
7227         * @return true if so
7228         * @throws SQLException
7229         *             DOCUMENT ME!
7230         */
7231        public boolean supportsSubqueriesInComparisons() throws SQLException {
7232                return this.conn.versionMeetsMinimum(4, 1, 0);
7233        }
7234 
7235        /**
7236         * Are subqueries in exists expressions supported? A JDBC compliant driver
7237         * always returns true.
7238         * 
7239         * @return true if so
7240         * @throws SQLException
7241         *             DOCUMENT ME!
7242         */
7243        public boolean supportsSubqueriesInExists() throws SQLException {
7244                return this.conn.versionMeetsMinimum(4, 1, 0);
7245        }
7246 
7247        /**
7248         * Are subqueries in "in" statements supported? A JDBC compliant driver
7249         * always returns true.
7250         * 
7251         * @return true if so
7252         * @throws SQLException
7253         *             DOCUMENT ME!
7254         */
7255        public boolean supportsSubqueriesInIns() throws SQLException {
7256                return this.conn.versionMeetsMinimum(4, 1, 0);
7257        }
7258 
7259        /**
7260         * Are subqueries in quantified expressions supported? A JDBC compliant
7261         * driver always returns true.
7262         * 
7263         * @return true if so
7264         * @throws SQLException
7265         *             DOCUMENT ME!
7266         */
7267        public boolean supportsSubqueriesInQuantifieds() throws SQLException {
7268                return this.conn.versionMeetsMinimum(4, 1, 0);
7269        }
7270 
7271        /**
7272         * Are table correlation names supported? A JDBC compliant driver always
7273         * returns true.
7274         * 
7275         * @return true if so
7276         * @throws SQLException
7277         *             DOCUMENT ME!
7278         */
7279        public boolean supportsTableCorrelationNames() throws SQLException {
7280                return true;
7281        }
7282 
7283        /**
7284         * Does the database support the given transaction isolation level?
7285         * 
7286         * @param level
7287         *            the values are defined in java.sql.Connection
7288         * @return true if so
7289         * @throws SQLException
7290         *             if a database access error occurs
7291         * @see Connection
7292         */
7293        public boolean supportsTransactionIsolationLevel(int level)
7294                        throws SQLException {
7295                if (this.conn.supportsIsolationLevel()) {
7296                        switch (level) {
7297                        case java.sql.Connection.TRANSACTION_READ_COMMITTED:
7298                        case java.sql.Connection.TRANSACTION_READ_UNCOMMITTED:
7299                        case java.sql.Connection.TRANSACTION_REPEATABLE_READ:
7300                        case java.sql.Connection.TRANSACTION_SERIALIZABLE:
7301                                return true;
7302 
7303                        default:
7304                                return false;
7305                        }
7306                }
7307 
7308                return false;
7309        }
7310 
7311        /**
7312         * Are transactions supported? If not, commit is a noop and the isolation
7313         * level is TRANSACTION_NONE.
7314         * 
7315         * @return true if transactions are supported
7316         * @throws SQLException
7317         *             DOCUMENT ME!
7318         */
7319        public boolean supportsTransactions() throws SQLException {
7320                return this.conn.supportsTransactions();
7321        }
7322 
7323        /**
7324         * Is SQL UNION supported? A JDBC compliant driver always returns true.
7325         * 
7326         * @return true if so
7327         * @throws SQLException
7328         *             DOCUMENT ME!
7329         */
7330        public boolean supportsUnion() throws SQLException {
7331                return this.conn.versionMeetsMinimum(4, 0, 0);
7332        }
7333 
7334        /**
7335         * Is SQL UNION ALL supported? A JDBC compliant driver always returns true.
7336         * 
7337         * @return true if so
7338         * @throws SQLException
7339         *             DOCUMENT ME!
7340         */
7341        public boolean supportsUnionAll() throws SQLException {
7342                return this.conn.versionMeetsMinimum(4, 0, 0);
7343        }
7344 
7345        /**
7346         * JDBC 2.0 Determine whether or not a visible row update can be detected by
7347         * calling ResultSet.rowUpdated().
7348         * 
7349         * @param type
7350         *            set type, i.e. ResultSet.TYPE_XXX
7351         * @return true if changes are detected by the resultset type
7352         * @exception SQLException
7353         *                if a database-access error occurs.
7354         */
7355        public boolean updatesAreDetected(int type) throws SQLException {
7356                return false;
7357        }
7358 
7359        /**
7360         * Does the database use a file for each table?
7361         * 
7362         * @return true if the database uses a local file for each table
7363         * @throws SQLException
7364         *             DOCUMENT ME!
7365         */
7366        public boolean usesLocalFilePerTable() throws SQLException {
7367                return false;
7368        }
7369 
7370        /**
7371         * Does the database store tables in a local file?
7372         * 
7373         * @return true if so
7374         * @throws SQLException
7375         *             DOCUMENT ME!
7376         */
7377        public boolean usesLocalFiles() throws SQLException {
7378                return false;
7379        }
7380}

[all classes][com.mysql.jdbc]
EMMA 2.0.4217 (C) Vladimir Roubtsov