/* Copyright (C) 2002 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.mysql.jdbc; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; import java.util.TreeMap; /** * JDBC Interface to Mysql functions * * <p> * This class provides information about the database as a whole. * </p> * * <p> * Many of the methods here return lists of information in ResultSets. You can * use the normal ResultSet methods such as getString and getInt to retrieve * the data from these ResultSets. If a given form of metadata is not * available, these methods show throw a java.sql.SQLException. * </p> * * <p> * Some of these methods take arguments that are String patterns. These * methods all have names such as fooPattern. Within a pattern String "%" * means match any substring of 0 or more characters and "_" means match any * one character. * </p> * * @author Mark Matthews * @version $Id: DatabaseMetaData.java,v 1.27.2.33 2004/01/13 21:56:18 mmatthew Exp $ */ public class DatabaseMetaData implements java.sql.DatabaseMetaData { private static final byte[] TABLE_AS_BYTES = "TABLE".getBytes(); /** The table type for generic tables that support foreign keys. */ private static final String SUPPORTS_FK = "SUPPORTS_FK"; // // Column indexes used by all DBMD foreign key // ResultSets // private static final int PKTABLE_CAT = 0; private static final int PKTABLE_SCHEM = 1; private static final int PKTABLE_NAME = 2; private static final int PKCOLUMN_NAME = 3; private static final int FKTABLE_CAT = 4; private static final int FKTABLE_SCHEM = 5; private static final int FKTABLE_NAME = 6; private static final int FKCOLUMN_NAME = 7; private static final int KEY_SEQ = 8; private static final int UPDATE_RULE = 9; private static final int DELETE_RULE = 10; private static final int FK_NAME = 11; private static final int PK_NAME = 12; private static final int DEFERRABILITY = 13; /** The connection to the database */ private Connection conn; /** The 'current' database name being used */ private String database = null; /** What character to use when quoting identifiers */ private String quotedId = null; /** * Creates a new DatabaseMetaData object. * * @param conn DOCUMENT ME! * @param database DOCUMENT ME! */ public DatabaseMetaData(Connection conn, String database) { this.conn = conn; this.database = database; try { this.quotedId = this.conn.supportsQuotedIdentifiers() ? getIdentifierQuoteString() : ""; } catch (SQLException sqlEx) { // Forced by API, never thrown from getIdentifierQuoteString() in this // implementation. AssertionFailedException.shouldNotHappen(sqlEx); } } /** * @see DatabaseMetaData#getAttributes(String, String, String, String) */ public java.sql.ResultSet getAttributes(String arg0, String arg1, String arg2, String arg3) throws SQLException { Field[] fields = new Field[21]; fields[0] = new Field("", "TYPE_CAT", Types.CHAR, 32); fields[1] = new Field("", "TYPE_SCHEM", Types.CHAR, 32); fields[2] = new Field("", "TYPE_NAME", Types.CHAR, 32); fields[3] = new Field("", "ATTR_NAME", Types.CHAR, 32); fields[4] = new Field("", "DATA_TYPE", Types.SMALLINT, 32); fields[5] = new Field("", "ATTR_TYPE_NAME", Types.CHAR, 32); fields[6] = new Field("", "ATTR_SIZE", Types.INTEGER, 32); fields[7] = new Field("", "DECIMAL_DIGITS", Types.INTEGER, 32); fields[8] = new Field("", "NUM_PREC_RADIX", Types.INTEGER, 32); fields[9] = new Field("", "NULLABLE ", Types.INTEGER, 32); fields[10] = new Field("", "REMARKS", Types.CHAR, 32); fields[11] = new Field("", "ATTR_DEF", Types.CHAR, 32); fields[12] = new Field("", "SQL_DATA_TYPE", Types.INTEGER, 32); fields[13] = new Field("", "SQL_DATETIME_SUB", Types.INTEGER, 32); fields[14] = new Field("", "CHAR_OCTET_LENGTH", Types.INTEGER, 32); fields[15] = new Field("", "ORDINAL_POSITION", Types.INTEGER, 32); fields[16] = new Field("", "IS_NULLABLE", Types.CHAR, 32); fields[17] = new Field("", "SCOPE_CATALOG", Types.CHAR, 32); fields[18] = new Field("", "SCOPE_SCHEMA", Types.CHAR, 32); fields[19] = new Field("", "SCOPE_TABLE", Types.CHAR, 32); fields[20] = new Field("", "SOURCE_DATA_TYPE", Types.SMALLINT, 32); return buildResultSet(fields, new ArrayList()); } /** * Get a description of a table's optimal set of columns that uniquely * identifies a row. They are ordered by SCOPE. * * <P> * Each column description has the following columns: * * <OL> * <li> * <B>SCOPE</B> short => actual scope of result * * <UL> * <li> * bestRowTemporary - very temporary, while using row * </li> * <li> * bestRowTransaction - valid for remainder of current transaction * </li> * <li> * bestRowSession - valid for remainder of current session * </li> * </ul> * * </li> * <li> * <B>COLUMN_NAME</B> String => column name * </li> * <li> * <B>DATA_TYPE</B> short => SQL data type from java.sql.Types * </li> * <li> * <B>TYPE_NAME</B> String => Data source dependent type name * </li> * <li> * <B>COLUMN_SIZE</B> int => precision * </li> * <li> * <B>BUFFER_LENGTH</B> int => not used * </li> * <li> * <B>DECIMAL_DIGITS</B> short => scale * </li> * <li> * <B>PSEUDO_COLUMN</B> short => is this a pseudo column like an Oracle * ROWID * * <UL> * <li> * bestRowUnknown - may or may not be pseudo column * </li> * <li> * bestRowNotPseudo - is NOT a pseudo column * </li> * <li> * bestRowPseudo - is a pseudo column * </li> * </ul> * * </li> * </ol> * </p> * * @param catalog a catalog name; "" retrieves those without a catalog * @param schema a schema name; "" retrieves those without a schema * @param table a table name * @param scope the scope of interest; use same values as SCOPE * @param nullable include columns that are nullable? * * @return ResultSet each row is a column description * * @throws java.sql.SQLException DOCUMENT ME! */ public java.sql.ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws java.sql.SQLException { Field[] fields = new Field[8]; fields[0] = new Field("", "SCOPE", Types.SMALLINT, 5); fields[1] = new Field("", "COLUMN_NAME", Types.CHAR, 32); fields[2] = new Field("", "DATA_TYPE", Types.SMALLINT, 32); fields[3] = new Field("", "TYPE_NAME", Types.CHAR, 32); fields[4] = new Field("", "COLUMN_SIZE", Types.INTEGER, 10); fields[5] = new Field("", "BUFFER_LENGTH", Types.INTEGER, 10); fields[6] = new Field("", "DECIMAL_DIGITS", Types.INTEGER, 10); fields[7] = new Field("", "PSEUDO_COLUMN", Types.SMALLINT, 5); String databasePart = ""; if (catalog != null) { if (!catalog.equals("")) { databasePart = " FROM " + this.quotedId + catalog + this.quotedId; } } else { databasePart = " FROM " + this.quotedId + this.database + this.quotedId; } if (table == null) { throw new java.sql.SQLException("Table not specified.", SQLError.SQL_STATE_ILLEGAL_ARGUMENT); } ResultSet results = null; Statement stmt = null; try { stmt = this.conn.createStatement(); if (stmt.getMaxRows() != 0) { stmt.setMaxRows(0); } StringBuffer queryBuf = new StringBuffer("SHOW COLUMNS FROM "); queryBuf.append(this.quotedId); queryBuf.append(table); queryBuf.append(this.quotedId); queryBuf.append(databasePart); results = stmt.executeQuery(queryBuf.toString()); ArrayList tuples = new ArrayList(); while (results.next()) { String keyType = results.getString("Key"); if (keyType != null) { if (StringUtils.startsWithIgnoreCase(keyType, "PRI")) { byte[][] rowVal = new byte[8][]; rowVal[0] = Integer.toString(java.sql.DatabaseMetaData.bestRowSession) .getBytes(); rowVal[1] = results.getBytes("Field"); String type = results.getString("Type"); int size = MysqlIO.getMaxBuf(); int decimals = 0; /* * Parse the Type column from MySQL */ if (type.indexOf("enum") != -1) { String temp = type.substring(type.indexOf("("), type.indexOf(")")); java.util.StringTokenizer tokenizer = new java.util.StringTokenizer(temp, ","); int maxLength = 0; while (tokenizer.hasMoreTokens()) { maxLength = Math.max(maxLength, (tokenizer.nextToken().length() - 2)); } size = maxLength; decimals = 0; type = "enum"; } else if (type.indexOf("(") != -1) { if (type.indexOf(",") != -1) { size = Integer.parseInt(type.substring(type .indexOf("(") + 1, type.indexOf(","))); decimals = Integer.parseInt(type.substring(type .indexOf(",") + 1, type.indexOf(")"))); } else { size = Integer.parseInt(type.substring(type .indexOf("(") + 1, type.indexOf(")"))); } type = type.substring(type.indexOf("(")); } rowVal[2] = new byte[0]; // FIXME! rowVal[3] = s2b(type); rowVal[4] = Integer.toString(size + decimals).getBytes(); rowVal[5] = Integer.toString(size + decimals).getBytes(); rowVal[6] = Integer.toString(decimals).getBytes(); rowVal[7] = Integer.toString(java.sql.DatabaseMetaData.bestRowNotPseudo) .getBytes(); tuples.add(rowVal); } } } return buildResultSet(fields, tuples); } finally { if (results != null) { try { results.close(); } catch (Exception ex) { ; } results = null; } if (stmt != null) { try { stmt.close(); } catch (Exception ex) { ; } stmt = null; } } } /** * Does a catalog appear at the start of a qualified table name? (Otherwise * it appears at the end) * * @return true if it appears at the start * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean isCatalogAtStart() throws java.sql.SQLException { return true; } /** * What's the separator between catalog and table name? * * @return the separator string * * @throws java.sql.SQLException DOCUMENT ME! */ public String getCatalogSeparator() throws java.sql.SQLException { return "."; } /** * What's the database vendor's preferred term for "catalog"? * * @return the vendor term * * @throws java.sql.SQLException DOCUMENT ME! */ public String getCatalogTerm() throws java.sql.SQLException { return "database"; } /** * Get the catalog names available in this database. The results are * ordered by catalog name. * * <P> * The catalog column is: * * <OL> * <li> * <B>TABLE_CAT</B> String => catalog name * </li> * </ol> * </p> * * @return ResultSet each row has a single String column that is a catalog * name * * @throws java.sql.SQLException DOCUMENT ME! */ public java.sql.ResultSet getCatalogs() throws java.sql.SQLException { java.sql.ResultSet results = null; java.sql.Statement stmt = null; try { stmt = this.conn.createStatement(); if (stmt.getMaxRows() != 0) { stmt.setMaxRows(0); } results = stmt.executeQuery("SHOW DATABASES"); java.sql.ResultSetMetaData resultsMD = results.getMetaData(); Field[] fields = new Field[1]; fields[0] = new Field("", "TABLE_CAT", Types.VARCHAR, resultsMD.getColumnDisplaySize(1)); ArrayList tuples = new ArrayList(); while (results.next()) { byte[][] rowVal = new byte[1][]; rowVal[0] = results.getBytes(1); tuples.add(rowVal); } return buildResultSet(fields, tuples); } finally { if (results != null) { try { results.close(); } catch (SQLException sqlEx) { AssertionFailedException.shouldNotHappen(sqlEx); } results = null; } if (stmt != null) { try { stmt.close(); } catch (SQLException sqlEx) { AssertionFailedException.shouldNotHappen(sqlEx); } stmt = null; } } } /** * Get a description of the access rights for a table's columns. * * <P> * Only privileges matching the column name criteria are returned. They * are ordered by COLUMN_NAME and PRIVILEGE. * </p> * * <P> * Each privilige description has the following columns: * * <OL> * <li> * <B>TABLE_CAT</B> String => table catalog (may be null) * </li> * <li> * <B>TABLE_SCHEM</B> String => table schema (may be null) * </li> * <li> * <B>TABLE_NAME</B> String => table name * </li> * <li> * <B>COLUMN_NAME</B> String => column name * </li> * <li> * <B>GRANTOR</B> => grantor of access (may be null) * </li> * <li> * <B>GRANTEE</B> String => grantee of access * </li> * <li> * <B>PRIVILEGE</B> String => name of access (SELECT, INSERT, UPDATE, * REFRENCES, ...) * </li> * <li> * <B>IS_GRANTABLE</B> String => "YES" if grantee is permitted to grant to * others; "NO" if not; null if unknown * </li> * </ol> * </p> * * @param catalog a catalog name; "" retrieves those without a catalog * @param schema a schema name; "" retrieves those without a schema * @param table a table name * @param columnNamePattern a column name pattern * * @return ResultSet each row is a column privilege description * * @throws java.sql.SQLException if a database access error occurs * * @see #getSearchStringEscape */ public java.sql.ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern) throws java.sql.SQLException { Field[] fields = new Field[8]; fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 64); fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 1); fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 64); fields[3] = new Field("", "COLUMN_NAME", Types.CHAR, 64); fields[4] = new Field("", "GRANTOR", Types.CHAR, 77); fields[5] = new Field("", "GRANTEE", Types.CHAR, 77); fields[6] = new Field("", "PRIVILEGE", Types.CHAR, 64); fields[7] = new Field("", "IS_GRANTABLE", Types.CHAR, 3); StringBuffer grantQuery = new StringBuffer( "SELECT c.host, c.db, t.grantor, c.user, " + "c.table_name, c.column_name, c.column_priv " + "from mysql.columns_priv c, mysql.tables_priv t " + "where c.host = t.host and c.db = t.db and " + "c.table_name = t.table_name "); if ((catalog != null) && (catalog.length() != 0)) { grantQuery.append(" AND c.db='"); grantQuery.append(catalog); grantQuery.append("' "); ; } grantQuery.append(" AND c.table_name ='"); grantQuery.append(table); grantQuery.append("' AND c.column_name like '"); grantQuery.append(columnNamePattern); grantQuery.append("'"); Statement stmt = null; ResultSet results = null; ArrayList grantRows = new ArrayList(); try { stmt = this.conn.createStatement(); if (stmt.getMaxRows() != 0) { stmt.setMaxRows(0); } results = stmt.executeQuery(grantQuery.toString()); while (results.next()) { String host = results.getString(1); String database = results.getString(2); String grantor = results.getString(3); String user = results.getString(4); if ((user == null) || (user.length() == 0)) { user = "%"; } StringBuffer fullUser = new StringBuffer(user); if ((host != null) && this.conn.useHostsInPrivileges()) { fullUser.append("@"); fullUser.append(host); } String columnName = results.getString(6); String allPrivileges = results.getString(7); if (allPrivileges != null) { allPrivileges = allPrivileges.toUpperCase(); StringTokenizer st = new StringTokenizer(allPrivileges, ","); while (st.hasMoreTokens()) { String privilege = st.nextToken().trim(); byte[][] tuple = new byte[8][]; tuple[0] = s2b(database); tuple[1] = null; tuple[2] = s2b(table); tuple[3] = s2b(columnName); if (grantor != null) { tuple[4] = s2b(grantor); } else { tuple[4] = null; } tuple[5] = s2b(fullUser.toString()); tuple[6] = s2b(privilege); tuple[7] = null; grantRows.add(tuple); } } } } finally { if (results != null) { try { results.close(); } catch (Exception ex) { ; } results = null; } if (stmt != null) { try { stmt.close(); } catch (Exception ex) { ; } stmt = null; } } return buildResultSet(fields, grantRows); } /** * Get a description of table columns available in a catalog. * * <P> * Only column descriptions matching the catalog, schema, table and column * name criteria are returned. They are ordered by TABLE_SCHEM, * TABLE_NAME and ORDINAL_POSITION. * </p> * * <P> * Each column description has the following columns: * * <OL> * <li> * <B>TABLE_CAT</B> String => table catalog (may be null) * </li> * <li> * <B>TABLE_SCHEM</B> String => table schema (may be null) * </li> * <li> * <B>TABLE_NAME</B> String => table name * </li> * <li> * <B>COLUMN_NAME</B> String => column name * </li> * <li> * <B>DATA_TYPE</B> short => SQL type from java.sql.Types * </li> * <li> * <B>TYPE_NAME</B> String => Data source dependent type name * </li> * <li> * <B>COLUMN_SIZE</B> int => column size. For char or date types this is * the maximum number of characters, for numeric or decimal types this is * precision. * </li> * <li> * <B>BUFFER_LENGTH</B> is not used. * </li> * <li> * <B>DECIMAL_DIGITS</B> int => the number of fractional digits * </li> * <li> * <B>NUM_PREC_RADIX</B> int => Radix (typically either 10 or 2) * </li> * <li> * <B>NULLABLE</B> int => is NULL allowed? * * <UL> * <li> * columnNoNulls - might not allow NULL values * </li> * <li> * columnNullable - definitely allows NULL values * </li> * <li> * columnNullableUnknown - nullability unknown * </li> * </ul> * * </li> * <li> * <B>REMARKS</B> String => comment describing column (may be null) * </li> * <li> * <B>COLUMN_DEF</B> String => default value (may be null) * </li> * <li> * <B>SQL_DATA_TYPE</B> int => unused * </li> * <li> * <B>SQL_DATETIME_SUB</B> int => unused * </li> * <li> * <B>CHAR_OCTET_LENGTH</B> int => for char types the maximum number of * bytes in the column * </li> * <li> * <B>ORDINAL_POSITION</B> int => index of column in table (starting at 1) * </li> * <li> * <B>IS_NULLABLE</B> String => "NO" means column definitely does not allow * NULL values; "YES" means the column might allow NULL values. An empty * string means nobody knows. * </li> * </ol> * </p> * * @param catalog a catalog name; "" retrieves those without a catalog * @param schemaPattern a schema name pattern; "" retrieves those without a * schema * @param tableName a table name pattern * @param columnNamePattern a column name pattern * * @return ResultSet each row is a column description * * @throws java.sql.SQLException if a database access error occurs * * @see #getSearchStringEscape */ public java.sql.ResultSet getColumns(String catalog, String schemaPattern, String tableName, String columnNamePattern) throws java.sql.SQLException { String databasePart = ""; if (columnNamePattern == null) { columnNamePattern = "%"; } if (catalog != null) { if (!catalog.equals("")) { databasePart = " FROM " + this.quotedId + catalog + this.quotedId; } } else { databasePart = " FROM " + this.quotedId + this.database + this.quotedId; } ArrayList tableNameList = new ArrayList(); int tablenameLength = 0; if (tableName == null) { // Select from all tables java.sql.ResultSet tables = null; try { tables = getTables(catalog, schemaPattern, "%", new String[0]); while (tables.next()) { String tableNameFromList = tables.getString("TABLE_NAME"); tableNameList.add(tableNameFromList); if (tableNameFromList.length() > tablenameLength) { tablenameLength = tableNameFromList.length(); } } } finally { if (tables != null) { try { tables.close(); } catch (Exception sqlEx) { AssertionFailedException.shouldNotHappen(sqlEx); } tables = null; } } } else { java.sql.ResultSet tables = null; try { tables = getTables(catalog, schemaPattern, tableName, new String[0]); while (tables.next()) { String tableNameFromList = tables.getString("TABLE_NAME"); tableNameList.add(tableNameFromList); if (tableNameFromList.length() > tablenameLength) { tablenameLength = tableNameFromList.length(); } } } finally { if (tables != null) { try { tables.close(); } catch (SQLException sqlEx) { AssertionFailedException.shouldNotHappen(sqlEx); } tables = null; } } } int catalogLength = 0; if (catalog != null) { catalogLength = catalog.length(); } else { catalog = ""; catalogLength = 0; } java.util.Iterator tableNames = tableNameList.iterator(); Field[] fields = new Field[18]; fields[0] = new Field("", "TABLE_CAT", Types.CHAR, catalogLength); fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 0); fields[2] = new Field("", "TABLE_NAME", Types.CHAR, tablenameLength); fields[3] = new Field("", "COLUMN_NAME", Types.CHAR, 32); fields[4] = new Field("", "DATA_TYPE", Types.SMALLINT, 5); fields[5] = new Field("", "TYPE_NAME", Types.CHAR, 16); fields[6] = new Field("", "COLUMN_SIZE", Types.INTEGER, Integer.toString(Integer.MAX_VALUE).length()); fields[7] = new Field("", "BUFFER_LENGTH", Types.INTEGER, 10); fields[8] = new Field("", "DECIMAL_DIGITS", Types.INTEGER, 10); fields[9] = new Field("", "NUM_PREC_RADIX", Types.INTEGER, 10); fields[10] = new Field("", "NULLABLE", Types.INTEGER, 10); fields[11] = new Field("", "REMARKS", Types.CHAR, 0); fields[12] = new Field("", "COLUMN_DEF", Types.CHAR, 0); fields[13] = new Field("", "SQL_DATA_TYPE", Types.INTEGER, 10); fields[14] = new Field("", "SQL_DATETIME_SUB", Types.INTEGER, 10); fields[15] = new Field("", "CHAR_OCTET_LENGTH", Types.INTEGER, Integer.toString(Integer.MAX_VALUE).length()); fields[16] = new Field("", "ORDINAL_POSITION", Types.INTEGER, 10); fields[17] = new Field("", "IS_NULLABLE", Types.CHAR, 3); ArrayList tuples = new ArrayList(); byte[] connectionCatalogAsBytes = null; if (catalog == null) { connectionCatalogAsBytes = s2b(this.conn.getCatalog()); } else { connectionCatalogAsBytes = s2b(catalog); } while (tableNames.hasNext()) { String tableNamePattern = (String) tableNames.next(); Statement stmt = null; ResultSet results = null; try { stmt = this.conn.createStatement(); if (stmt.getMaxRows() != 0) { stmt.setMaxRows(0); } StringBuffer queryBuf = new StringBuffer("SHOW COLUMNS FROM "); queryBuf.append(this.quotedId); queryBuf.append(tableNamePattern); queryBuf.append(this.quotedId); queryBuf.append(databasePart); queryBuf.append(" LIKE '"); queryBuf.append(columnNamePattern); queryBuf.append("'"); results = stmt.executeQuery(queryBuf.toString()); int ordPos = 1; while (results.next()) { byte[][] rowVal = new byte[18][]; rowVal[0] = connectionCatalogAsBytes; // TABLE_CAT rowVal[1] = null; // TABLE_SCHEM (No schemas in MySQL) rowVal[2] = s2b(tableNamePattern); // TABLE_NAME rowVal[3] = results.getBytes("Field"); String typeInfo = results.getString("Type"); if (Driver.DEBUG) { System.out.println("Type: " + typeInfo); } String mysqlType = ""; if (typeInfo.indexOf("(") != -1) { mysqlType = typeInfo.substring(0, typeInfo.indexOf("(")); } else { mysqlType = typeInfo; } if (this.conn.capitalizeDBMDTypes()) { mysqlType = mysqlType.toUpperCase(); } /* * Convert to XOPEN (thanks JK) */ rowVal[4] = Integer.toString(MysqlDefs.mysqlToJavaType( mysqlType)).getBytes(); // DATA_TYPE (jdbc) rowVal[5] = s2b(mysqlType); // TYPE_NAME (native) // Figure Out the Size if (typeInfo != null) { if (StringUtils.startsWithIgnoreCase(typeInfo, "enum") || StringUtils.startsWithIgnoreCase(typeInfo, "set")) { String temp = typeInfo.substring(typeInfo.indexOf( "("), typeInfo.lastIndexOf(")")); java.util.StringTokenizer tokenizer = new java.util.StringTokenizer(temp, ","); int maxLength = 0; while (tokenizer.hasMoreTokens()) { maxLength = Math.max(maxLength, (tokenizer.nextToken().length() - 2)); } rowVal[6] = Integer.toString(maxLength).getBytes(); rowVal[8] = new byte[] { (byte) '0' }; } else if (typeInfo.indexOf(",") != -1) { // Numeric with decimals String size = typeInfo.substring((typeInfo.indexOf( "(") + 1), (typeInfo.indexOf(","))); String decimals = typeInfo.substring((typeInfo .indexOf(",") + 1), (typeInfo.indexOf(")"))); rowVal[6] = s2b(size); rowVal[8] = s2b(decimals); } else { String size = "0"; /* If the size is specified with the DDL, use that */ if (typeInfo.indexOf("(") != -1) { size = typeInfo.substring((typeInfo.indexOf("(") + 1), (typeInfo.indexOf(")"))); } else if (typeInfo.equalsIgnoreCase("tinyint")) { size = "1"; } else if (typeInfo.equalsIgnoreCase("smallint")) { size = "6"; } else if (typeInfo.equalsIgnoreCase("mediumint")) { size = "6"; } else if (typeInfo.equalsIgnoreCase("int")) { size = "11"; } else if (typeInfo.equalsIgnoreCase("integer")) { size = "11"; } else if (typeInfo.equalsIgnoreCase("bigint")) { size = "25"; } else if (typeInfo.equalsIgnoreCase("int24")) { size = "25"; } else if (typeInfo.equalsIgnoreCase("real")) { size = "12"; } else if (typeInfo.equalsIgnoreCase("float")) { size = "12"; } else if (typeInfo.equalsIgnoreCase("decimal")) { size = "12"; } else if (typeInfo.equalsIgnoreCase("numeric")) { size = "12"; } else if (typeInfo.equalsIgnoreCase("double")) { size = "22"; } else if (typeInfo.equalsIgnoreCase("char")) { size = "1"; } else if (typeInfo.equalsIgnoreCase("varchar")) { size = "255"; } else if (typeInfo.equalsIgnoreCase("date")) { size = "10"; } else if (typeInfo.equalsIgnoreCase("time")) { size = "8"; } else if (typeInfo.equalsIgnoreCase("timestamp")) { size = "19"; } else if (typeInfo.equalsIgnoreCase("datetime")) { size = "19"; } else if (typeInfo.equalsIgnoreCase("tinyblob")) { size = "255"; } else if (typeInfo.equalsIgnoreCase("blob")) { size = "65535"; } else if (typeInfo.equalsIgnoreCase("mediumblob")) { size = "16277215"; } else if (typeInfo.equalsIgnoreCase("longblob")) { size = Integer.toString(Integer.MAX_VALUE); } else if (typeInfo.equalsIgnoreCase("tinytext")) { size = "255"; } else if (typeInfo.equalsIgnoreCase("text")) { size = "65535"; } else if (typeInfo.equalsIgnoreCase("mediumtext")) { size = "16277215"; } else if (typeInfo.equalsIgnoreCase("longtext")) { size = Integer.toString(Integer.MAX_VALUE); } else if (typeInfo.equalsIgnoreCase("enum")) { size = "255"; } else if (typeInfo.equalsIgnoreCase("set")) { size = "255"; } rowVal[6] = size.getBytes(); rowVal[8] = new byte[] { (byte) '0' }; } } else { rowVal[8] = new byte[] { (byte) '0' }; rowVal[6] = new byte[] { (byte) '0' }; } rowVal[7] = Integer.toString(MysqlIO.getMaxBuf()).getBytes(); // BUFFER_LENGTH rowVal[9] = new byte[] { (byte) '1', (byte) '0' }; // NUM_PREC_RADIX (is this right for char?) String nullable = results.getString("Null"); // Nullable? if (nullable != null) { if (nullable.equals("YES")) { rowVal[10] = Integer.toString(java.sql.DatabaseMetaData.columnNullable) .getBytes(); rowVal[17] = new String("YES").getBytes(); // IS_NULLABLE } else { rowVal[10] = Integer.toString(java.sql.DatabaseMetaData.columnNoNulls) .getBytes(); rowVal[17] = "NO".getBytes(); } } else { rowVal[10] = Integer.toString(java.sql.DatabaseMetaData.columnNoNulls) .getBytes(); rowVal[17] = "NO".getBytes(); } // // Doesn't always have this field, depending on version // // // REMARK column // try { rowVal[11] = results.getBytes("Extra"); } catch (Exception E) { rowVal[11] = new byte[0]; } // COLUMN_DEF rowVal[12] = results.getBytes("Default"); rowVal[13] = new byte[] { (byte) '0' }; // SQL_DATA_TYPE rowVal[14] = new byte[] { (byte) '0' }; // SQL_DATE_TIME_SUB rowVal[15] = rowVal[6]; // CHAR_OCTET_LENGTH rowVal[16] = Integer.toString(ordPos++).getBytes(); // ORDINAL_POSITION tuples.add(rowVal); } } finally { if (results != null) { try { results.close(); } catch (Exception ex) { ; } results = null; } if (stmt != null) { try { stmt.close(); } catch (Exception ex) { ; } stmt = null; } } } java.sql.ResultSet results = buildResultSet(fields, tuples); return results; } /** * JDBC 2.0 Return the connection that produced this metadata object. * * @return the connection that produced this metadata object. * * @throws SQLException if a database error occurs */ public java.sql.Connection getConnection() throws SQLException { return (java.sql.Connection) this.conn; } /** * Get a description of the foreign key columns in the foreign key table * that reference the primary key columns of the primary key table * (describe how one table imports another's key.) This should normally * return a single foreign key/primary key pair (most tables only import a * foreign key from a table once.) They are ordered by FKTABLE_CAT, * FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ. * * <P> * Each foreign key column description has the following columns: * * <OL> * <li> * <B>PKTABLE_CAT</B> String => primary key table catalog (may be null) * </li> * <li> * <B>PKTABLE_SCHEM</B> String => primary key table schema (may be null) * </li> * <li> * <B>PKTABLE_NAME</B> String => primary key table name * </li> * <li> * <B>PKCOLUMN_NAME</B> String => primary key column name * </li> * <li> * <B>FKTABLE_CAT</B> String => foreign key table catalog (may be null) * being exported (may be null) * </li> * <li> * <B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null) * being exported (may be null) * </li> * <li> * <B>FKTABLE_NAME</B> String => foreign key table name being exported * </li> * <li> * <B>FKCOLUMN_NAME</B> String => foreign key column name being exported * </li> * <li> * <B>KEY_SEQ</B> short => sequence number within foreign key * </li> * <li> * <B>UPDATE_RULE</B> short => What happens to foreign key when primary is * updated: * * <UL> * <li> * importedKeyCascade - change imported key to agree with primary key * update * </li> * <li> * importedKeyRestrict - do not allow update of primary key if it has been * imported * </li> * <li> * importedKeySetNull - change imported key to NULL if its primary key has * been updated * </li> * </ul> * * </li> * <li> * <B>DELETE_RULE</B> short => What happens to the foreign key when primary * is deleted. * * <UL> * <li> * importedKeyCascade - delete rows that import a deleted key * </li> * <li> * importedKeyRestrict - do not allow delete of primary key if it has been * imported * </li> * <li> * importedKeySetNull - change imported key to NULL if its primary key has * been deleted * </li> * </ul> * * </li> * <li> * <B>FK_NAME</B> String => foreign key identifier (may be null) * </li> * <li> * <B>PK_NAME</B> String => primary key identifier (may be null) * </li> * </ol> * </p> * * @param primaryCatalog a catalog name; "" retrieves those without a * catalog * @param primarySchema a schema name pattern; "" retrieves those without a * schema * @param primaryTable a table name * @param foreignCatalog a catalog name; "" retrieves those without a * catalog * @param foreignSchema a schema name pattern; "" retrieves those without a * schema * @param foreignTable a table name * * @return ResultSet each row is a foreign key column description * * @throws java.sql.SQLException if a database access error occurs */ public java.sql.ResultSet getCrossReference(String primaryCatalog, String primarySchema, String primaryTable, String foreignCatalog, String foreignSchema, String foreignTable) throws java.sql.SQLException { if (Driver.TRACE) { Object[] args = { primaryCatalog, primarySchema, primaryTable, foreignCatalog, foreignSchema, foreignTable }; Debug.methodCall(this, "getCrossReference", args); } if (primaryTable == null) { throw new java.sql.SQLException("Table not specified.", SQLError.SQL_STATE_ILLEGAL_ARGUMENT); } Field[] fields = new Field[14]; fields[0] = new Field("", "PKTABLE_CAT", Types.CHAR, 255); fields[1] = new Field("", "PKTABLE_SCHEM", Types.CHAR, 0); fields[2] = new Field("", "PKTABLE_NAME", Types.CHAR, 255); fields[3] = new Field("", "PKCOLUMN_NAME", Types.CHAR, 32); fields[4] = new Field("", "FKTABLE_CAT", Types.CHAR, 255); fields[5] = new Field("", "FKTABLE_SCHEM", Types.CHAR, 0); fields[6] = new Field("", "FKTABLE_NAME", Types.CHAR, 255); fields[7] = new Field("", "FKCOLUMN_NAME", Types.CHAR, 32); fields[8] = new Field("", "KEY_SEQ", Types.SMALLINT, 2); fields[9] = new Field("", "UPDATE_RULE", Types.SMALLINT, 2); fields[10] = new Field("", "DELETE_RULE", Types.SMALLINT, 2); fields[11] = new Field("", "FK_NAME", Types.CHAR, 255); fields[12] = new Field("", "PK_NAME", Types.CHAR, 0); fields[13] = new Field("", "DEFERRABILITY", Types.INTEGER, 2); if (this.conn.getIO().versionMeetsMinimum(3, 23, 0)) { Statement stmt = null; ResultSet fkresults = null; try { /* * Get foreign key information for table */ if (this.conn.getIO().versionMeetsMinimum(3, 23, 50)) { // we can use 'SHOW CREATE TABLE' String database = this.database; if (foreignCatalog != null) { if (!foreignCatalog.equals("")) { database = foreignCatalog; } } fkresults = extractForeignKeyFromCreateTable(this.conn, this, database, null); } else { String databasePart = ""; if (foreignCatalog != null) { if (!foreignCatalog.equals("")) { databasePart = " FROM " + foreignCatalog; } } else { databasePart = " FROM " + this.database; } stmt = this.conn.createStatement(); if (stmt.getMaxRows() != 0) { stmt.setMaxRows(0); } fkresults = stmt.executeQuery("show table status " + databasePart); } String foreignTableWithCase = getTableNameWithCase(foreignTable); String primaryTableWithCase = getTableNameWithCase(primaryTable); /* * Parse imported foreign key information */ ArrayList tuples = new ArrayList(); String dummy; while (fkresults.next()) { String tableType = fkresults.getString("Type"); if ((tableType != null) && (tableType.equalsIgnoreCase("innodb") || tableType.equalsIgnoreCase(SUPPORTS_FK))) { String comment = fkresults.getString("Comment").trim(); if (comment != null) { StringTokenizer commentTokens = new StringTokenizer(comment, ";", false); if (commentTokens.hasMoreTokens()) { dummy = commentTokens.nextToken(); // Skip InnoDB comment } while (commentTokens.hasMoreTokens()) { String keys = commentTokens.nextToken(); // simple-columned keys: (m) REFER airline/tt(a) // multi-columned keys : (m n) REFER airline/vv(a b) int firstLeftParenIndex = keys.indexOf('('); int firstRightParenIndex = keys.indexOf(')'); String constraintName = keys.substring(0, firstLeftParenIndex); String referencingColumns = keys.substring(firstLeftParenIndex + 1, firstRightParenIndex); StringTokenizer referencingColumnsTokenizer = new StringTokenizer(referencingColumns, ", "); int secondLeftParenIndex = keys.indexOf('(', firstRightParenIndex + 1); int secondRightParenIndex = keys.indexOf(')', firstRightParenIndex + 1); String referencedColumns = keys.substring(secondLeftParenIndex + 1, secondRightParenIndex); StringTokenizer referencedColumnsTokenizer = new StringTokenizer(referencedColumns, ", "); int slashIndex = keys.indexOf('/'); String referencedTable = keys.substring(slashIndex + 1, secondLeftParenIndex); int keySeq = 0; while (referencingColumnsTokenizer .hasMoreTokens()) { String referencingColumn = referencingColumnsTokenizer .nextToken(); // one tuple for each table between parenthesis byte[][] tuple = new byte[14][]; tuple[4] = ((foreignCatalog == null) ? null : s2b(foreignCatalog)); tuple[5] = ((foreignSchema == null) ? null : s2b(foreignSchema)); dummy = fkresults.getString("Name"); // FKTABLE_NAME if (dummy.compareTo(foreignTableWithCase) != 0) { continue; } else { tuple[6] = s2b(dummy); } tuple[7] = s2b(referencingColumn); // FKCOLUMN_NAME tuple[0] = ((primaryCatalog == null) ? null : s2b(primaryCatalog)); tuple[1] = ((primarySchema == null) ? null : s2b(primarySchema)); // Skip foreign key if it doesn't refer to the right table if (referencedTable.compareTo( primaryTableWithCase) != 0) { continue; } tuple[2] = s2b(referencedTable); // PKTABLE_NAME tuple[3] = s2b(referencedColumnsTokenizer .nextToken()); // PKCOLUMN_NAME tuple[8] = Integer.toString(keySeq) .getBytes(); // KEY_SEQ int[] actions = getForeignKeyActions(keys); tuple[9] = Integer.toString(actions[1]) .getBytes(); tuple[10] = Integer.toString(actions[0]) .getBytes(); tuple[11] = s2b(constraintName); // FK_NAME tuple[12] = null; // PK_NAME tuple[13] = Integer.toString(java.sql.DatabaseMetaData.importedKeyNotDeferrable) .getBytes(); tuples.add(tuple); keySeq++; } } } } } if (Driver.TRACE) { StringBuffer rows = new StringBuffer(); rows.append("\n"); for (int i = 0; i < tuples.size(); i++) { byte[][] b = (byte[][]) tuples.get(i); rows.append("[Row] "); boolean firstTime = true; for (int j = 0; j < b.length; j++) { if (!firstTime) { rows.append(", "); } else { firstTime = false; } if (b[j] == null) { rows.append("null"); } else { rows.append(new String(b[j])); } } rows.append("\n"); } Debug.returnValue(this, "getCrossReference", rows.toString()); } return buildResultSet(fields, tuples); } finally { if (fkresults != null) { try { fkresults.close(); } catch (Exception sqlEx) { AssertionFailedException.shouldNotHappen(sqlEx); } fkresults = null; } if (stmt != null) { try { stmt.close(); } catch (Exception ex) { ; } stmt = null; } } } else { return buildResultSet(fields, new ArrayList()); } } /** * @see DatabaseMetaData#getDatabaseMajorVersion() */ public int getDatabaseMajorVersion() throws SQLException { return this.conn.getServerMajorVersion(); } /** * @see DatabaseMetaData#getDatabaseMinorVersion() */ public int getDatabaseMinorVersion() throws SQLException { return this.conn.getServerMinorVersion(); } /** * What's the name of this database product? * * @return database product name * * @throws java.sql.SQLException DOCUMENT ME! */ public String getDatabaseProductName() throws java.sql.SQLException { return "MySQL"; } /** * What's the version of this database product? * * @return database version * * @throws java.sql.SQLException DOCUMENT ME! */ public String getDatabaseProductVersion() throws java.sql.SQLException { return this.conn.getServerVersion(); } //---------------------------------------------------------------------- /** * What's the database's default transaction isolation level? The values * are defined in java.sql.Connection. * * @return the default isolation level * * @throws java.sql.SQLException if a database access error occurs * * @see Connection */ public int getDefaultTransactionIsolation() throws java.sql.SQLException { if (this.conn.supportsIsolationLevel()) { return java.sql.Connection.TRANSACTION_READ_COMMITTED; } else { return java.sql.Connection.TRANSACTION_NONE; } } /** * What's this JDBC driver's major version number? * * @return JDBC driver major version */ public int getDriverMajorVersion() { return Driver.getMajorVersionInternal(); } /** * What's this JDBC driver's minor version number? * * @return JDBC driver minor version number */ public int getDriverMinorVersion() { return Driver.getMinorVersionInternal(); } /** * What's the name of this JDBC driver? * * @return JDBC driver name * * @throws java.sql.SQLException DOCUMENT ME! */ public String getDriverName() throws java.sql.SQLException { return "MySQL-AB JDBC Driver"; } /** * What's the version of this JDBC driver? * * @return JDBC driver version * * @throws java.sql.SQLException DOCUMENT ME! */ public String getDriverVersion() throws java.sql.SQLException { return "mysql-connector-java-3.0.10-stable ( $Date: 2004/01/13 21:56:18 $, $Revision: 1.27.2.33 $ )"; } /** * Get a description of a foreign key columns that reference a table's * primary key columns (the foreign keys exported by a table). They are * ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ. * * <P> * Each foreign key column description has the following columns: * * <OL> * <li> * <B>PKTABLE_CAT</B> String => primary key table catalog (may be null) * </li> * <li> * <B>PKTABLE_SCHEM</B> String => primary key table schema (may be null) * </li> * <li> * <B>PKTABLE_NAME</B> String => primary key table name * </li> * <li> * <B>PKCOLUMN_NAME</B> String => primary key column name * </li> * <li> * <B>FKTABLE_CAT</B> String => foreign key table catalog (may be null) * being exported (may be null) * </li> * <li> * <B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null) * being exported (may be null) * </li> * <li> * <B>FKTABLE_NAME</B> String => foreign key table name being exported * </li> * <li> * <B>FKCOLUMN_NAME</B> String => foreign key column name being exported * </li> * <li> * <B>KEY_SEQ</B> short => sequence number within foreign key * </li> * <li> * <B>UPDATE_RULE</B> short => What happens to foreign key when primary is * updated: * * <UL> * <li> * importedKeyCascade - change imported key to agree with primary key * update * </li> * <li> * importedKeyRestrict - do not allow update of primary key if it has been * imported * </li> * <li> * importedKeySetNull - change imported key to NULL if its primary key has * been updated * </li> * </ul> * * </li> * <li> * <B>DELETE_RULE</B> short => What happens to the foreign key when primary * is deleted. * * <UL> * <li> * importedKeyCascade - delete rows that import a deleted key * </li> * <li> * importedKeyRestrict - do not allow delete of primary key if it has been * imported * </li> * <li> * importedKeySetNull - change imported key to NULL if its primary key has * been deleted * </li> * </ul> * * </li> * <li> * <B>FK_NAME</B> String => foreign key identifier (may be null) * </li> * <li> * <B>PK_NAME</B> String => primary key identifier (may be null) * </li> * </ol> * </p> * * @param catalog a catalog name; "" retrieves those without a catalog * @param schema a schema name pattern; "" retrieves those without a schema * @param table a table name * * @return ResultSet each row is a foreign key column description * * @throws java.sql.SQLException if a database access error occurs * * @see #getImportedKeys */ public java.sql.ResultSet getExportedKeys(String catalog, String schema, String table) throws java.sql.SQLException { if (Driver.TRACE) { Object[] args = { catalog, schema, table }; Debug.methodCall(this, "getExportedKeys", args); } if (table == null) { throw new java.sql.SQLException("Table not specified.", SQLError.SQL_STATE_ILLEGAL_ARGUMENT); } Field[] fields = new Field[14]; fields[0] = new Field("", "PKTABLE_CAT", Types.CHAR, 255); fields[1] = new Field("", "PKTABLE_SCHEM", Types.CHAR, 0); fields[2] = new Field("", "PKTABLE_NAME", Types.CHAR, 255); fields[3] = new Field("", "PKCOLUMN_NAME", Types.CHAR, 32); fields[4] = new Field("", "FKTABLE_CAT", Types.CHAR, 255); fields[5] = new Field("", "FKTABLE_SCHEM", Types.CHAR, 0); fields[6] = new Field("", "FKTABLE_NAME", Types.CHAR, 255); fields[7] = new Field("", "FKCOLUMN_NAME", Types.CHAR, 32); fields[8] = new Field("", "KEY_SEQ", Types.SMALLINT, 2); fields[9] = new Field("", "UPDATE_RULE", Types.SMALLINT, 2); fields[10] = new Field("", "DELETE_RULE", Types.SMALLINT, 2); fields[11] = new Field("", "FK_NAME", Types.CHAR, 255); fields[12] = new Field("", "PK_NAME", Types.CHAR, 0); fields[13] = new Field("", "DEFERRABILITY", Types.INTEGER, 2); if (this.conn.getIO().versionMeetsMinimum(3, 23, 0)) { Statement stmt = null; ResultSet fkresults = null; try { /* * Get foreign key information for table */ if (this.conn.getIO().versionMeetsMinimum(3, 23, 50)) { // we can use 'SHOW CREATE TABLE' String database = this.database; if (catalog != null) { if (!catalog.equals("")) { database = catalog; } } fkresults = extractForeignKeyFromCreateTable(this.conn, this, database, null); } else { String databasePart = ""; if (catalog != null) { if (!catalog.equals("")) { databasePart = " FROM " + catalog; } } else { databasePart = " FROM " + this.database; } stmt = this.conn.createStatement(); if (stmt.getMaxRows() != 0) { stmt.setMaxRows(0); } fkresults = stmt.executeQuery("show table status " + databasePart); } // lower-case table name might be turned on String tableNameWithCase = getTableNameWithCase(table); /* * Parse imported foreign key information */ ArrayList tuples = new ArrayList(); while (fkresults.next()) { String tableType = fkresults.getString("Type"); if ((tableType != null) && (tableType.equalsIgnoreCase("innodb") || tableType.equalsIgnoreCase(SUPPORTS_FK))) { String comment = fkresults.getString("Comment").trim(); if (comment != null) { StringTokenizer commentTokens = new StringTokenizer(comment, ";", false); if (commentTokens.hasMoreTokens()) { commentTokens.nextToken(); // Skip InnoDB comment while (commentTokens.hasMoreTokens()) { String keys = commentTokens.nextToken(); getExportKeyResults(catalog, tableNameWithCase, keys, tuples, fkresults.getString("Name")); } } } } } if (Driver.TRACE) { StringBuffer rows = new StringBuffer(); rows.append("\n"); for (int i = 0; i < tuples.size(); i++) { byte[][] b = (byte[][]) tuples.get(i); rows.append("[Row] "); boolean firstTime = true; for (int j = 0; j < b.length; j++) { if (!firstTime) { rows.append(", "); } else { firstTime = false; } if (b[j] == null) { rows.append("null"); } else { rows.append(new String(b[j])); } } rows.append("\n"); } Debug.returnValue(this, "getExportedKeys", rows.toString()); } return buildResultSet(fields, tuples); } finally { if (fkresults != null) { try { fkresults.close(); } catch (SQLException sqlEx) { AssertionFailedException.shouldNotHappen(sqlEx); } fkresults = null; } if (stmt != null) { try { stmt.close(); } catch (Exception ex) { AssertionFailedException.shouldNotHappen(ex); } stmt = null; } } } else { return buildResultSet(fields, new ArrayList()); } } /** * Get all the "extra" characters that can be used in unquoted identifier * names (those beyond a-z, 0-9 and _). * * @return the string containing the extra characters * * @throws java.sql.SQLException DOCUMENT ME! */ public String getExtraNameCharacters() throws java.sql.SQLException { return "#@"; } /** * What's the string used to quote SQL identifiers? This returns a space " * " if identifier quoting isn't supported. A JDBC compliant driver always * uses a double quote character. * * @return the quoting string * * @throws java.sql.SQLException DOCUMENT ME! */ public String getIdentifierQuoteString() throws java.sql.SQLException { if (this.conn.supportsQuotedIdentifiers()) { if (!this.conn.useAnsiQuotedIdentifiers()) { return "`"; } else { return "\""; } } else { return " "; } } /** * Get a description of the primary key columns that are referenced by a * table's foreign key columns (the primary keys imported by a table). * They are ordered by PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME, and * KEY_SEQ. * * <P> * Each primary key column description has the following columns: * * <OL> * <li> * <B>PKTABLE_CAT</B> String => primary key table catalog being imported * (may be null) * </li> * <li> * <B>PKTABLE_SCHEM</B> String => primary key table schema being imported * (may be null) * </li> * <li> * <B>PKTABLE_NAME</B> String => primary key table name being imported * </li> * <li> * <B>PKCOLUMN_NAME</B> String => primary key column name being imported * </li> * <li> * <B>FKTABLE_CAT</B> String => foreign key table catalog (may be null) * </li> * <li> * <B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null) * </li> * <li> * <B>FKTABLE_NAME</B> String => foreign key table name * </li> * <li> * <B>FKCOLUMN_NAME</B> String => foreign key column name * </li> * <li> * <B>KEY_SEQ</B> short => sequence number within foreign key * </li> * <li> * <B>UPDATE_RULE</B> short => What happens to foreign key when primary is * updated: * * <UL> * <li> * importedKeyCascade - change imported key to agree with primary key * update * </li> * <li> * importedKeyRestrict - do not allow update of primary key if it has been * imported * </li> * <li> * importedKeySetNull - change imported key to NULL if its primary key has * been updated * </li> * </ul> * * </li> * <li> * <B>DELETE_RULE</B> short => What happens to the foreign key when primary * is deleted. * * <UL> * <li> * importedKeyCascade - delete rows that import a deleted key * </li> * <li> * importedKeyRestrict - do not allow delete of primary key if it has been * imported * </li> * <li> * importedKeySetNull - change imported key to NULL if its primary key has * been deleted * </li> * </ul> * * </li> * <li> * <B>FK_NAME</B> String => foreign key name (may be null) * </li> * <li> * <B>PK_NAME</B> String => primary key name (may be null) * </li> * </ol> * </p> * * @param catalog a catalog name; "" retrieves those without a catalog * @param schema a schema name pattern; "" retrieves those without a schema * @param table a table name * * @return ResultSet each row is a primary key column description * * @throws java.sql.SQLException if a database access error occurs * * @see #getExportedKeys */ public java.sql.ResultSet getImportedKeys(String catalog, String schema, String table) throws java.sql.SQLException { if (Driver.TRACE) { Object[] args = { catalog, schema, table }; Debug.methodCall(this, "getImportedKeys", args); } if (table == null) { throw new java.sql.SQLException("Table not specified.", SQLError.SQL_STATE_ILLEGAL_ARGUMENT); } Field[] fields = new Field[14]; fields[0] = new Field("", "PKTABLE_CAT", Types.CHAR, 255); fields[1] = new Field("", "PKTABLE_SCHEM", Types.CHAR, 0); fields[2] = new Field("", "PKTABLE_NAME", Types.CHAR, 255); fields[3] = new Field("", "PKCOLUMN_NAME", Types.CHAR, 32); fields[4] = new Field("", "FKTABLE_CAT", Types.CHAR, 255); fields[5] = new Field("", "FKTABLE_SCHEM", Types.CHAR, 0); fields[6] = new Field("", "FKTABLE_NAME", Types.CHAR, 255); fields[7] = new Field("", "FKCOLUMN_NAME", Types.CHAR, 32); fields[8] = new Field("", "KEY_SEQ", Types.SMALLINT, 2); fields[9] = new Field("", "UPDATE_RULE", Types.SMALLINT, 2); fields[10] = new Field("", "DELETE_RULE", Types.SMALLINT, 2); fields[11] = new Field("", "FK_NAME", Types.CHAR, 255); fields[12] = new Field("", "PK_NAME", Types.CHAR, 0); fields[13] = new Field("", "DEFERRABILITY", Types.INTEGER, 2); if (this.conn.getIO().versionMeetsMinimum(3, 23, 0)) { Statement stmt = null; ResultSet fkresults = null; try { /* * Get foreign key information for table */ if (this.conn.getIO().versionMeetsMinimum(3, 23, 50)) { // we can use 'SHOW CREATE TABLE' String database = this.database; if (catalog != null) { if (!catalog.equals("")) { database = catalog; } } fkresults = extractForeignKeyFromCreateTable(this.conn, this, database, table); } else { String databasePart = ""; if (catalog != null) { if (!catalog.equals("")) { databasePart = " FROM " + catalog; } } else { databasePart = " FROM " + this.database; } stmt = this.conn.createStatement(); if (stmt.getMaxRows() != 0) { stmt.setMaxRows(0); } fkresults = stmt.executeQuery("show table status " + databasePart + " like '" + table + "'"); } /* * Parse imported foreign key information */ ArrayList tuples = new ArrayList(); while (fkresults.next()) { String tableType = fkresults.getString("Type"); if ((tableType != null) && (tableType.equalsIgnoreCase("innodb") || tableType.equalsIgnoreCase(SUPPORTS_FK))) { String comment = fkresults.getString("Comment").trim(); if (comment != null) { StringTokenizer commentTokens = new StringTokenizer(comment, ";", false); if (commentTokens.hasMoreTokens()) { commentTokens.nextToken(); // Skip InnoDB comment while (commentTokens.hasMoreTokens()) { String keys = commentTokens.nextToken(); getImportKeyResults(catalog, table, keys, tuples); } } } } } if (Driver.TRACE) { StringBuffer rows = new StringBuffer(); rows.append("\n"); for (int i = 0; i < tuples.size(); i++) { byte[][] b = (byte[][]) tuples.get(i); rows.append("[Row] "); boolean firstTime = true; for (int j = 0; j < b.length; j++) { if (!firstTime) { rows.append(", "); } else { firstTime = false; } if (b[j] == null) { rows.append("null"); } else { rows.append(new String(b[j])); } } rows.append("\n"); } Debug.returnValue(this, "getImportedKeys", rows.toString()); } return buildResultSet(fields, tuples); } finally { if (fkresults != null) { try { fkresults.close(); } catch (SQLException sqlEx) { AssertionFailedException.shouldNotHappen(sqlEx); } fkresults = null; } if (stmt != null) { try { stmt.close(); } catch (Exception ex) { AssertionFailedException.shouldNotHappen(ex); } stmt = null; } } } else { return buildResultSet(fields, new ArrayList()); } } /** * Get a description of a table's indices and statistics. They are ordered * by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION. * * <P> * Each index column description has the following columns: * * <OL> * <li> * <B>TABLE_CAT</B> String => table catalog (may be null) * </li> * <li> * <B>TABLE_SCHEM</B> String => table schema (may be null) * </li> * <li> * <B>TABLE_NAME</B> String => table name * </li> * <li> * <B>NON_UNIQUE</B> boolean => Can index values be non-unique? false when * TYPE is tableIndexStatistic * </li> * <li> * <B>INDEX_QUALIFIER</B> String => index catalog (may be null); null when * TYPE is tableIndexStatistic * </li> * <li> * <B>INDEX_NAME</B> String => index name; null when TYPE is * tableIndexStatistic * </li> * <li> * <B>TYPE</B> short => index type: * * <UL> * <li> * tableIndexStatistic - this identifies table statistics that are returned * in conjuction with a table's index descriptions * </li> * <li> * tableIndexClustered - this is a clustered index * </li> * <li> * tableIndexHashed - this is a hashed index * </li> * <li> * tableIndexOther - this is some other style of index * </li> * </ul> * * </li> * <li> * <B>ORDINAL_POSITION</B> short => column sequence number within index; * zero when TYPE is tableIndexStatistic * </li> * <li> * <B>COLUMN_NAME</B> String => column name; null when TYPE is * tableIndexStatistic * </li> * <li> * <B>ASC_OR_DESC</B> String => column sort sequence, "A" => ascending, "D" * => descending, may be null if sort sequence is not supported; null when * TYPE is tableIndexStatistic * </li> * <li> * <B>CARDINALITY</B> int => When TYPE is tableIndexStatisic then this is * the number of rows in the table; otherwise it is the number of unique * values in the index. * </li> * <li> * <B>PAGES</B> int => When TYPE is tableIndexStatisic then this is the * number of pages used for the table, otherwise it is the number of pages * used for the current index. * </li> * <li> * <B>FILTER_CONDITION</B> String => Filter condition, if any. (may be * null) * </li> * </ol> * </p> * * @param catalog a catalog name; "" retrieves those without a catalog * @param schema a schema name pattern; "" retrieves those without a schema * @param table a table name * @param unique when true, return only indices for unique values; when * false, return indices regardless of whether unique or not * @param approximate when true, result is allowed to reflect approximate * or out of data values; when false, results are requested to be * accurate * * @return ResultSet each row is an index column description * * @throws java.sql.SQLException DOCUMENT ME! */ public java.sql.ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws java.sql.SQLException { /* * MySQL stores index information in the following fields: * * Table * Non_unique * Key_name * Seq_in_index * Column_name * Collation * Cardinality * Sub_part */ String databasePart = ""; if (catalog != null) { if (!catalog.equals("")) { databasePart = " FROM " + this.quotedId + catalog + this.quotedId; } } else { databasePart = " FROM " + this.quotedId + this.database + this.quotedId; } Statement stmt = null; ResultSet results = null; try { stmt = this.conn.createStatement(); if (stmt.getMaxRows() != 0) { stmt.setMaxRows(0); } StringBuffer queryBuf = new StringBuffer("SHOW INDEX FROM "); queryBuf.append(this.quotedId); queryBuf.append(table); queryBuf.append(this.quotedId); queryBuf.append(databasePart); results = stmt.executeQuery(queryBuf.toString()); Field[] fields = new Field[13]; fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 255); fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 0); fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 255); fields[3] = new Field("", "NON_UNIQUE", Types.CHAR, 3); fields[4] = new Field("", "INDEX_QUALIFIER", Types.CHAR, 1); fields[5] = new Field("", "INDEX_NAME", Types.CHAR, 32); fields[6] = new Field("", "TYPE", Types.CHAR, 32); fields[7] = new Field("", "ORDINAL_POSITION", Types.SMALLINT, 5); fields[8] = new Field("", "COLUMN_NAME", Types.CHAR, 32); fields[9] = new Field("", "ASC_OR_DESC", Types.CHAR, 1); fields[10] = new Field("", "CARDINALITY", Types.INTEGER, 10); fields[11] = new Field("", "PAGES", Types.INTEGER, 10); fields[12] = new Field("", "FILTER_CONDITION", Types.CHAR, 32); byte[] connectionCatalogAsBytes; if (catalog == null) { connectionCatalogAsBytes = s2b(this.conn.getCatalog()); } else { connectionCatalogAsBytes = s2b(catalog); } ArrayList rows = new ArrayList(); while (results.next()) { byte[][] row = new byte[14][]; row[0] = connectionCatalogAsBytes; row[1] = null; row[2] = results.getBytes("Table"); row[3] = ((results.getInt("Non_unique") != 0) ? s2b("true") : s2b("false")); row[4] = new byte[0]; row[5] = results.getBytes("Key_name"); row[6] = Integer.toString(java.sql.DatabaseMetaData.tableIndexOther) .getBytes(); row[7] = results.getBytes("Seq_in_index"); row[8] = results.getBytes("Column_name"); row[9] = results.getBytes("Collation"); row[10] = results.getBytes("Cardinality"); row[11] = s2b("0"); row[12] = null; rows.add(row); } java.sql.ResultSet indexInfo = buildResultSet(fields, rows); return indexInfo; } finally { if (results != null) { try { results.close(); } catch (Exception ex) { ; } results = null; } if (stmt != null) { try { stmt.close(); } catch (Exception ex) { ; } stmt = null; } } } /** * @see DatabaseMetaData#getJDBCMajorVersion() */ public int getJDBCMajorVersion() throws SQLException { return 3; } /** * @see DatabaseMetaData#getJDBCMinorVersion() */ public int getJDBCMinorVersion() throws SQLException { return 0; } //---------------------------------------------------------------------- // The following group of methods exposes various limitations // based on the target database with the current driver. // Unless otherwise specified, a result of zero means there is no // limit, or the limit is not known. /** * How many hex characters can you have in an inline binary literal? * * @return max literal length * * @throws java.sql.SQLException DOCUMENT ME! */ public int getMaxBinaryLiteralLength() throws java.sql.SQLException { return 16777208; } /** * What's the maximum length of a catalog name? * * @return max name length in bytes * * @throws java.sql.SQLException DOCUMENT ME! */ public int getMaxCatalogNameLength() throws java.sql.SQLException { return 32; } /** * What's the max length for a character literal? * * @return max literal length * * @throws java.sql.SQLException DOCUMENT ME! */ public int getMaxCharLiteralLength() throws java.sql.SQLException { return 16777208; } /** * What's the limit on column name length? * * @return max literal length * * @throws java.sql.SQLException DOCUMENT ME! */ public int getMaxColumnNameLength() throws java.sql.SQLException { return 64; } /** * What's the maximum number of columns in a "GROUP BY" clause? * * @return max number of columns * * @throws java.sql.SQLException DOCUMENT ME! */ public int getMaxColumnsInGroupBy() throws java.sql.SQLException { return 64; } /** * What's the maximum number of columns allowed in an index? * * @return max columns * * @throws java.sql.SQLException DOCUMENT ME! */ public int getMaxColumnsInIndex() throws java.sql.SQLException { return 16; } /** * What's the maximum number of columns in an "ORDER BY" clause? * * @return max columns * * @throws java.sql.SQLException DOCUMENT ME! */ public int getMaxColumnsInOrderBy() throws java.sql.SQLException { return 64; } /** * What's the maximum number of columns in a "SELECT" list? * * @return max columns * * @throws java.sql.SQLException DOCUMENT ME! */ public int getMaxColumnsInSelect() throws java.sql.SQLException { return 256; } /** * What's maximum number of columns in a table? * * @return max columns * * @throws java.sql.SQLException DOCUMENT ME! */ public int getMaxColumnsInTable() throws java.sql.SQLException { return 512; } /** * How many active connections can we have at a time to this database? * * @return max connections * * @throws java.sql.SQLException DOCUMENT ME! */ public int getMaxConnections() throws java.sql.SQLException { return 0; } /** * What's the maximum cursor name length? * * @return max cursor name length in bytes * * @throws java.sql.SQLException DOCUMENT ME! */ public int getMaxCursorNameLength() throws java.sql.SQLException { return 64; } /** * What's the maximum length of an index (in bytes)? * * @return max index length in bytes * * @throws java.sql.SQLException DOCUMENT ME! */ public int getMaxIndexLength() throws java.sql.SQLException { return 256; } /** * What's the maximum length of a procedure name? * * @return max name length in bytes * * @throws java.sql.SQLException DOCUMENT ME! */ public int getMaxProcedureNameLength() throws java.sql.SQLException { return 0; } /** * What's the maximum length of a single row? * * @return max row size in bytes * * @throws java.sql.SQLException DOCUMENT ME! */ public int getMaxRowSize() throws java.sql.SQLException { return Integer.MAX_VALUE - 8; // Max buffer size - HEADER } /** * What's the maximum length allowed for a schema name? * * @return max name length in bytes * * @throws java.sql.SQLException DOCUMENT ME! */ public int getMaxSchemaNameLength() throws java.sql.SQLException { return 0; } /** * What's the maximum length of a SQL statement? * * @return max length in bytes * * @throws java.sql.SQLException DOCUMENT ME! */ public int getMaxStatementLength() throws java.sql.SQLException { return MysqlIO.getMaxBuf() - 4; // Max buffer - header } /** * How many active statements can we have open at one time to this * database? * * @return the maximum * * @throws java.sql.SQLException DOCUMENT ME! */ public int getMaxStatements() throws java.sql.SQLException { return 0; } /** * What's the maximum length of a table name? * * @return max name length in bytes * * @throws java.sql.SQLException DOCUMENT ME! */ public int getMaxTableNameLength() throws java.sql.SQLException { return 64; } /** * What's the maximum number of tables in a SELECT? * * @return the maximum * * @throws java.sql.SQLException DOCUMENT ME! */ public int getMaxTablesInSelect() throws java.sql.SQLException { return 256; } /** * What's the maximum length of a user name? * * @return max name length in bytes * * @throws java.sql.SQLException DOCUMENT ME! */ public int getMaxUserNameLength() throws java.sql.SQLException { return 16; } /** * Get a comma separated list of math functions. * * @return the list * * @throws java.sql.SQLException DOCUMENT ME! */ public String getNumericFunctions() throws java.sql.SQLException { return "ABS,ACOS,ASIN,ATAN,ATAN2,BIT_COUNT,CEILING,COS," + "COT,DEGREES,EXP,FLOOR,LOG,LOG10,MAX,MIN,MOD,PI,POW," + "POWER,RADIANS,RAND,ROUND,SIN,SQRT,TAN,TRUNCATE"; } /** * Get a description of a table's primary key columns. They are ordered by * COLUMN_NAME. * * <P> * Each column description has the following columns: * * <OL> * <li> * <B>TABLE_CAT</B> String => table catalog (may be null) * </li> * <li> * <B>TABLE_SCHEM</B> String => table schema (may be null) * </li> * <li> * <B>TABLE_NAME</B> String => table name * </li> * <li> * <B>COLUMN_NAME</B> String => column name * </li> * <li> * <B>KEY_SEQ</B> short => sequence number within primary key * </li> * <li> * <B>PK_NAME</B> String => primary key name (may be null) * </li> * </ol> * </p> * * @param catalog a catalog name; "" retrieves those without a catalog * @param schema a schema name pattern; "" retrieves those without a schema * @param table a table name * * @return ResultSet each row is a primary key column description * * @throws java.sql.SQLException DOCUMENT ME! */ public java.sql.ResultSet getPrimaryKeys(String catalog, String schema, String table) throws java.sql.SQLException { Field[] fields = new Field[6]; fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 255); fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 0); fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 255); fields[3] = new Field("", "COLUMN_NAME", Types.CHAR, 32); fields[4] = new Field("", "KEY_SEQ", Types.SMALLINT, 5); fields[5] = new Field("", "PK_NAME", Types.CHAR, 32); String dbSub = ""; if (catalog != null) { if (!catalog.equals("")) { dbSub = " FROM " + this.quotedId + catalog + this.quotedId; } } else { dbSub = " FROM " + this.quotedId + this.database + this.quotedId; } if (table == null) { throw new java.sql.SQLException("Table not specified.", SQLError.SQL_STATE_ILLEGAL_ARGUMENT); } Statement stmt = null; ResultSet rs = null; try { stmt = this.conn.createStatement(); if (stmt.getMaxRows() != 0) { stmt.setMaxRows(0); } StringBuffer queryBuf = new StringBuffer("SHOW KEYS FROM "); queryBuf.append(this.quotedId); queryBuf.append(table); queryBuf.append(this.quotedId); queryBuf.append(dbSub); rs = stmt.executeQuery(queryBuf.toString()); byte[] connectionCatalogAsBytes; if (catalog == null) { connectionCatalogAsBytes = s2b(this.conn.getCatalog()); } else { connectionCatalogAsBytes = s2b(catalog); } ArrayList tuples = new ArrayList(); TreeMap sortMap = new TreeMap(); while (rs.next()) { String keyType = rs.getString("Key_name"); if (keyType != null) { if (keyType.equalsIgnoreCase("PRIMARY") || keyType.equalsIgnoreCase("PRI")) { byte[][] tuple = new byte[6][]; tuple[0] = connectionCatalogAsBytes; tuple[1] = null; tuple[2] = s2b(table); String columnName = rs.getString("Column_name"); tuple[3] = s2b(columnName); tuple[4] = s2b(rs.getString("Seq_in_index")); tuple[5] = s2b(keyType); sortMap.put(columnName, tuple); } } } // Now pull out in column name sorted order Iterator sortedIterator = sortMap.values().iterator(); while (sortedIterator.hasNext()) { tuples.add(sortedIterator.next()); } return buildResultSet(fields, tuples); } finally { if (rs != null) { try { rs.close(); } catch (Exception ex) { ; } rs = null; } if (stmt != null) { try { stmt.close(); } catch (Exception ex) { ; } stmt = null; } } } /** * Get a description of a catalog's stored procedure parameters and result * columns. * * <P> * Only descriptions matching the schema, procedure and parameter name * criteria are returned. They are ordered by PROCEDURE_SCHEM and * PROCEDURE_NAME. Within this, the return value, if any, is first. Next * are the parameter descriptions in call order. The column descriptions * follow in column number order. * </p> * * <P> * Each row in the ResultSet is a parameter desription or column * description with the following fields: * * <OL> * <li> * <B>PROCEDURE_CAT</B> String => procedure catalog (may be null) * </li> * <li> * <B>PROCEDURE_SCHEM</B> String => procedure schema (may be null) * </li> * <li> * <B>PROCEDURE_NAME</B> String => procedure name * </li> * <li> * <B>COLUMN_NAME</B> String => column/parameter name * </li> * <li> * <B>COLUMN_TYPE</B> Short => kind of column/parameter: * * <UL> * <li> * procedureColumnUnknown - nobody knows * </li> * <li> * procedureColumnIn - IN parameter * </li> * <li> * procedureColumnInOut - INOUT parameter * </li> * <li> * procedureColumnOut - OUT parameter * </li> * <li> * procedureColumnReturn - procedure return value * </li> * <li> * procedureColumnResult - result column in ResultSet * </li> * </ul> * * </li> * <li> * <B>DATA_TYPE</B> short => SQL type from java.sql.Types * </li> * <li> * <B>TYPE_NAME</B> String => SQL type name * </li> * <li> * <B>PRECISION</B> int => precision * </li> * <li> * <B>LENGTH</B> int => length in bytes of data * </li> * <li> * <B>SCALE</B> short => scale * </li> * <li> * <B>RADIX</B> short => radix * </li> * <li> * <B>NULLABLE</B> short => can it contain NULL? * * <UL> * <li> * procedureNoNulls - does not allow NULL values * </li> * <li> * procedureNullable - allows NULL values * </li> * <li> * procedureNullableUnknown - nullability unknown * </li> * </ul> * * </li> * <li> * <B>REMARKS</B> String => comment describing parameter/column * </li> * </ol> * </p> * * <P> * <B>Note:</B> Some databases may not return the column descriptions for a * procedure. Additional columns beyond REMARKS can be defined by the * database. * </p> * * @param catalog a catalog name; "" retrieves those without a catalog * @param schemaPattern a schema name pattern; "" retrieves those without a * schema * @param procedureNamePattern a procedure name pattern * @param columnNamePattern a column name pattern * * @return ResultSet each row is a stored procedure parameter or column * description * * @throws java.sql.SQLException if a database access error occurs * * @see #getSearchStringEscape */ public java.sql.ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) throws java.sql.SQLException { Field[] fields = new Field[14]; fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 0); fields[1] = new Field("", "PROCEDURE_CAT", Types.CHAR, 0); fields[2] = new Field("", "PROCEDURE_SCHEM", Types.CHAR, 0); fields[3] = new Field("", "PROCEDURE_NAME", Types.CHAR, 0); fields[4] = new Field("", "COLUMN_NAME", Types.CHAR, 0); fields[5] = new Field("", "COLUMN_TYPE", Types.CHAR, 0); fields[6] = new Field("", "DATA_TYPE", Types.SMALLINT, 0); fields[7] = new Field("", "TYPE_NAME", Types.CHAR, 0); fields[8] = new Field("", "PRECISION", Types.INTEGER, 0); fields[9] = new Field("", "LENGTH", Types.INTEGER, 0); fields[10] = new Field("", "SCALE", Types.SMALLINT, 0); fields[11] = new Field("", "RADIX", Types.SMALLINT, 0); fields[12] = new Field("", "NULLABLE", Types.SMALLINT, 0); fields[13] = new Field("", "REMARKS", Types.CHAR, 0); return buildResultSet(fields, new ArrayList()); } /** * What's the database vendor's preferred term for "procedure"? * * @return the vendor term * * @throws java.sql.SQLException DOCUMENT ME! */ public String getProcedureTerm() throws java.sql.SQLException { return ""; } /** * Get a description of stored procedures available in a catalog. * * <P> * Only procedure descriptions matching the schema and procedure name * criteria are returned. They are ordered by PROCEDURE_SCHEM, and * PROCEDURE_NAME. * </p> * * <P> * Each procedure description has the the following columns: * * <OL> * <li> * <B>PROCEDURE_CAT</B> String => procedure catalog (may be null) * </li> * <li> * <B>PROCEDURE_SCHEM</B> String => procedure schema (may be null) * </li> * <li> * <B>PROCEDURE_NAME</B> String => procedure name * </li> * <li> * reserved for future use * </li> * <li> * reserved for future use * </li> * <li> * reserved for future use * </li> * <li> * <B>REMARKS</B> String => explanatory comment on the procedure * </li> * <li> * <B>PROCEDURE_TYPE</B> short => kind of procedure: * * <UL> * <li> * procedureResultUnknown - May return a result * </li> * <li> * procedureNoResult - Does not return a result * </li> * <li> * procedureReturnsResult - Returns a result * </li> * </ul> * * </li> * </ol> * </p> * * @param catalog a catalog name; "" retrieves those without a catalog * @param schemaPattern a schema name pattern; "" retrieves those without a * schema * @param procedureNamePattern a procedure name pattern * * @return ResultSet each row is a procedure description * * @throws java.sql.SQLException if a database access error occurs * * @see #getSearchStringEscape */ public java.sql.ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws java.sql.SQLException { Field[] fields = new Field[8]; fields[0] = new Field("", "PROCEDURE_CAT", Types.CHAR, 0); fields[1] = new Field("", "PROCEDURE_SCHEM", Types.CHAR, 0); fields[2] = new Field("", "PROCEDURE_NAME", Types.CHAR, 0); fields[3] = new Field("", "resTABLE_CAT", Types.CHAR, 0); fields[4] = new Field("", "resTABLE_CAT", Types.CHAR, 0); fields[5] = new Field("", "resTABLE_CAT", Types.CHAR, 0); fields[6] = new Field("", "REMARKS", Types.CHAR, 0); fields[7] = new Field("", "PROCEDURE_TYPE", Types.SMALLINT, 0); return buildResultSet(fields, new ArrayList()); } /** * Is the database in read-only mode? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean isReadOnly() throws java.sql.SQLException { return false; } /** * @see DatabaseMetaData#getResultSetHoldability() */ public int getResultSetHoldability() throws SQLException { return ResultSet.CLOSE_CURSORS_AT_COMMIT; } /** * Get a comma separated list of all a database's SQL keywords that are NOT * also SQL92 keywords. * * @return the list * * @throws java.sql.SQLException DOCUMENT ME! */ public String getSQLKeywords() throws java.sql.SQLException { return "AUTO_INCREMENT,BINARY,BLOB,ENUM,INFILE,LOAD,MEDIUMINT,OPTION,OUTFILE,REPLACE,SET,TEXT,UNSIGNED,ZEROFILL"; } /** * @see DatabaseMetaData#getSQLStateType() */ public int getSQLStateType() throws SQLException { return 0; } /** * What's the database vendor's preferred term for "schema"? * * @return the vendor term * * @throws java.sql.SQLException DOCUMENT ME! */ public String getSchemaTerm() throws java.sql.SQLException { return ""; } /** * Get the schema names available in this database. The results are * ordered by schema name. * * <P> * The schema column is: * * <OL> * <li> * <B>TABLE_SCHEM</B> String => schema name * </li> * </ol> * </p> * * @return ResultSet each row has a single String column that is a schema * name * * @throws java.sql.SQLException DOCUMENT ME! */ public java.sql.ResultSet getSchemas() throws java.sql.SQLException { Field[] fields = new Field[1]; fields[0] = new Field("", "TABLE_SCHEM", java.sql.Types.CHAR, 0); ArrayList tuples = new ArrayList(); java.sql.ResultSet results = buildResultSet(fields, tuples); return results; } /** * This is the string that can be used to escape '_' or '%' in the string * pattern style catalog search parameters. * * <P> * The '_' character represents any single character. * </p> * * <P> * The '%' character represents any sequence of zero or more characters. * </p> * * @return the string used to escape wildcard characters * * @throws java.sql.SQLException DOCUMENT ME! */ public String getSearchStringEscape() throws java.sql.SQLException { return "\\"; } /** * Get a comma separated list of string functions. * * @return the list * * @throws java.sql.SQLException DOCUMENT ME! */ public String getStringFunctions() throws java.sql.SQLException { return "ASCII,BIN,BIT_LENGTH,CHAR,CHARACTER_LENGTH,CHAR_LENGTH,CONCAT," + "CONCAT_WS,CONV,ELT,EXPORT_SET,FIELD,FIND_IN_SET,HEX,INSERT," + "INSTR,LCASE,LEFT,LENGTH,LOAD_FILE,LOCATE,LOCATE,LOWER,LPAD," + "LTRIM,MAKE_SET,MATCH,MID,OCT,OCTET_LENGTH,ORD,POSITION," + "QUOTE,REPEAT,REPLACE,REVERSE,RIGHT,RPAD,RTRIM,SOUNDEX," + "SPACE,STRCMP,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING," + "SUBSTRING_INDEX,TRIM,UCASE,UPPER"; } /** * @see DatabaseMetaData#getSuperTables(String, String, String) */ public java.sql.ResultSet getSuperTables(String arg0, String arg1, String arg2) throws SQLException { Field[] fields = new Field[4]; fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 32); fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 32); fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 32); fields[3] = new Field("", "SUPERTABLE_NAME", Types.CHAR, 32); return buildResultSet(fields, new ArrayList()); } /** * @see DatabaseMetaData#getSuperTypes(String, String, String) */ public java.sql.ResultSet getSuperTypes(String arg0, String arg1, String arg2) throws SQLException { Field[] fields = new Field[6]; fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 32); fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 32); fields[2] = new Field("", "TYPE_NAME", Types.CHAR, 32); fields[3] = new Field("", "SUPERTYPE_CAT", Types.CHAR, 32); fields[4] = new Field("", "SUPERTYPE_SCHEM", Types.CHAR, 32); fields[5] = new Field("", "SUPERTYPE_NAME", Types.CHAR, 32); return buildResultSet(fields, new ArrayList()); } /** * Get a comma separated list of system functions. * * @return the list * * @throws java.sql.SQLException DOCUMENT ME! */ public String getSystemFunctions() throws java.sql.SQLException { return "DATABASE,USER,SYSTEM_USER,SESSION_USER,PASSWORD,ENCRYPT,LAST_INSERT_ID,VERSION"; } /** * Get a description of the access rights for each table available in a * catalog. * * <P> * Only privileges matching the schema and table name criteria are * returned. They are ordered by TABLE_SCHEM, TABLE_NAME, and PRIVILEGE. * </p> * * <P> * Each privilige description has the following columns: * * <OL> * <li> * <B>TABLE_CAT</B> String => table catalog (may be null) * </li> * <li> * <B>TABLE_SCHEM</B> String => table schema (may be null) * </li> * <li> * <B>TABLE_NAME</B> String => table name * </li> * <li> * <B>COLUMN_NAME</B> String => column name * </li> * <li> * <B>GRANTOR</B> => grantor of access (may be null) * </li> * <li> * <B>GRANTEE</B> String => grantee of access * </li> * <li> * <B>PRIVILEGE</B> String => name of access (SELECT, INSERT, UPDATE, * REFRENCES, ...) * </li> * <li> * <B>IS_GRANTABLE</B> String => "YES" if grantee is permitted to grant to * others; "NO" if not; null if unknown * </li> * </ol> * </p> * * @param catalog a catalog name; "" retrieves those without a catalog * @param schemaPattern a schema name pattern; "" retrieves those without a * schema * @param tableNamePattern a table name pattern * * @return ResultSet each row is a table privilege description * * @throws java.sql.SQLException if a database access error occurs * * @see #getSearchStringEscape */ public java.sql.ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws java.sql.SQLException { Field[] fields = new Field[7]; fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 64); fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 1); fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 64); fields[3] = new Field("", "GRANTOR", Types.CHAR, 77); fields[4] = new Field("", "GRANTEE", Types.CHAR, 77); fields[5] = new Field("", "PRIVILEGE", Types.CHAR, 64); fields[6] = new Field("", "IS_GRANTABLE", Types.CHAR, 3); StringBuffer grantQuery = new StringBuffer( "SELECT host,db,table_name,grantor,user,table_priv from mysql.tables_priv "); grantQuery.append(" WHERE "); if ((catalog != null) && (catalog.length() != 0)) { grantQuery.append(" db='"); grantQuery.append(catalog); grantQuery.append("' AND "); } grantQuery.append("table_name like '"); grantQuery.append(tableNamePattern); grantQuery.append("'"); ResultSet results = null; ArrayList grantRows = new ArrayList(); Statement stmt = null; try { stmt = this.conn.createStatement(); if (stmt.getMaxRows() != 0) { stmt.setMaxRows(0); } results = stmt.executeQuery(grantQuery.toString()); while (results.next()) { String host = results.getString(1); String database = results.getString(2); String table = results.getString(3); String grantor = results.getString(4); String user = results.getString(5); if ((user == null) || (user.length() == 0)) { user = "%"; } StringBuffer fullUser = new StringBuffer(user); if ((host != null) && this.conn.useHostsInPrivileges()) { fullUser.append("@"); fullUser.append(host); } String allPrivileges = results.getString(6); if (allPrivileges != null) { allPrivileges = allPrivileges.toUpperCase(); StringTokenizer st = new StringTokenizer(allPrivileges, ","); while (st.hasMoreTokens()) { String privilege = st.nextToken().trim(); // Loop through every column in the table java.sql.ResultSet columnResults = null; try { columnResults = getColumns(catalog, schemaPattern, table, "%"); while (columnResults.next()) { byte[][] tuple = new byte[8][]; tuple[0] = s2b(database); tuple[1] = null; tuple[2] = s2b(table); if (grantor != null) { tuple[3] = s2b(grantor); } else { tuple[3] = null; } tuple[4] = s2b(fullUser.toString()); tuple[5] = s2b(privilege); tuple[6] = null; grantRows.add(tuple); } } finally { if (columnResults != null) { try { columnResults.close(); } catch (Exception ex) { ; } } } } } } } finally { if (results != null) { try { results.close(); } catch (Exception ex) { ; } results = null; } if (stmt != null) { try { stmt.close(); } catch (Exception ex) { ; } stmt = null; } } return buildResultSet(fields, grantRows); } /** * Get the table types available in this database. The results are ordered * by table type. * * <P> * The table type is: * * <OL> * <li> * <B>TABLE_TYPE</B> String => table type. Typical types are "TABLE", * "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", * "SYNONYM". * </li> * </ol> * </p> * * @return ResultSet each row has a single String column that is a table * type * * @throws java.sql.SQLException DOCUMENT ME! */ public java.sql.ResultSet getTableTypes() throws java.sql.SQLException { ArrayList tuples = new ArrayList(); Field[] fields = new Field[1]; fields[0] = new Field("", "TABLE_TYPE", Types.VARCHAR, 5); byte[][] tableTypeRow = new byte[1][]; tableTypeRow[0] = TABLE_AS_BYTES; tuples.add(tableTypeRow); byte[][] tempTypeRow = new byte[1][]; tempTypeRow[0] = s2b("LOCAL TEMPORARY"); tuples.add(tempTypeRow); return buildResultSet(fields, tuples); } /** * Get a description of tables available in a catalog. * * <P> * Only table descriptions matching the catalog, schema, table name and * type criteria are returned. They are ordered by TABLE_TYPE, * TABLE_SCHEM and TABLE_NAME. * </p> * * <P> * Each table description has the following columns: * * <OL> * <li> * <B>TABLE_CAT</B> String => table catalog (may be null) * </li> * <li> * <B>TABLE_SCHEM</B> String => table schema (may be null) * </li> * <li> * <B>TABLE_NAME</B> String => table name * </li> * <li> * <B>TABLE_TYPE</B> String => table type. Typical types are "TABLE", * "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", * "SYNONYM". * </li> * <li> * <B>REMARKS</B> String => explanatory comment on the table * </li> * </ol> * </p> * * <P> * <B>Note:</B> Some databases may not return information for all tables. * </p> * * @param catalog a catalog name; "" retrieves those without a catalog * @param schemaPattern a schema name pattern; "" retrieves those without a * schema * @param tableNamePattern a table name pattern * @param types a list of table types to include; null returns all types * * @return ResultSet each row is a table description * * @throws java.sql.SQLException DOCUMENT ME! * * @see #getSearchStringEscape */ public java.sql.ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) throws java.sql.SQLException { String databasePart = ""; if (catalog != null) { if (!catalog.equals("")) { databasePart = " FROM " + this.quotedId + catalog + this.quotedId; } } else { databasePart = " FROM " + this.quotedId + this.database + this.quotedId; } if (tableNamePattern == null) { tableNamePattern = "%"; } Statement stmt = null; ResultSet results = null; try { stmt = this.conn.createStatement(); if (stmt.getMaxRows() != 0) { stmt.setMaxRows(0); } results = stmt.executeQuery("SHOW TABLES " + databasePart + " LIKE '" + tableNamePattern + "'"); Field[] fields = new Field[5]; fields[0] = new Field("", "TABLE_CAT", java.sql.Types.VARCHAR, (catalog == null) ? 0 : catalog.length()); fields[1] = new Field("", "TABLE_SCHEM", java.sql.Types.VARCHAR, 0); fields[2] = new Field("", "TABLE_NAME", java.sql.Types.VARCHAR, 255); fields[3] = new Field("", "TABLE_TYPE", java.sql.Types.VARCHAR, 5); fields[4] = new Field("", "REMARKS", java.sql.Types.VARCHAR, 0); ArrayList tuples = new ArrayList(); byte[][] row = null; byte[] connectionCatalogAsBytes = null; if (catalog == null) { connectionCatalogAsBytes = s2b(this.conn.getCatalog()); } else { connectionCatalogAsBytes = s2b(catalog); } while (results.next()) { String name = results.getString(1); row = new byte[5][]; row[0] = connectionCatalogAsBytes; row[1] = null; row[2] = name.getBytes(); row[3] = TABLE_AS_BYTES; row[4] = new byte[0]; tuples.add(row); } java.sql.ResultSet tables = buildResultSet(fields, tuples); return tables; } finally { if (results != null) { try { results.close(); } catch (Exception ex) { ; } results = null; } if (stmt != null) { try { stmt.close(); } catch (Exception ex) { ; } stmt = null; } } } /** * Get a comma separated list of time and date functions. * * @return the list * * @throws java.sql.SQLException DOCUMENT ME! */ public String getTimeDateFunctions() throws java.sql.SQLException { return "DAYOFWEEK,WEEKDAY,DAYOFMONTH,DAYOFYEAR,MONTH,DAYNAME," + "MONTHNAME,QUARTER,WEEK,YEAR,HOUR,MINUTE,SECOND,PERIOD_ADD," + "PERIOD_DIFF,TO_DAYS,FROM_DAYS,DATE_FORMAT,TIME_FORMAT," + "CURDATE,CURRENT_DATE,CURTIME,CURRENT_TIME,NOW,SYSDATE," + "CURRENT_TIMESTAMP,UNIX_TIMESTAMP,FROM_UNIXTIME," + "SEC_TO_TIME,TIME_TO_SEC"; } /** * Get a description of all the standard SQL types supported by this * database. They are ordered by DATA_TYPE and then by how closely the * data type maps to the corresponding JDBC SQL type. * * <P> * Each type description has the following columns: * * <OL> * <li> * <B>TYPE_NAME</B> String => Type name * </li> * <li> * <B>DATA_TYPE</B> short => SQL data type from java.sql.Types * </li> * <li> * <B>PRECISION</B> int => maximum precision * </li> * <li> * <B>LITERAL_PREFIX</B> String => prefix used to quote a literal (may be * null) * </li> * <li> * <B>LITERAL_SUFFIX</B> String => suffix used to quote a literal (may be * null) * </li> * <li> * <B>CREATE_PARAMS</B> String => parameters used in creating the type (may * be null) * </li> * <li> * <B>NULLABLE</B> short => can you use NULL for this type? * * <UL> * <li> * typeNoNulls - does not allow NULL values * </li> * <li> * typeNullable - allows NULL values * </li> * <li> * typeNullableUnknown - nullability unknown * </li> * </ul> * * </li> * <li> * <B>CASE_SENSITIVE</B> boolean=> is it case sensitive? * </li> * <li> * <B>SEARCHABLE</B> short => can you use "WHERE" based on this type: * * <UL> * <li> * typePredNone - No support * </li> * <li> * typePredChar - Only supported with WHERE .. LIKE * </li> * <li> * typePredBasic - Supported except for WHERE .. LIKE * </li> * <li> * typeSearchable - Supported for all WHERE .. * </li> * </ul> * * </li> * <li> * <B>UNSIGNED_ATTRIBUTE</B> boolean => is it unsigned? * </li> * <li> * <B>FIXED_PREC_SCALE</B> boolean => can it be a money value? * </li> * <li> * <B>AUTO_INCREMENT</B> boolean => can it be used for an auto-increment * value? * </li> * <li> * <B>LOCAL_TYPE_NAME</B> String => localized version of type name (may be * null) * </li> * <li> * <B>MINIMUM_SCALE</B> short => minimum scale supported * </li> * <li> * <B>MAXIMUM_SCALE</B> short => maximum scale supported * </li> * <li> * <B>SQL_DATA_TYPE</B> int => unused * </li> * <li> * <B>SQL_DATETIME_SUB</B> int => unused * </li> * <li> * <B>NUM_PREC_RADIX</B> int => usually 2 or 10 * </li> * </ol> * </p> * * @return ResultSet each row is a SQL type description * * @throws java.sql.SQLException DOCUMENT ME! */ /** * Get a description of all the standard SQL types supported by this * database. They are ordered by DATA_TYPE and then by how closely the * data type maps to the corresponding JDBC SQL type. * * <P> * Each type description has the following columns: * * <OL> * <li> * <B>TYPE_NAME</B> String => Type name * </li> * <li> * <B>DATA_TYPE</B> short => SQL data type from java.sql.Types * </li> * <li> * <B>PRECISION</B> int => maximum precision * </li> * <li> * <B>LITERAL_PREFIX</B> String => prefix used to quote a literal (may be * null) * </li> * <li> * <B>LITERAL_SUFFIX</B> String => suffix used to quote a literal (may be * null) * </li> * <li> * <B>CREATE_PARAMS</B> String => parameters used in creating the type (may * be null) * </li> * <li> * <B>NULLABLE</B> short => can you use NULL for this type? * * <UL> * <li> * typeNoNulls - does not allow NULL values * </li> * <li> * typeNullable - allows NULL values * </li> * <li> * typeNullableUnknown - nullability unknown * </li> * </ul> * * </li> * <li> * <B>CASE_SENSITIVE</B> boolean=> is it case sensitive? * </li> * <li> * <B>SEARCHABLE</B> short => can you use "WHERE" based on this type: * * <UL> * <li> * typePredNone - No support * </li> * <li> * typePredChar - Only supported with WHERE .. LIKE * </li> * <li> * typePredBasic - Supported except for WHERE .. LIKE * </li> * <li> * typeSearchable - Supported for all WHERE .. * </li> * </ul> * * </li> * <li> * <B>UNSIGNED_ATTRIBUTE</B> boolean => is it unsigned? * </li> * <li> * <B>FIXED_PREC_SCALE</B> boolean => can it be a money value? * </li> * <li> * <B>AUTO_INCREMENT</B> boolean => can it be used for an auto-increment * value? * </li> * <li> * <B>LOCAL_TYPE_NAME</B> String => localized version of type name (may be * null) * </li> * <li> * <B>MINIMUM_SCALE</B> short => minimum scale supported * </li> * <li> * <B>MAXIMUM_SCALE</B> short => maximum scale supported * </li> * <li> * <B>SQL_DATA_TYPE</B> int => unused * </li> * <li> * <B>SQL_DATETIME_SUB</B> int => unused * </li> * <li> * <B>NUM_PREC_RADIX</B> int => usually 2 or 10 * </li> * </ol> * </p> * * @return ResultSet each row is a SQL type description * * @throws java.sql.SQLException DOCUMENT ME! */ public java.sql.ResultSet getTypeInfo() throws java.sql.SQLException { Field[] fields = new Field[18]; fields[0] = new Field("", "TYPE_NAME", Types.CHAR, 32); fields[1] = new Field("", "DATA_TYPE", Types.SMALLINT, 5); fields[2] = new Field("", "PRECISION", Types.INTEGER, 10); fields[3] = new Field("", "LITERAL_PREFIX", Types.CHAR, 4); fields[4] = new Field("", "LITERAL_SUFFIX", Types.CHAR, 4); fields[5] = new Field("", "CREATE_PARAMS", Types.CHAR, 32); fields[6] = new Field("", "NULLABLE", Types.SMALLINT, 5); fields[7] = new Field("", "CASE_SENSITIVE", Types.CHAR, 3); fields[8] = new Field("", "SEARCHABLE", Types.SMALLINT, 3); fields[9] = new Field("", "UNSIGNED_ATTRIBUTE", Types.CHAR, 3); fields[10] = new Field("", "FIXED_PREC_SCALE", Types.CHAR, 3); fields[11] = new Field("", "AUTO_INCREMENT", Types.CHAR, 3); fields[12] = new Field("", "LOCAL_TYPE_NAME", Types.CHAR, 32); fields[13] = new Field("", "MINIMUM_SCALE", Types.SMALLINT, 5); fields[14] = new Field("", "MAXIMUM_SCALE", Types.SMALLINT, 5); fields[15] = new Field("", "SQL_DATA_TYPE", Types.INTEGER, 10); fields[16] = new Field("", "SQL_DATETIME_SUB", Types.INTEGER, 10); fields[17] = new Field("", "NUM_PREC_RADIX", Types.INTEGER, 10); byte[][] rowVal = null; ArrayList tuples = new ArrayList(); /* * The following are ordered by java.sql.Types, and * then by how closely the MySQL type matches the * JDBC Type (per spec) */ /* * MySQL Type: BIT (silently converted to TINYINT(1)) * JDBC Type: BIT */ rowVal = new byte[18][]; rowVal[0] = s2b("BIT"); rowVal[1] = Integer.toString(java.sql.Types.BIT).getBytes(); // JDBC Data type rowVal[2] = s2b("1"); // Precision rowVal[3] = s2b(""); // Literal Prefix rowVal[4] = s2b(""); // Literal Suffix rowVal[5] = s2b(""); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("true"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("BIT"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: BOOL (silently converted to TINYINT(1)) * JDBC Type: BIT */ rowVal = new byte[18][]; rowVal[0] = s2b("BOOL"); rowVal[1] = Integer.toString(java.sql.Types.BIT).getBytes(); // JDBC Data type rowVal[2] = s2b("1"); // Precision rowVal[3] = s2b(""); // Literal Prefix rowVal[4] = s2b(""); // Literal Suffix rowVal[5] = s2b(""); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("true"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("BOOL"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: TINYINT * JDBC Type: TINYINT */ rowVal = new byte[18][]; rowVal[0] = s2b("TINYINT"); rowVal[1] = Integer.toString(java.sql.Types.TINYINT).getBytes(); // JDBC Data type rowVal[2] = s2b("3"); // Precision rowVal[3] = s2b(""); // Literal Prefix rowVal[4] = s2b(""); // Literal Suffix rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("true"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("true"); // Auto Increment rowVal[12] = s2b("TINYINT"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: BIGINT * JDBC Type: BIGINT */ rowVal = new byte[18][]; rowVal[0] = s2b("BIGINT"); rowVal[1] = Integer.toString(java.sql.Types.BIGINT).getBytes(); // JDBC Data type rowVal[2] = s2b("19"); // Precision rowVal[3] = s2b(""); // Literal Prefix rowVal[4] = s2b(""); // Literal Suffix rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("true"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("true"); // Auto Increment rowVal[12] = s2b("BIGINT"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: LONG VARBINARY * JDBC Type: LONGVARBINARY */ rowVal = new byte[18][]; rowVal[0] = s2b("LONG VARBINARY"); rowVal[1] = Integer.toString(java.sql.Types.LONGVARBINARY).getBytes(); // JDBC Data type rowVal[2] = s2b("16777215"); // Precision rowVal[3] = s2b("'"); // Literal Prefix rowVal[4] = s2b("'"); // Literal Suffix rowVal[5] = s2b(""); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("true"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("LONG VARBINARY"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: MEDIUMBLOB * JDBC Type: LONGVARBINARY */ rowVal = new byte[18][]; rowVal[0] = s2b("MEDIUMBLOB"); rowVal[1] = Integer.toString(java.sql.Types.LONGVARBINARY).getBytes(); // JDBC Data type rowVal[2] = s2b("16777215"); // Precision rowVal[3] = s2b("'"); // Literal Prefix rowVal[4] = s2b("'"); // Literal Suffix rowVal[5] = s2b(""); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("true"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("MEDIUMBLOB"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: LONGBLOB * JDBC Type: LONGVARBINARY */ rowVal = new byte[18][]; rowVal[0] = s2b("LONGBLOB"); rowVal[1] = Integer.toString(java.sql.Types.LONGVARBINARY).getBytes(); // JDBC Data type rowVal[2] = Integer.toString(Integer.MAX_VALUE).getBytes(); // Precision rowVal[3] = s2b("'"); // Literal Prefix rowVal[4] = s2b("'"); // Literal Suffix rowVal[5] = s2b(""); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("true"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("LONGBLOB"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: BLOB * JDBC Type: LONGVARBINARY */ rowVal = new byte[18][]; rowVal[0] = s2b("BLOB"); rowVal[1] = Integer.toString(java.sql.Types.LONGVARBINARY).getBytes(); // JDBC Data type rowVal[2] = s2b("65535"); // Precision rowVal[3] = s2b("'"); // Literal Prefix rowVal[4] = s2b("'"); // Literal Suffix rowVal[5] = s2b(""); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("true"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("BLOB"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: TINYBLOB * JDBC Type: LONGVARBINARY */ rowVal = new byte[18][]; rowVal[0] = s2b("TINYBLOB"); rowVal[1] = Integer.toString(java.sql.Types.LONGVARBINARY).getBytes(); // JDBC Data type rowVal[2] = s2b("255"); // Precision rowVal[3] = s2b("'"); // Literal Prefix rowVal[4] = s2b("'"); // Literal Suffix rowVal[5] = s2b(""); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("true"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("TINYBLOB"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: VARBINARY (sliently converted to VARCHAR(M) BINARY) * JDBC Type: VARBINARY */ rowVal = new byte[18][]; rowVal[0] = s2b("VARBINARY"); rowVal[1] = Integer.toString(java.sql.Types.VARBINARY).getBytes(); // JDBC Data type rowVal[2] = s2b("255"); // Precision rowVal[3] = s2b("'"); // Literal Prefix rowVal[4] = s2b("'"); // Literal Suffix rowVal[5] = s2b("(M)"); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("true"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("VARBINARY"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: BINARY (silently converted to CHAR(M) BINARY) * JDBC Type: BINARY */ rowVal = new byte[18][]; rowVal[0] = s2b("BINARY"); rowVal[1] = Integer.toString(java.sql.Types.BINARY).getBytes(); // JDBC Data type rowVal[2] = s2b("255"); // Precision rowVal[3] = s2b("'"); // Literal Prefix rowVal[4] = s2b("'"); // Literal Suffix rowVal[5] = s2b("(M)"); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("true"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("BINARY"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: LONG VARCHAR * JDBC Type: LONGVARCHAR */ rowVal = new byte[18][]; rowVal[0] = s2b("LONG VARCHAR"); rowVal[1] = Integer.toString(java.sql.Types.LONGVARCHAR).getBytes(); // JDBC Data type rowVal[2] = s2b("16777215"); // Precision rowVal[3] = s2b("'"); // Literal Prefix rowVal[4] = s2b("'"); // Literal Suffix rowVal[5] = s2b(""); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("LONG VARCHAR"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: MEDIUMTEXT * JDBC Type: LONGVARCHAR */ rowVal = new byte[18][]; rowVal[0] = s2b("MEDIUMTEXT"); rowVal[1] = Integer.toString(java.sql.Types.LONGVARCHAR).getBytes(); // JDBC Data type rowVal[2] = s2b("16777215"); // Precision rowVal[3] = s2b("'"); // Literal Prefix rowVal[4] = s2b("'"); // Literal Suffix rowVal[5] = s2b(""); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("MEDIUMTEXT"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: LONGTEXT * JDBC Type: LONGVARCHAR */ rowVal = new byte[18][]; rowVal[0] = s2b("LONGTEXT"); rowVal[1] = Integer.toString(java.sql.Types.LONGVARCHAR).getBytes(); // JDBC Data type rowVal[2] = Integer.toString(Integer.MAX_VALUE).getBytes(); // Precision rowVal[3] = s2b("'"); // Literal Prefix rowVal[4] = s2b("'"); // Literal Suffix rowVal[5] = s2b(""); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("LONGTEXT"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: TEXT * JDBC Type: LONGVARCHAR */ rowVal = new byte[18][]; rowVal[0] = s2b("TEXT"); rowVal[1] = Integer.toString(java.sql.Types.LONGVARCHAR).getBytes(); // JDBC Data type rowVal[2] = s2b("65535"); // Precision rowVal[3] = s2b("'"); // Literal Prefix rowVal[4] = s2b("'"); // Literal Suffix rowVal[5] = s2b(""); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("TEXT"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: TINYTEXT * JDBC Type: LONGVARCHAR */ rowVal = new byte[18][]; rowVal[0] = s2b("TINYTEXT"); rowVal[1] = Integer.toString(java.sql.Types.LONGVARCHAR).getBytes(); // JDBC Data type rowVal[2] = s2b("255"); // Precision rowVal[3] = s2b("'"); // Literal Prefix rowVal[4] = s2b("'"); // Literal Suffix rowVal[5] = s2b(""); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("TINYTEXT"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: CHAR * JDBC Type: CHAR */ rowVal = new byte[18][]; rowVal[0] = s2b("CHAR"); rowVal[1] = Integer.toString(java.sql.Types.CHAR).getBytes(); // JDBC Data type rowVal[2] = s2b("255"); // Precision rowVal[3] = s2b("'"); // Literal Prefix rowVal[4] = s2b("'"); // Literal Suffix rowVal[5] = s2b("(M)"); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("CHAR"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: NUMERIC (silently converted to DECIMAL) * JDBC Type: NUMERIC */ rowVal = new byte[18][]; rowVal[0] = s2b("NUMERIC"); rowVal[1] = Integer.toString(java.sql.Types.NUMERIC).getBytes(); // JDBC Data type rowVal[2] = s2b("17"); // Precision rowVal[3] = s2b(""); // Literal Prefix rowVal[4] = s2b(""); // Literal Suffix rowVal[5] = s2b("[(M[,D])] [ZEROFILL]"); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("true"); // Auto Increment rowVal[12] = s2b("NUMERIC"); // Locale Type Name rowVal[13] = s2b("308"); // Minimum Scale rowVal[14] = s2b("308"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: DECIMAL * JDBC Type: DECIMAL */ rowVal = new byte[18][]; rowVal[0] = s2b("DECIMAL"); rowVal[1] = Integer.toString(java.sql.Types.DECIMAL).getBytes(); // JDBC Data type rowVal[2] = s2b("17"); // Precision rowVal[3] = s2b(""); // Literal Prefix rowVal[4] = s2b(""); // Literal Suffix rowVal[5] = s2b("[(M[,D])] [ZEROFILL]"); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("true"); // Auto Increment rowVal[12] = s2b("DECIMAL"); // Locale Type Name rowVal[13] = s2b("-308"); // Minimum Scale rowVal[14] = s2b("308"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: INTEGER * JDBC Type: INTEGER */ rowVal = new byte[18][]; rowVal[0] = s2b("INTEGER"); rowVal[1] = Integer.toString(java.sql.Types.INTEGER).getBytes(); // JDBC Data type rowVal[2] = s2b("10"); // Precision rowVal[3] = s2b(""); // Literal Prefix rowVal[4] = s2b(""); // Literal Suffix rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("true"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("true"); // Auto Increment rowVal[12] = s2b("INTEGER"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: INT * JDBC Type: INTEGER */ rowVal = new byte[18][]; rowVal[0] = s2b("INT"); rowVal[1] = Integer.toString(java.sql.Types.INTEGER).getBytes(); // JDBC Data type rowVal[2] = s2b("10"); // Precision rowVal[3] = s2b(""); // Literal Prefix rowVal[4] = s2b(""); // Literal Suffix rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("true"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("true"); // Auto Increment rowVal[12] = s2b("INT"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: MEDIUMINT * JDBC Type: INTEGER */ rowVal = new byte[18][]; rowVal[0] = s2b("MEDIUMINT"); rowVal[1] = Integer.toString(java.sql.Types.INTEGER).getBytes(); // JDBC Data type rowVal[2] = s2b("7"); // Precision rowVal[3] = s2b(""); // Literal Prefix rowVal[4] = s2b(""); // Literal Suffix rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("true"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("true"); // Auto Increment rowVal[12] = s2b("MEDIUMINT"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: SMALLINT * JDBC Type: SMALLINT */ rowVal = new byte[18][]; rowVal[0] = s2b("SMALLINT"); rowVal[1] = Integer.toString(java.sql.Types.SMALLINT).getBytes(); // JDBC Data type rowVal[2] = s2b("5"); // Precision rowVal[3] = s2b(""); // Literal Prefix rowVal[4] = s2b(""); // Literal Suffix rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("true"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("true"); // Auto Increment rowVal[12] = s2b("SMALLINT"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: DOUBLE * JDBC Type: FLOAT (is really an alias for DOUBLE from JDBC's perspective) */ rowVal = new byte[18][]; rowVal[0] = s2b("DOUBLE"); rowVal[1] = Integer.toString(java.sql.Types.FLOAT).getBytes(); // JDBC Data type rowVal[2] = s2b("17"); // Precision rowVal[3] = s2b(""); // Literal Prefix rowVal[4] = s2b(""); // Literal Suffix rowVal[5] = s2b("[(M,D)] [ZEROFILL]"); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("true"); // Auto Increment rowVal[12] = s2b("DOUBLE"); // Locale Type Name rowVal[13] = s2b("-308"); // Minimum Scale rowVal[14] = s2b("308"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: FLOAT * JDBC Type: REAL (this is the SINGLE PERCISION floating point type) */ rowVal = new byte[18][]; rowVal[0] = s2b("FLOAT"); rowVal[1] = Integer.toString(java.sql.Types.REAL).getBytes(); // JDBC Data type rowVal[2] = s2b("10"); // Precision rowVal[3] = s2b(""); // Literal Prefix rowVal[4] = s2b(""); // Literal Suffix rowVal[5] = s2b("[(M,D)] [ZEROFILL]"); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("true"); // Auto Increment rowVal[12] = s2b("FLOAT"); // Locale Type Name rowVal[13] = s2b("-38"); // Minimum Scale rowVal[14] = s2b("38"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: DOUBLE * JDBC Type: DOUBLE */ rowVal = new byte[18][]; rowVal[0] = s2b("DOUBLE"); rowVal[1] = Integer.toString(java.sql.Types.DOUBLE).getBytes(); // JDBC Data type rowVal[2] = s2b("17"); // Precision rowVal[3] = s2b(""); // Literal Prefix rowVal[4] = s2b(""); // Literal Suffix rowVal[5] = s2b("[(M,D)] [ZEROFILL]"); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("true"); // Auto Increment rowVal[12] = s2b("DOUBLE"); // Locale Type Name rowVal[13] = s2b("-308"); // Minimum Scale rowVal[14] = s2b("308"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: DOUBLE PRECISION * JDBC Type: DOUBLE */ rowVal = new byte[18][]; rowVal[0] = s2b("DOUBLE PRECISION"); rowVal[1] = Integer.toString(java.sql.Types.DOUBLE).getBytes(); // JDBC Data type rowVal[2] = s2b("17"); // Precision rowVal[3] = s2b(""); // Literal Prefix rowVal[4] = s2b(""); // Literal Suffix rowVal[5] = s2b("[(M,D)] [ZEROFILL]"); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("true"); // Auto Increment rowVal[12] = s2b("DOUBLE PRECISION"); // Locale Type Name rowVal[13] = s2b("-308"); // Minimum Scale rowVal[14] = s2b("308"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: REAL (does not map to Types.REAL) * JDBC Type: DOUBLE */ rowVal = new byte[18][]; rowVal[0] = s2b("REAL"); rowVal[1] = Integer.toString(java.sql.Types.DOUBLE).getBytes(); // JDBC Data type rowVal[2] = s2b("17"); // Precision rowVal[3] = s2b(""); // Literal Prefix rowVal[4] = s2b(""); // Literal Suffix rowVal[5] = s2b("[(M,D)] [ZEROFILL]"); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("true"); // Auto Increment rowVal[12] = s2b("REAL"); // Locale Type Name rowVal[13] = s2b("-308"); // Minimum Scale rowVal[14] = s2b("308"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: VARCHAR * JDBC Type: VARCHAR */ rowVal = new byte[18][]; rowVal[0] = s2b("VARCHAR"); rowVal[1] = Integer.toString(java.sql.Types.VARCHAR).getBytes(); // JDBC Data type rowVal[2] = s2b("255"); // Precision rowVal[3] = s2b("'"); // Literal Prefix rowVal[4] = s2b("'"); // Literal Suffix rowVal[5] = s2b("(M)"); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("VARCHAR"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: ENUM * JDBC Type: VARCHAR */ rowVal = new byte[18][]; rowVal[0] = s2b("ENUM"); rowVal[1] = Integer.toString(java.sql.Types.VARCHAR).getBytes(); // JDBC Data type rowVal[2] = s2b("65535"); // Precision rowVal[3] = s2b("'"); // Literal Prefix rowVal[4] = s2b("'"); // Literal Suffix rowVal[5] = s2b(""); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("ENUM"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: SET * JDBC Type: VARCHAR */ rowVal = new byte[18][]; rowVal[0] = s2b("SET"); rowVal[1] = Integer.toString(java.sql.Types.VARCHAR).getBytes(); // JDBC Data type rowVal[2] = s2b("64"); // Precision rowVal[3] = s2b("'"); // Literal Prefix rowVal[4] = s2b("'"); // Literal Suffix rowVal[5] = s2b(""); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("SET"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: DATE * JDBC Type: DATE */ rowVal = new byte[18][]; rowVal[0] = s2b("DATE"); rowVal[1] = Integer.toString(java.sql.Types.DATE).getBytes(); // JDBC Data type rowVal[2] = s2b("0"); // Precision rowVal[3] = s2b("'"); // Literal Prefix rowVal[4] = s2b("'"); // Literal Suffix rowVal[5] = s2b(""); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("DATE"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: TIME * JDBC Type: TIME */ rowVal = new byte[18][]; rowVal[0] = s2b("TIME"); rowVal[1] = Integer.toString(java.sql.Types.TIME).getBytes(); // JDBC Data type rowVal[2] = s2b("0"); // Precision rowVal[3] = s2b("'"); // Literal Prefix rowVal[4] = s2b("'"); // Literal Suffix rowVal[5] = s2b(""); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("TIME"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: DATETIME * JDBC Type: TIMESTAMP */ rowVal = new byte[18][]; rowVal[0] = s2b("DATETIME"); rowVal[1] = Integer.toString(java.sql.Types.TIMESTAMP).getBytes(); // JDBC Data type rowVal[2] = s2b("0"); // Precision rowVal[3] = s2b("'"); // Literal Prefix rowVal[4] = s2b("'"); // Literal Suffix rowVal[5] = s2b(""); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("DATETIME"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); /* * MySQL Type: TIMESTAMP * JDBC Type: TIMESTAMP */ rowVal = new byte[18][]; rowVal[0] = s2b("TIMESTAMP"); rowVal[1] = Integer.toString(java.sql.Types.TIMESTAMP).getBytes(); // JDBC Data type rowVal[2] = s2b("0"); // Precision rowVal[3] = s2b("'"); // Literal Prefix rowVal[4] = s2b("'"); // Literal Suffix rowVal[5] = s2b("[(M)]"); // Create Params rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable) .getBytes(); // Nullable rowVal[7] = s2b("false"); // Case Sensitive rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable) .getBytes(); // Searchable rowVal[9] = s2b("false"); // Unsignable rowVal[10] = s2b("false"); // Fixed Prec Scale rowVal[11] = s2b("false"); // Auto Increment rowVal[12] = s2b("TIMESTAMP"); // Locale Type Name rowVal[13] = s2b("0"); // Minimum Scale rowVal[14] = s2b("0"); // Maximum Scale rowVal[15] = s2b("0"); // SQL Data Type (not used) rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used) rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10) tuples.add(rowVal); return buildResultSet(fields, tuples); } /** * JDBC 2.0 Get a description of the user-defined types defined in a * particular schema. Schema specific UDTs may have type JAVA_OBJECT, * STRUCT, or DISTINCT. * * <P> * Only types matching the catalog, schema, type name and type criteria * are returned. They are ordered by DATA_TYPE, TYPE_SCHEM and * TYPE_NAME. The type name parameter may be a fully qualified name. In * this case, the catalog and schemaPattern parameters are ignored. * </p> * * <P> * Each type description has the following columns: * * <OL> * <li> * <B>TYPE_CAT</B> String => the type's catalog (may be null) * </li> * <li> * <B>TYPE_SCHEM</B> String => type's schema (may be null) * </li> * <li> * <B>TYPE_NAME</B> String => type name * </li> * <li> * <B>CLASS_NAME</B> String => Java class name * </li> * <li> * <B>DATA_TYPE</B> String => type value defined in java.sql.Types. One * of JAVA_OBJECT, STRUCT, or DISTINCT * </li> * <li> * <B>REMARKS</B> String => explanatory comment on the type * </li> * </ol> * </p> * * <P> * <B>Note:</B> If the driver does not support UDTs then an empty result * set is returned. * </p> * * @param catalog a catalog name; "" retrieves those without a catalog; * null means drop catalog name from the selection criteria * @param schemaPattern a schema name pattern; "" retrieves those without a * schema * @param typeNamePattern a type name pattern; may be a fully qualified * name * @param types a list of user-named types to include (JAVA_OBJECT, STRUCT, * or DISTINCT); null returns all types * * @return ResultSet - each row is a type description * * @exception SQLException if a database-access error occurs. */ public java.sql.ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types) throws SQLException { Field[] fields = new Field[6]; fields[0] = new Field("", "TYPE_CAT", Types.VARCHAR, 32); fields[1] = new Field("", "TYPE_SCHEM", Types.VARCHAR, 32); fields[2] = new Field("", "TYPE_NAME", Types.VARCHAR, 32); fields[3] = new Field("", "CLASS_NAME", Types.VARCHAR, 32); fields[4] = new Field("", "DATA_TYPE", Types.VARCHAR, 32); fields[5] = new Field("", "REMARKS", Types.VARCHAR, 32); ArrayList tuples = new ArrayList(); return buildResultSet(fields, tuples); } /** * What's the url for this database? * * @return the url or null if it can't be generated * * @throws java.sql.SQLException DOCUMENT ME! */ public String getURL() throws java.sql.SQLException { return this.conn.getURL(); } /** * What's our user name as known to the database? * * @return our database user name * * @throws java.sql.SQLException DOCUMENT ME! */ public String getUserName() throws java.sql.SQLException { if (this.conn.useHostsInPrivileges()) { Statement stmt = null; ResultSet rs = null; try { stmt = this.conn.createStatement(); if (stmt.getMaxRows() != 0) { stmt.setMaxRows(0); } rs = stmt.executeQuery("SELECT USER()"); rs.next(); return rs.getString(1); } finally { if (rs != null) { try { rs.close(); } catch (Exception ex) { AssertionFailedException.shouldNotHappen(ex); } rs = null; } if (stmt != null) { try { stmt.close(); } catch (Exception ex) { AssertionFailedException.shouldNotHappen(ex); } stmt = null; } } } else { return this.conn.getUser(); } } /** * Get a description of a table's columns that are automatically updated * when any value in a row is updated. They are unordered. * * <P> * Each column description has the following columns: * * <OL> * <li> * <B>SCOPE</B> short => is not used * </li> * <li> * <B>COLUMN_NAME</B> String => column name * </li> * <li> * <B>DATA_TYPE</B> short => SQL data type from java.sql.Types * </li> * <li> * <B>TYPE_NAME</B> String => Data source dependent type name * </li> * <li> * <B>COLUMN_SIZE</B> int => precision * </li> * <li> * <B>BUFFER_LENGTH</B> int => length of column value in bytes * </li> * <li> * <B>DECIMAL_DIGITS</B> short => scale * </li> * <li> * <B>PSEUDO_COLUMN</B> short => is this a pseudo column like an Oracle * ROWID * * <UL> * <li> * versionColumnUnknown - may or may not be pseudo column * </li> * <li> * versionColumnNotPseudo - is NOT a pseudo column * </li> * <li> * versionColumnPseudo - is a pseudo column * </li> * </ul> * * </li> * </ol> * </p> * * @param catalog a catalog name; "" retrieves those without a catalog * @param schema a schema name; "" retrieves those without a schema * @param table a table name * * @return ResultSet each row is a column description * * @throws java.sql.SQLException DOCUMENT ME! */ public java.sql.ResultSet getVersionColumns(String catalog, String schema, String table) throws java.sql.SQLException { Field[] fields = new Field[8]; fields[0] = new Field("", "SCOPE", Types.SMALLINT, 5); fields[1] = new Field("", "COLUMN_NAME", Types.CHAR, 32); fields[2] = new Field("", "DATA_TYPE", Types.SMALLINT, 5); fields[3] = new Field("", "TYPE_NAME", Types.CHAR, 16); fields[4] = new Field("", "COLUMN_SIZE", Types.CHAR, 16); fields[5] = new Field("", "BUFFER_LENGTH", Types.CHAR, 16); fields[6] = new Field("", "DECIMAL_DIGITS", Types.CHAR, 16); fields[7] = new Field("", "PSEUDO_COLUMN", Types.SMALLINT, 5); return buildResultSet(fields, new ArrayList()); // do TIMESTAMP columns count? } /** * Can all the procedures returned by getProcedures be called by the * current user? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean allProceduresAreCallable() throws java.sql.SQLException { return false; } /** * Can all the tables returned by getTable be SELECTed by the current user? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean allTablesAreSelectable() throws java.sql.SQLException { return false; } /** * Does a data definition statement within a transaction force the * transaction to commit? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean dataDefinitionCausesTransactionCommit() throws java.sql.SQLException { return true; } /** * Is a data definition statement within a transaction ignored? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean dataDefinitionIgnoredInTransactions() throws java.sql.SQLException { return false; } /** * JDBC 2.0 Determine whether or not a visible row delete can be detected * by calling ResultSet.rowDeleted(). If deletesAreDetected() returns * false, then deleted rows are removed from the result set. * * @param type set type, i.e. ResultSet.TYPE_XXX * * @return true if changes are detected by the resultset type * * @exception SQLException if a database-access error occurs. */ public boolean deletesAreDetected(int type) throws SQLException { return false; } /** * Did getMaxRowSize() include LONGVARCHAR and LONGVARBINARY blobs? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean doesMaxRowSizeIncludeBlobs() throws java.sql.SQLException { return true; } /** * Extracts foreign key info for one table. * * @param rows the list of rows to add to * @param rs the result set from 'SHOW CREATE TABLE' * @param catalog the database name * * @return the list of rows with new rows added * * @throws SQLException if a database access error occurs */ public List extractForeignKeyForTable(ArrayList rows, java.sql.ResultSet rs, String catalog) throws SQLException { byte[][] row = new byte[3][]; row[0] = rs.getBytes(1); row[1] = s2b(SUPPORTS_FK); String createTableString = rs.getString(2); StringTokenizer lineTokenizer = new StringTokenizer(createTableString, "\n"); StringBuffer commentBuf = new StringBuffer("comment; "); boolean firstTime = true; while (lineTokenizer.hasMoreTokens()) { String line = lineTokenizer.nextToken().trim(); String constraintName = null; if (StringUtils.startsWithIgnoreCase(line, "CONSTRAINT")) { boolean usingBackTicks = true; int beginPos = line.indexOf("`"); if (beginPos == -1) { beginPos = line.indexOf("\""); usingBackTicks = false; } if (beginPos != -1) { int endPos = -1; if (usingBackTicks) { endPos = line.indexOf("`", beginPos + 1); } else { endPos = line.indexOf("\"", beginPos + 1); } if (endPos != -1) { constraintName = line.substring(beginPos + 1, endPos); line = line.substring(endPos + 1, line.length()).trim(); } } } if (line.startsWith("FOREIGN KEY")) { if (line.endsWith(",")) { line = line.substring(0, line.length() - 1); } // Remove all back-ticks int lineLength = line.length(); StringBuffer lineBuf = new StringBuffer(lineLength); for (int i = 0; i < lineLength; i++) { char c = line.charAt(i); if (c != '`') { lineBuf.append(c); } } line = lineBuf.toString(); StringTokenizer keyTokens = new StringTokenizer(line, "()", false); keyTokens.nextToken(); // eat 'FOREIGN KEY' String localColumnNamesString = keyTokens.nextToken(); String referCatalogTableString = keyTokens.nextToken(); StringTokenizer referSchemaTable = new StringTokenizer(referCatalogTableString .trim(), " ."); String referColumnNamesString = keyTokens.nextToken(); referSchemaTable.nextToken(); //discard the REFERENCES token int numTokensLeft = referSchemaTable.countTokens(); String referCatalog = null; String referTable = null; if (numTokensLeft == 2) { // some versions of MySQL don't report the database name referCatalog = referSchemaTable.nextToken(); referTable = referSchemaTable.nextToken(); } else { referTable = referSchemaTable.nextToken(); referCatalog = catalog; } if (!firstTime) { commentBuf.append("; "); } else { firstTime = false; } if (constraintName != null) { commentBuf.append(constraintName); } else { commentBuf.append("not_available"); } commentBuf.append("("); commentBuf.append(localColumnNamesString); commentBuf.append(") REFER "); commentBuf.append(referCatalog); commentBuf.append("/"); commentBuf.append(referTable); commentBuf.append("("); commentBuf.append(referColumnNamesString); commentBuf.append(")"); int lastParenIndex = line.lastIndexOf(")"); if (lastParenIndex != (line.length() - 1)) { String cascadeOptions = cascadeOptions = line.substring(lastParenIndex + 1); commentBuf.append(" "); commentBuf.append(cascadeOptions); } } } row[2] = s2b(commentBuf.toString()); rows.add(row); return rows; } /** * Creates a result set similar enough to 'SHOW TABLE STATUS' to allow the * same code to work on extracting the foreign key data * * @param conn the database connection to use * @param metadata the DatabaseMetaData instance calling this method * @param catalog the database name to extract foreign key info for * @param tableName the table to extract foreign key info for * * @return A result set that has the structure of 'show table status' * * @throws SQLException if a database access error occurs. */ public ResultSet extractForeignKeyFromCreateTable( java.sql.Connection conn, java.sql.DatabaseMetaData metadata, String catalog, String tableName) throws SQLException { ArrayList tableList = new ArrayList(); java.sql.ResultSet rs = null; java.sql.Statement stmt = null; if (tableName != null) { tableList.add(tableName); } else { try { rs = metadata.getTables(catalog, "", "%", new String[] { "TABLE" }); while (rs.next()) { tableList.add(rs.getString("TABLE_NAME")); } } finally { if (rs != null) { rs.close(); } rs = null; } } ArrayList rows = new ArrayList(); Field[] fields = new Field[3]; fields[0] = new Field("", "Name", Types.CHAR, Integer.MAX_VALUE); fields[1] = new Field("", "Type", Types.CHAR, 255); fields[2] = new Field("", "Comment", Types.CHAR, Integer.MAX_VALUE); int numTables = tableList.size(); try { stmt = conn.createStatement(); if (stmt.getMaxRows() != 0) { stmt.setMaxRows(0); } for (int i = 0; i < numTables; i++) { String tableToExtract = (String) tableList.get(i); String query = new StringBuffer("SHOW CREATE TABLE ").append( "`").append(catalog).append("`.`").append(tableToExtract) .append("`") .toString(); rs = stmt.executeQuery(query); while (rs.next()) { extractForeignKeyForTable(rows, rs, catalog); } } } finally { if (rs != null) { rs.close(); } rs = null; if (stmt != null) { stmt.close(); } stmt = null; } return buildResultSet(fields, rows); } /** * JDBC 2.0 Determine whether or not a visible row insert can be detected * by calling ResultSet.rowInserted(). * * @param type set type, i.e. ResultSet.TYPE_XXX * * @return true if changes are detected by the resultset type * * @exception SQLException if a database-access error occurs. */ public boolean insertsAreDetected(int type) throws SQLException { return false; } /** * @see DatabaseMetaData#locatorsUpdateCopy() */ public boolean locatorsUpdateCopy() throws SQLException { return true; } /** * Are concatenations between NULL and non-NULL values NULL? A JDBC * compliant driver always returns true. * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean nullPlusNonNullIsNull() throws java.sql.SQLException { return true; } /** * Are NULL values sorted at the end regardless of sort order? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean nullsAreSortedAtEnd() throws java.sql.SQLException { return false; } /** * Are NULL values sorted at the start regardless of sort order? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean nullsAreSortedAtStart() throws java.sql.SQLException { if (this.conn.getIO().versionMeetsMinimum(4, 0, 2) && !this.conn.getIO().versionMeetsMinimum(4, 0, 11)) { return true; } else { return false; } } /** * Are NULL values sorted high? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean nullsAreSortedHigh() throws java.sql.SQLException { return false; } /** * Are NULL values sorted low? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean nullsAreSortedLow() throws java.sql.SQLException { return !nullsAreSortedHigh(); } /** * DOCUMENT ME! * * @param type DOCUMENT ME! * * @return DOCUMENT ME! * * @throws SQLException DOCUMENT ME! */ public boolean othersDeletesAreVisible(int type) throws SQLException { return false; } /** * DOCUMENT ME! * * @param type DOCUMENT ME! * * @return DOCUMENT ME! * * @throws SQLException DOCUMENT ME! */ public boolean othersInsertsAreVisible(int type) throws SQLException { return false; } /** * JDBC 2.0 Determine whether changes made by others are visible. * * @param type set type, i.e. ResultSet.TYPE_XXX * * @return true if changes are visible for the result set type * * @exception SQLException if a database-access error occurs. */ public boolean othersUpdatesAreVisible(int type) throws SQLException { return false; } /** * DOCUMENT ME! * * @param type DOCUMENT ME! * * @return DOCUMENT ME! * * @throws SQLException DOCUMENT ME! */ public boolean ownDeletesAreVisible(int type) throws SQLException { return false; } /** * DOCUMENT ME! * * @param type DOCUMENT ME! * * @return DOCUMENT ME! * * @throws SQLException DOCUMENT ME! */ public boolean ownInsertsAreVisible(int type) throws SQLException { return false; } /** * JDBC 2.0 Determine whether a result set's own changes visible. * * @param type set type, i.e. ResultSet.TYPE_XXX * * @return true if changes are visible for the result set type * * @exception SQLException if a database-access error occurs. */ public boolean ownUpdatesAreVisible(int type) throws SQLException { return false; } /** * Does the database store mixed case unquoted SQL identifiers in lower * case? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean storesLowerCaseIdentifiers() throws java.sql.SQLException { return false; } /** * Does the database store mixed case quoted SQL identifiers in lower case? * A JDBC compliant driver will always return false. * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean storesLowerCaseQuotedIdentifiers() throws java.sql.SQLException { return false; } /** * Does the database store mixed case unquoted SQL identifiers in mixed * case? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean storesMixedCaseIdentifiers() throws java.sql.SQLException { return true; } /** * Does the database store mixed case quoted SQL identifiers in mixed case? * A JDBC compliant driver will always return false. * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean storesMixedCaseQuotedIdentifiers() throws java.sql.SQLException { return false; } /** * Does the database store mixed case unquoted SQL identifiers in upper * case? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean storesUpperCaseIdentifiers() throws java.sql.SQLException { return false; } /** * Does the database store mixed case quoted SQL identifiers in upper case? * A JDBC compliant driver will always return true. * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean storesUpperCaseQuotedIdentifiers() throws java.sql.SQLException { return false; } /** * Is the ANSI92 entry level SQL grammar supported? All JDBC compliant * drivers must return true. * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsANSI92EntryLevelSQL() throws java.sql.SQLException { return true; } /** * Is the ANSI92 full SQL grammar supported? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsANSI92FullSQL() throws java.sql.SQLException { return false; } /** * Is the ANSI92 intermediate SQL grammar supported? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsANSI92IntermediateSQL() throws java.sql.SQLException { return false; } /** * Is "ALTER TABLE" with add column supported? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsAlterTableWithAddColumn() throws java.sql.SQLException { return true; } /** * Is "ALTER TABLE" with drop column supported? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsAlterTableWithDropColumn() throws java.sql.SQLException { return true; } /** * JDBC 2.0 Return true if the driver supports batch updates, else return * false. * * @return DOCUMENT ME! * * @throws SQLException DOCUMENT ME! */ public boolean supportsBatchUpdates() throws SQLException { return true; } /** * Can a catalog name be used in a data manipulation statement? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsCatalogsInDataManipulation() throws java.sql.SQLException { // Servers before 3.22 could not do this return this.conn.getIO().versionMeetsMinimum(3, 3, 22); } /** * Can a catalog name be used in a index definition statement? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsCatalogsInIndexDefinitions() throws java.sql.SQLException { return false; } /** * Can a catalog name be used in a privilege definition statement? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsCatalogsInPrivilegeDefinitions() throws java.sql.SQLException { return false; } /** * Can a catalog name be used in a procedure call statement? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsCatalogsInProcedureCalls() throws java.sql.SQLException { return false; } /** * Can a catalog name be used in a table definition statement? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsCatalogsInTableDefinitions() throws java.sql.SQLException { return false; } /** * Is column aliasing supported? * * <P> * If so, the SQL AS clause can be used to provide names for computed * columns or to provide alias names for columns as required. A JDBC * compliant driver always returns true. * </p> * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsColumnAliasing() throws java.sql.SQLException { return true; } /** * Is the CONVERT function between SQL types supported? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsConvert() throws java.sql.SQLException { return true; } /** * Is CONVERT between the given SQL types supported? * * @param fromType the type to convert from * @param toType the type to convert to * * @return true if so * * @throws java.sql.SQLException if an error occurs * * @see Types */ public boolean supportsConvert(int fromType, int toType) throws java.sql.SQLException { switch (fromType) { /* The char/binary types can be converted * to pretty much anything. */ case java.sql.Types.CHAR: case java.sql.Types.VARCHAR: case java.sql.Types.LONGVARCHAR: case java.sql.Types.BINARY: case java.sql.Types.VARBINARY: case java.sql.Types.LONGVARBINARY: switch (toType) { case java.sql.Types.DECIMAL: case java.sql.Types.NUMERIC: case java.sql.Types.REAL: case java.sql.Types.TINYINT: case java.sql.Types.SMALLINT: case java.sql.Types.INTEGER: case java.sql.Types.BIGINT: case java.sql.Types.FLOAT: case java.sql.Types.DOUBLE: case java.sql.Types.CHAR: case java.sql.Types.VARCHAR: case java.sql.Types.LONGVARCHAR: case java.sql.Types.BINARY: case java.sql.Types.VARBINARY: case java.sql.Types.LONGVARBINARY: case java.sql.Types.OTHER: case java.sql.Types.DATE: case java.sql.Types.TIME: case java.sql.Types.TIMESTAMP: return true; default: return false; } /* We don't handle the BIT type * yet. */ case java.sql.Types.BIT: return false; /* The numeric types. Basically they can convert * among themselves, and with char/binary types. */ case java.sql.Types.DECIMAL: case java.sql.Types.NUMERIC: case java.sql.Types.REAL: case java.sql.Types.TINYINT: case java.sql.Types.SMALLINT: case java.sql.Types.INTEGER: case java.sql.Types.BIGINT: case java.sql.Types.FLOAT: case java.sql.Types.DOUBLE: switch (toType) { case java.sql.Types.DECIMAL: case java.sql.Types.NUMERIC: case java.sql.Types.REAL: case java.sql.Types.TINYINT: case java.sql.Types.SMALLINT: case java.sql.Types.INTEGER: case java.sql.Types.BIGINT: case java.sql.Types.FLOAT: case java.sql.Types.DOUBLE: case java.sql.Types.CHAR: case java.sql.Types.VARCHAR: case java.sql.Types.LONGVARCHAR: case java.sql.Types.BINARY: case java.sql.Types.VARBINARY: case java.sql.Types.LONGVARBINARY: return true; default: return false; } /* MySQL doesn't support a NULL type. */ case java.sql.Types.NULL: return false; /* With this driver, this will always be a serialized * object, so the char/binary types will work. */ case java.sql.Types.OTHER: switch (toType) { case java.sql.Types.CHAR: case java.sql.Types.VARCHAR: case java.sql.Types.LONGVARCHAR: case java.sql.Types.BINARY: case java.sql.Types.VARBINARY: case java.sql.Types.LONGVARBINARY: return true; default: return false; } /* Dates can be converted to char/binary types. */ case java.sql.Types.DATE: switch (toType) { case java.sql.Types.CHAR: case java.sql.Types.VARCHAR: case java.sql.Types.LONGVARCHAR: case java.sql.Types.BINARY: case java.sql.Types.VARBINARY: case java.sql.Types.LONGVARBINARY: return true; default: return false; } /* Time can be converted to char/binary types */ case java.sql.Types.TIME: switch (toType) { case java.sql.Types.CHAR: case java.sql.Types.VARCHAR: case java.sql.Types.LONGVARCHAR: case java.sql.Types.BINARY: case java.sql.Types.VARBINARY: case java.sql.Types.LONGVARBINARY: return true; default: return false; } /* Timestamp can be converted to char/binary types * and date/time types (with loss of precision). */ case java.sql.Types.TIMESTAMP: switch (toType) { case java.sql.Types.CHAR: case java.sql.Types.VARCHAR: case java.sql.Types.LONGVARCHAR: case java.sql.Types.BINARY: case java.sql.Types.VARBINARY: case java.sql.Types.LONGVARBINARY: case java.sql.Types.TIME: case java.sql.Types.DATE: return true; default: return false; } /* We shouldn't get here! */ default: return false; // not sure } } /** * Is the ODBC Core SQL grammar supported? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsCoreSQLGrammar() throws java.sql.SQLException { return true; } /** * Are correlated subqueries supported? A JDBC compliant driver always * returns true. * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsCorrelatedSubqueries() throws java.sql.SQLException { return false; } /** * Are both data definition and data manipulation statements within a * transaction supported? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsDataDefinitionAndDataManipulationTransactions() throws java.sql.SQLException { return false; } /** * Are only data manipulation statements within a transaction supported? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsDataManipulationTransactionsOnly() throws java.sql.SQLException { return false; } /** * If table correlation names are supported, are they restricted to be * different from the names of the tables? A JDBC compliant driver always * returns true. * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsDifferentTableCorrelationNames() throws java.sql.SQLException { return true; } /** * Are expressions in "ORDER BY" lists supported? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsExpressionsInOrderBy() throws java.sql.SQLException { return true; } /** * Is the ODBC Extended SQL grammar supported? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsExtendedSQLGrammar() throws java.sql.SQLException { return false; } /** * Are full nested outer joins supported? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsFullOuterJoins() throws java.sql.SQLException { return false; } /** * JDBC 3.0 * * @return DOCUMENT ME! */ public boolean supportsGetGeneratedKeys() { return true; } /** * Is some form of "GROUP BY" clause supported? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsGroupBy() throws java.sql.SQLException { return true; } /** * Can a "GROUP BY" clause add columns not in the SELECT provided it * specifies all the columns in the SELECT? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsGroupByBeyondSelect() throws java.sql.SQLException { return true; } /** * Can a "GROUP BY" clause use columns not in the SELECT? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsGroupByUnrelated() throws java.sql.SQLException { return false; } /** * Is the SQL Integrity Enhancement Facility supported? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsIntegrityEnhancementFacility() throws java.sql.SQLException { return false; } /** * Is the escape character in "LIKE" clauses supported? A JDBC compliant * driver always returns true. * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsLikeEscapeClause() throws java.sql.SQLException { return true; } /** * Is there limited support for outer joins? (This will be true if * supportFullOuterJoins is true.) * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsLimitedOuterJoins() throws java.sql.SQLException { return true; } /** * Is the ODBC Minimum SQL grammar supported? All JDBC compliant drivers * must return true. * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsMinimumSQLGrammar() throws java.sql.SQLException { return true; } /** * Does the database support mixed case unquoted SQL identifiers? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsMixedCaseIdentifiers() throws java.sql.SQLException { return false; } /** * Does the database support mixed case quoted SQL identifiers? A JDBC * compliant driver will always return true. * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsMixedCaseQuotedIdentifiers() throws java.sql.SQLException { return false; } /** * @see DatabaseMetaData#supportsMultipleOpenResults() */ public boolean supportsMultipleOpenResults() throws SQLException { return false; } /** * Are multiple ResultSets from a single execute supported? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsMultipleResultSets() throws java.sql.SQLException { return false; } /** * Can we have multiple transactions open at once (on different * connections)? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsMultipleTransactions() throws java.sql.SQLException { return true; } /** * @see DatabaseMetaData#supportsNamedParameters() */ public boolean supportsNamedParameters() throws SQLException { return false; } /** * Can columns be defined as non-nullable? A JDBC compliant driver always * returns true. * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsNonNullableColumns() throws java.sql.SQLException { return true; } /** * Can cursors remain open across commits? * * @return true if so * * @throws java.sql.SQLException if a database access error occurs * * @see Connection#disableAutoClose */ public boolean supportsOpenCursorsAcrossCommit() throws java.sql.SQLException { return false; } /** * Can cursors remain open across rollbacks? * * @return true if so * * @throws java.sql.SQLException if an error occurs * * @see Connection#disableAutoClose */ public boolean supportsOpenCursorsAcrossRollback() throws java.sql.SQLException { return false; } /** * Can statements remain open across commits? * * @return true if so * * @throws java.sql.SQLException if an error occurs * * @see Connection#disableAutoClose */ public boolean supportsOpenStatementsAcrossCommit() throws java.sql.SQLException { return false; } /** * Can statements remain open across rollbacks? * * @return true if so * * @throws java.sql.SQLException if an error occurs * * @see Connection#disableAutoClose */ public boolean supportsOpenStatementsAcrossRollback() throws java.sql.SQLException { return false; } /** * Can an "ORDER BY" clause use columns not in the SELECT? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsOrderByUnrelated() throws java.sql.SQLException { return false; } /** * Is some form of outer join supported? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsOuterJoins() throws java.sql.SQLException { return true; } /** * Is positioned DELETE supported? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsPositionedDelete() throws java.sql.SQLException { return false; } /** * Is positioned UPDATE supported? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsPositionedUpdate() throws java.sql.SQLException { return false; } /** * JDBC 2.0 Does the database support the concurrency type in combination * with the given result set type? * * @param type defined in java.sql.ResultSet * @param concurrency type defined in java.sql.ResultSet * * @return true if so * * @exception SQLException if a database-access error occurs. * * @see Connection */ public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException { return ((type == ResultSet.TYPE_SCROLL_INSENSITIVE) && ((concurrency == ResultSet.CONCUR_READ_ONLY) || (concurrency == ResultSet.CONCUR_UPDATABLE))); } /** * @see DatabaseMetaData#supportsResultSetHoldability(int) */ public boolean supportsResultSetHoldability(int holdability) throws SQLException { return (holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT); } /** * JDBC 2.0 Does the database support the given result set type? * * @param type defined in java.sql.ResultSet * * @return true if so * * @exception SQLException if a database-access error occurs. * * @see Connection */ public boolean supportsResultSetType(int type) throws SQLException { return (type == ResultSet.TYPE_SCROLL_INSENSITIVE); } /** * @see DatabaseMetaData#supportsSavepoints() */ public boolean supportsSavepoints() throws SQLException { return false; } /** * Can a schema name be used in a data manipulation statement? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsSchemasInDataManipulation() throws java.sql.SQLException { return false; } /** * Can a schema name be used in an index definition statement? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsSchemasInIndexDefinitions() throws java.sql.SQLException { return false; } /** * Can a schema name be used in a privilege definition statement? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsSchemasInPrivilegeDefinitions() throws java.sql.SQLException { return false; } /** * Can a schema name be used in a procedure call statement? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsSchemasInProcedureCalls() throws java.sql.SQLException { return false; } /** * Can a schema name be used in a table definition statement? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsSchemasInTableDefinitions() throws java.sql.SQLException { return false; } /** * Is SELECT for UPDATE supported? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsSelectForUpdate() throws java.sql.SQLException { return false; } /** * @see DatabaseMetaData#supportsStatementPooling() */ public boolean supportsStatementPooling() throws SQLException { return false; } /** * Are stored procedure calls using the stored procedure escape syntax * supported? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsStoredProcedures() throws java.sql.SQLException { return false; } /** * Are subqueries in comparison expressions supported? A JDBC compliant * driver always returns true. * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsSubqueriesInComparisons() throws java.sql.SQLException { return this.conn.getIO().versionMeetsMinimum(4, 1, 0); } /** * Are subqueries in exists expressions supported? A JDBC compliant driver * always returns true. * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsSubqueriesInExists() throws java.sql.SQLException { return this.conn.getIO().versionMeetsMinimum(4, 1, 0); } /** * Are subqueries in "in" statements supported? A JDBC compliant driver * always returns true. * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsSubqueriesInIns() throws java.sql.SQLException { return this.conn.getIO().versionMeetsMinimum(4, 1, 0); } /** * Are subqueries in quantified expressions supported? A JDBC compliant * driver always returns true. * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsSubqueriesInQuantifieds() throws java.sql.SQLException { return this.conn.getIO().versionMeetsMinimum(4, 1, 0); } /** * Are table correlation names supported? A JDBC compliant driver always * returns true. * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsTableCorrelationNames() throws java.sql.SQLException { return true; } /** * Does the database support the given transaction isolation level? * * @param level the values are defined in java.sql.Connection * * @return true if so * * @throws java.sql.SQLException if a database access error occurs * * @see Connection */ public boolean supportsTransactionIsolationLevel(int level) throws java.sql.SQLException { if (this.conn.supportsIsolationLevel()) { switch (level) { case java.sql.Connection.TRANSACTION_READ_COMMITTED: case java.sql.Connection.TRANSACTION_READ_UNCOMMITTED: case java.sql.Connection.TRANSACTION_REPEATABLE_READ: case java.sql.Connection.TRANSACTION_SERIALIZABLE: return true; default: return false; } } else { return false; } } /** * Are transactions supported? If not, commit is a noop and the isolation * level is TRANSACTION_NONE. * * @return true if transactions are supported * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsTransactions() throws java.sql.SQLException { return this.conn.supportsTransactions(); } /** * Is SQL UNION supported? A JDBC compliant driver always returns true. * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsUnion() throws java.sql.SQLException { return this.conn.getIO().versionMeetsMinimum(4, 0, 0); } /** * Is SQL UNION ALL supported? A JDBC compliant driver always returns true. * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean supportsUnionAll() throws java.sql.SQLException { return this.conn.getIO().versionMeetsMinimum(4, 0, 0); } /** * JDBC 2.0 Determine whether or not a visible row update can be detected * by calling ResultSet.rowUpdated(). * * @param type set type, i.e. ResultSet.TYPE_XXX * * @return true if changes are detected by the resultset type * * @exception SQLException if a database-access error occurs. */ public boolean updatesAreDetected(int type) throws SQLException { return false; } /** * Does the database use a file for each table? * * @return true if the database uses a local file for each table * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean usesLocalFilePerTable() throws java.sql.SQLException { return false; } /** * Does the database store tables in a local file? * * @return true if so * * @throws java.sql.SQLException DOCUMENT ME! */ public boolean usesLocalFiles() throws java.sql.SQLException { return false; } /** * Parses the cascade option string and returns the DBMD constant that * represents it (for deletes) * * @param cascadeOptions the comment from 'SHOW TABLE STATUS' * * @return the DBMD constant that represents the cascade option */ private int getCascadeDeleteOption(String cascadeOptions) { int onDeletePos = cascadeOptions.indexOf("ON DELETE"); if (onDeletePos != -1) { String deleteOptions = cascadeOptions.substring(onDeletePos, cascadeOptions.length()); if (deleteOptions.startsWith("ON DELETE CASCADE")) { return DatabaseMetaData.importedKeyCascade; } else if (deleteOptions.startsWith("ON DELETE SET NULL")) { return DatabaseMetaData.importedKeySetNull; } else if (deleteOptions.startsWith("ON DELETE RESTRICT")) { return DatabaseMetaData.importedKeyRestrict; } else if (deleteOptions.startsWith("ON DELETE NO ACTION")) { return DatabaseMetaData.importedKeyNoAction; } } return DatabaseMetaData.importedKeyNoAction; } /** * Parses the cascade option string and returns the DBMD constant that * represents it (for Updates) * * @param cascadeOptions the comment from 'SHOW TABLE STATUS' * * @return the DBMD constant that represents the cascade option */ private int getCascadeUpdateOption(String cascadeOptions) { int onUpdatePos = cascadeOptions.indexOf("ON UPDATE"); if (onUpdatePos != -1) { String updateOptions = cascadeOptions.substring(onUpdatePos, cascadeOptions.length()); if (updateOptions.startsWith("ON UPDATE CASCADE")) { return DatabaseMetaData.importedKeyCascade; } else if (updateOptions.startsWith("ON UPDATE SET NULL")) { return DatabaseMetaData.importedKeySetNull; } else if (updateOptions.startsWith("ON UPDATE RESTRICT")) { return DatabaseMetaData.importedKeyRestrict; } else if (updateOptions.startsWith("ON UPDATE NO ACTION")) { return DatabaseMetaData.importedKeyNoAction; } } return DatabaseMetaData.importedKeyNoAction; } /** * Adds to the tuples list the exported keys of exportingTable based on the * keysComment from the 'show table status' sql command. KeysComment is * that part of the comment field that follows the "InnoDB free ...;" * prefix. * * @param catalog the database to use * @param exportingTable the table keys are being exported from * @param keysComment the comment from 'show table status' * @param tuples the rows to add results to * @param fkTableName the foreign key table name * * @throws SQLException if a database access error occurs */ private void getExportKeyResults(String catalog, String exportingTable, String keysComment, List tuples, String fkTableName) throws SQLException { getResultsImpl(catalog, exportingTable, keysComment, tuples, fkTableName, true); } /** * Returns the DELETE and UPDATE foreign key actions from the given 'SHOW * TABLE STATUS' string, with the DELETE action being the first item in * the array, and the UPDATE action being the second. * * @param commentString the comment from 'SHOW TABLE STATUS' * * @return int[] [0] = delete action, [1] = update action */ private int[] getForeignKeyActions(String commentString) { int[] actions = new int[] { DatabaseMetaData.importedKeyNoAction, DatabaseMetaData.importedKeyNoAction }; int lastParenIndex = commentString.lastIndexOf(")"); if (lastParenIndex != (commentString.length() - 1)) { String cascadeOptions = commentString.substring(lastParenIndex + 1) .trim().toUpperCase(); actions[0] = getCascadeDeleteOption(cascadeOptions); actions[1] = getCascadeUpdateOption(cascadeOptions); } return actions; } /** * Populates the tuples list with the imported keys of importingTable based * on the keysComment from the 'show table status' sql command. * KeysComment is that part of the comment field that follows the "InnoDB * free ...;" prefix. * * @param catalog the database to use * @param importingTable the table keys are being imported to * @param keysComment the comment from 'show table status' * @param tuples the rows to add results to * * @throws SQLException if a database access error occurs */ private void getImportKeyResults(String catalog, String importingTable, String keysComment, List tuples) throws SQLException { getResultsImpl(catalog, importingTable, keysComment, tuples, null, false); } private void getResultsImpl(String catalog, String table, String keysComment, List tuples, String fkTableName, boolean isExport) throws SQLException { // keys will equal something like this: // (parent_service_id child_service_id) REFER ds/subservices(parent_service_id child_service_id) // parse of the string into three phases: // 1: parse the opening parentheses to determine how many results there will be // 2: read in the schema name/table name // 3: parse the closing parentheses int firstLeftParenIndex = keysComment.indexOf('('); String constraintName = keysComment.substring(0, firstLeftParenIndex) .trim(); keysComment = keysComment.substring(firstLeftParenIndex, keysComment.length()); StringTokenizer keyTokens = new StringTokenizer(keysComment.trim(), "()", false); String localColumnNamesString = keyTokens.nextToken(); StringTokenizer localColumnNames = new StringTokenizer(localColumnNamesString, " ,"); String referCatalogTableString = keyTokens.nextToken(); StringTokenizer referSchemaTable = new StringTokenizer(referCatalogTableString, " /"); String referColumnNamesString = keyTokens.nextToken(); StringTokenizer referColumnNames = new StringTokenizer(referColumnNamesString, " ,"); referSchemaTable.nextToken(); //discard the REFER token String referCatalog = referSchemaTable.nextToken(); String referTable = referSchemaTable.nextToken(); if (isExport && !referTable.equals(table)) { return; } if (localColumnNames.countTokens() != referColumnNames.countTokens()) { throw new SQLException("Error parsing foriegn keys definition", SQLError.SQL_STATE_GENERAL_ERROR); } int keySeqIndex = 1; byte[] connectionCatalogAsBytes = null; if (catalog == null) { connectionCatalogAsBytes = s2b(this.conn.getCatalog()); } else { connectionCatalogAsBytes = s2b(catalog); } while (localColumnNames.hasMoreTokens()) { byte[][] tuple = new byte[14][]; String localColumnName = localColumnNames.nextToken(); String referColumnName = referColumnNames.nextToken(); tuple[FKTABLE_CAT] = connectionCatalogAsBytes; tuple[FKTABLE_SCHEM] = null; tuple[FKTABLE_NAME] = s2b((isExport) ? fkTableName : table); tuple[FKCOLUMN_NAME] = s2b(localColumnName); tuple[PKTABLE_CAT] = s2b(referCatalog); tuple[PKTABLE_SCHEM] = null; tuple[PKTABLE_NAME] = s2b((isExport) ? table : referTable); tuple[PKCOLUMN_NAME] = s2b(referColumnName); tuple[KEY_SEQ] = s2b(Integer.toString(keySeqIndex++)); int[] actions = getForeignKeyActions(keysComment); tuple[UPDATE_RULE] = s2b(Integer.toString(actions[1])); tuple[DELETE_RULE] = s2b(Integer.toString(actions[0])); tuple[FK_NAME] = s2b(constraintName); tuple[PK_NAME] = null; //not available from show table status tuple[DEFERRABILITY] = s2b(Integer.toString( java.sql.DatabaseMetaData.importedKeyNotDeferrable)); tuples.add(tuple); } } private String getTableNameWithCase(String table) { String tableNameWithCase = (this.conn.lowerCaseTableNames() ? table.toLowerCase() : table); return tableNameWithCase; } private java.sql.ResultSet buildResultSet(com.mysql.jdbc.Field[] fields, java.util.ArrayList rows) throws SQLException { int fieldsLength = fields.length; for (int i = 0; i < fieldsLength; i++) { fields[i].setConnection(this.conn); } return new com.mysql.jdbc.ResultSet(this.conn.getCatalog(), fields, new RowDataStatic(rows), this.conn); } /** * Converts the given string to bytes, using the connection's character * encoding, or if not available, the JVM default encoding. * * @param s DOCUMENT ME! * * @return DOCUMENT ME! */ private byte[] s2b(String s) { if ((this.conn != null) && this.conn.useUnicode()) { try { String encoding = this.conn.getEncoding(); if (encoding == null) { return s.getBytes(); } else { SingleByteCharsetConverter converter = this.conn.getCharsetConverter(encoding); if (converter != null) { return converter.toBytes(s); } else { return s.getBytes(encoding); } } } catch (java.io.UnsupportedEncodingException E) { return s.getBytes(); } } else { return s.getBytes(); } } }