KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > mysql > jdbc > DatabaseMetaData


1 /*
2    Copyright (C) 2002 MySQL AB
3
4       This program is free software; you can redistribute it and/or modify
5       it under the terms of the GNU General Public License as published by
6       the Free Software Foundation; either version 2 of the License, or
7       (at your option) any later version.
8
9       This program is distributed in the hope that it will be useful,
10       but WITHOUT ANY WARRANTY; without even the implied warranty of
11       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12       GNU General Public License for more details.
13
14       You should have received a copy of the GNU General Public License
15       along with this program; if not, write to the Free Software
16       Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18  */

19 package com.mysql.jdbc;
20
21 import java.sql.ResultSet JavaDoc;
22 import java.sql.SQLException JavaDoc;
23 import java.sql.Statement JavaDoc;
24 import java.sql.Types JavaDoc;
25
26 import java.util.ArrayList JavaDoc;
27 import java.util.Iterator JavaDoc;
28 import java.util.List JavaDoc;
29 import java.util.StringTokenizer JavaDoc;
30 import java.util.TreeMap JavaDoc;
31
32
33 /**
34  * JDBC Interface to Mysql functions
35  *
36  * <p>
37  * This class provides information about the database as a whole.
38  * </p>
39  *
40  * <p>
41  * Many of the methods here return lists of information in ResultSets. You can
42  * use the normal ResultSet methods such as getString and getInt to retrieve
43  * the data from these ResultSets. If a given form of metadata is not
44  * available, these methods show throw a java.sql.SQLException.
45  * </p>
46  *
47  * <p>
48  * Some of these methods take arguments that are String patterns. These
49  * methods all have names such as fooPattern. Within a pattern String "%"
50  * means match any substring of 0 or more characters and "_" means match any
51  * one character.
52  * </p>
53  *
54  * @author Mark Matthews
55  * @version $Id: DatabaseMetaData.java,v 1.27.2.34 2004/02/04 02:47:36 mmatthew Exp $
56  */

57 public class DatabaseMetaData implements java.sql.DatabaseMetaData JavaDoc {
58     private static final byte[] TABLE_AS_BYTES = "TABLE".getBytes();
59
60     /** The table type for generic tables that support foreign keys. */
61     private static final String JavaDoc SUPPORTS_FK = "SUPPORTS_FK";
62
63     //
64
// Column indexes used by all DBMD foreign key
65
// ResultSets
66
//
67
private static final int PKTABLE_CAT = 0;
68     private static final int PKTABLE_SCHEM = 1;
69     private static final int PKTABLE_NAME = 2;
70     private static final int PKCOLUMN_NAME = 3;
71     private static final int FKTABLE_CAT = 4;
72     private static final int FKTABLE_SCHEM = 5;
73     private static final int FKTABLE_NAME = 6;
74     private static final int FKCOLUMN_NAME = 7;
75     private static final int KEY_SEQ = 8;
76     private static final int UPDATE_RULE = 9;
77     private static final int DELETE_RULE = 10;
78     private static final int FK_NAME = 11;
79     private static final int PK_NAME = 12;
80     private static final int DEFERRABILITY = 13;
81
82     /** The connection to the database */
83     private Connection conn;
84
85     /** The 'current' database name being used */
86     private String JavaDoc database = null;
87
88     /** What character to use when quoting identifiers */
89     private String JavaDoc quotedId = null;
90
91     /**
92      * Creates a new DatabaseMetaData object.
93      *
94      * @param conn DOCUMENT ME!
95      * @param database DOCUMENT ME!
96      */

97     public DatabaseMetaData(Connection conn, String JavaDoc database) {
98         this.conn = conn;
99         this.database = database;
100
101         try {
102             this.quotedId = this.conn.supportsQuotedIdentifiers()
103                 ? getIdentifierQuoteString() : "";
104         } catch (SQLException JavaDoc sqlEx) {
105             // Forced by API, never thrown from getIdentifierQuoteString() in this
106
// implementation.
107
AssertionFailedException.shouldNotHappen(sqlEx);
108         }
109     }
110
111     /**
112      * @see DatabaseMetaData#getAttributes(String, String, String, String)
113      */

114     public java.sql.ResultSet JavaDoc getAttributes(String JavaDoc arg0, String JavaDoc arg1,
115         String JavaDoc arg2, String JavaDoc arg3) throws SQLException JavaDoc {
116         Field[] fields = new Field[21];
117         fields[0] = new Field("", "TYPE_CAT", Types.CHAR, 32);
118         fields[1] = new Field("", "TYPE_SCHEM", Types.CHAR, 32);
119         fields[2] = new Field("", "TYPE_NAME", Types.CHAR, 32);
120         fields[3] = new Field("", "ATTR_NAME", Types.CHAR, 32);
121         fields[4] = new Field("", "DATA_TYPE", Types.SMALLINT, 32);
122         fields[5] = new Field("", "ATTR_TYPE_NAME", Types.CHAR, 32);
123         fields[6] = new Field("", "ATTR_SIZE", Types.INTEGER, 32);
124         fields[7] = new Field("", "DECIMAL_DIGITS", Types.INTEGER, 32);
125         fields[8] = new Field("", "NUM_PREC_RADIX", Types.INTEGER, 32);
126         fields[9] = new Field("", "NULLABLE ", Types.INTEGER, 32);
127         fields[10] = new Field("", "REMARKS", Types.CHAR, 32);
128         fields[11] = new Field("", "ATTR_DEF", Types.CHAR, 32);
129         fields[12] = new Field("", "SQL_DATA_TYPE", Types.INTEGER, 32);
130         fields[13] = new Field("", "SQL_DATETIME_SUB", Types.INTEGER, 32);
131         fields[14] = new Field("", "CHAR_OCTET_LENGTH", Types.INTEGER, 32);
132         fields[15] = new Field("", "ORDINAL_POSITION", Types.INTEGER, 32);
133         fields[16] = new Field("", "IS_NULLABLE", Types.CHAR, 32);
134         fields[17] = new Field("", "SCOPE_CATALOG", Types.CHAR, 32);
135         fields[18] = new Field("", "SCOPE_SCHEMA", Types.CHAR, 32);
136         fields[19] = new Field("", "SCOPE_TABLE", Types.CHAR, 32);
137         fields[20] = new Field("", "SOURCE_DATA_TYPE", Types.SMALLINT, 32);
138
139         return buildResultSet(fields, new ArrayList JavaDoc());
140     }
141
142     /**
143      * Get a description of a table's optimal set of columns that uniquely
144      * identifies a row. They are ordered by SCOPE.
145      *
146      * <P>
147      * Each column description has the following columns:
148      *
149      * <OL>
150      * <li>
151      * <B>SCOPE</B> short => actual scope of result
152      *
153      * <UL>
154      * <li>
155      * bestRowTemporary - very temporary, while using row
156      * </li>
157      * <li>
158      * bestRowTransaction - valid for remainder of current transaction
159      * </li>
160      * <li>
161      * bestRowSession - valid for remainder of current session
162      * </li>
163      * </ul>
164      *
165      * </li>
166      * <li>
167      * <B>COLUMN_NAME</B> String => column name
168      * </li>
169      * <li>
170      * <B>DATA_TYPE</B> short => SQL data type from java.sql.Types
171      * </li>
172      * <li>
173      * <B>TYPE_NAME</B> String => Data source dependent type name
174      * </li>
175      * <li>
176      * <B>COLUMN_SIZE</B> int => precision
177      * </li>
178      * <li>
179      * <B>BUFFER_LENGTH</B> int => not used
180      * </li>
181      * <li>
182      * <B>DECIMAL_DIGITS</B> short => scale
183      * </li>
184      * <li>
185      * <B>PSEUDO_COLUMN</B> short => is this a pseudo column like an Oracle
186      * ROWID
187      *
188      * <UL>
189      * <li>
190      * bestRowUnknown - may or may not be pseudo column
191      * </li>
192      * <li>
193      * bestRowNotPseudo - is NOT a pseudo column
194      * </li>
195      * <li>
196      * bestRowPseudo - is a pseudo column
197      * </li>
198      * </ul>
199      *
200      * </li>
201      * </ol>
202      * </p>
203      *
204      * @param catalog a catalog name; "" retrieves those without a catalog
205      * @param schema a schema name; "" retrieves those without a schema
206      * @param table a table name
207      * @param scope the scope of interest; use same values as SCOPE
208      * @param nullable include columns that are nullable?
209      *
210      * @return ResultSet each row is a column description
211      *
212      * @throws java.sql.SQLException DOCUMENT ME!
213      */

214     public java.sql.ResultSet JavaDoc getBestRowIdentifier(String JavaDoc catalog,
215         String JavaDoc schema, String JavaDoc table, int scope, boolean nullable)
216         throws java.sql.SQLException JavaDoc {
217         Field[] fields = new Field[8];
218         fields[0] = new Field("", "SCOPE", Types.SMALLINT, 5);
219         fields[1] = new Field("", "COLUMN_NAME", Types.CHAR, 32);
220         fields[2] = new Field("", "DATA_TYPE", Types.SMALLINT, 32);
221         fields[3] = new Field("", "TYPE_NAME", Types.CHAR, 32);
222         fields[4] = new Field("", "COLUMN_SIZE", Types.INTEGER, 10);
223         fields[5] = new Field("", "BUFFER_LENGTH", Types.INTEGER, 10);
224         fields[6] = new Field("", "DECIMAL_DIGITS", Types.INTEGER, 10);
225         fields[7] = new Field("", "PSEUDO_COLUMN", Types.SMALLINT, 5);
226
227         String JavaDoc databasePart = "";
228
229         if (catalog != null) {
230             if (!catalog.equals("")) {
231                 databasePart = " FROM " + this.quotedId + catalog
232                     + this.quotedId;
233             }
234         } else {
235             databasePart = " FROM " + this.quotedId + this.database
236                 + this.quotedId;
237         }
238
239         if (table == null) {
240             throw new java.sql.SQLException JavaDoc("Table not specified.", SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
241         }
242
243         ResultSet results = null;
244         Statement stmt = null;
245
246         try {
247             stmt = this.conn.createStatement();
248
249             if (stmt.getMaxRows() != 0) {
250                 stmt.setMaxRows(0);
251             }
252             
253             StringBuffer JavaDoc queryBuf = new StringBuffer JavaDoc("SHOW COLUMNS FROM ");
254             queryBuf.append(this.quotedId);
255             queryBuf.append(table);
256             queryBuf.append(this.quotedId);
257             queryBuf.append(databasePart);
258
259             results = stmt.executeQuery(queryBuf.toString());
260
261             ArrayList JavaDoc tuples = new ArrayList JavaDoc();
262
263             while (results.next()) {
264                 String JavaDoc keyType = results.getString("Key");
265
266                 if (keyType != null) {
267                     if (StringUtils.startsWithIgnoreCase(keyType, "PRI")) {
268                         byte[][] rowVal = new byte[8][];
269                         rowVal[0] = Integer.toString(java.sql.DatabaseMetaData.bestRowSession)
270                                            .getBytes();
271                         rowVal[1] = results.getBytes("Field");
272
273                         String JavaDoc type = results.getString("Type");
274                         int size = MysqlIO.getMaxBuf();
275                         int decimals = 0;
276
277                         /*
278                          * Parse the Type column from MySQL
279                          */

280                         if (type.indexOf("enum") != -1) {
281                             String JavaDoc temp = type.substring(type.indexOf("("),
282                                     type.indexOf(")"));
283                             java.util.StringTokenizer JavaDoc tokenizer = new java.util.StringTokenizer JavaDoc(temp,
284                                     ",");
285                             int maxLength = 0;
286
287                             while (tokenizer.hasMoreTokens()) {
288                                 maxLength = Math.max(maxLength,
289                                         (tokenizer.nextToken().length() - 2));
290                             }
291
292                             size = maxLength;
293                             decimals = 0;
294                             type = "enum";
295                         } else if (type.indexOf("(") != -1) {
296                             if (type.indexOf(",") != -1) {
297                                 size = Integer.parseInt(type.substring(type
298                                             .indexOf("(") + 1, type.indexOf(",")));
299                                 decimals = Integer.parseInt(type.substring(type
300                                             .indexOf(",") + 1, type.indexOf(")")));
301                             } else {
302                                 size = Integer.parseInt(type.substring(type
303                                             .indexOf("(") + 1, type.indexOf(")")));
304                             }
305
306                             type = type.substring(type.indexOf("("));
307                         }
308
309                         rowVal[2] = new byte[0]; // FIXME!
310
rowVal[3] = s2b(type);
311                         rowVal[4] = Integer.toString(size + decimals).getBytes();
312                         rowVal[5] = Integer.toString(size + decimals).getBytes();
313                         rowVal[6] = Integer.toString(decimals).getBytes();
314                         rowVal[7] = Integer.toString(java.sql.DatabaseMetaData.bestRowNotPseudo)
315                                            .getBytes();
316                         tuples.add(rowVal);
317                     }
318                 }
319             }
320
321             return buildResultSet(fields, tuples);
322         } finally {
323             if (results != null) {
324                 try {
325                     results.close();
326                 } catch (Exception JavaDoc ex) {
327                     ;
328                 }
329
330                 results = null;
331             }
332
333             if (stmt != null) {
334                 try {
335                     stmt.close();
336                 } catch (Exception JavaDoc ex) {
337                     ;
338                 }
339
340                 stmt = null;
341             }
342         }
343     }
344
345     /**
346      * Does a catalog appear at the start of a qualified table name? (Otherwise
347      * it appears at the end)
348      *
349      * @return true if it appears at the start
350      *
351      * @throws java.sql.SQLException DOCUMENT ME!
352      */

353     public boolean isCatalogAtStart() throws java.sql.SQLException JavaDoc {
354         return true;
355     }
356
357     /**
358      * What's the separator between catalog and table name?
359      *
360      * @return the separator string
361      *
362      * @throws java.sql.SQLException DOCUMENT ME!
363      */

364     public String JavaDoc getCatalogSeparator() throws java.sql.SQLException JavaDoc {
365         return ".";
366     }
367
368     /**
369      * What's the database vendor's preferred term for "catalog"?
370      *
371      * @return the vendor term
372      *
373      * @throws java.sql.SQLException DOCUMENT ME!
374      */

375     public String JavaDoc getCatalogTerm() throws java.sql.SQLException JavaDoc {
376         return "database";
377     }
378
379     /**
380      * Get the catalog names available in this database. The results are
381      * ordered by catalog name.
382      *
383      * <P>
384      * The catalog column is:
385      *
386      * <OL>
387      * <li>
388      * <B>TABLE_CAT</B> String => catalog name
389      * </li>
390      * </ol>
391      * </p>
392      *
393      * @return ResultSet each row has a single String column that is a catalog
394      * name
395      *
396      * @throws java.sql.SQLException DOCUMENT ME!
397      */

398     public java.sql.ResultSet JavaDoc getCatalogs() throws java.sql.SQLException JavaDoc {
399         java.sql.ResultSet JavaDoc results = null;
400         java.sql.Statement JavaDoc stmt = null;
401
402         try {
403             stmt = this.conn.createStatement();
404             
405             if (stmt.getMaxRows() != 0) {
406                 stmt.setMaxRows(0);
407             }
408             
409             results = stmt.executeQuery("SHOW DATABASES");
410
411             java.sql.ResultSetMetaData JavaDoc resultsMD = results.getMetaData();
412             Field[] fields = new Field[1];
413             fields[0] = new Field("", "TABLE_CAT", Types.VARCHAR,
414                     resultsMD.getColumnDisplaySize(1));
415
416             ArrayList JavaDoc tuples = new ArrayList JavaDoc();
417
418             while (results.next()) {
419                 byte[][] rowVal = new byte[1][];
420                 rowVal[0] = results.getBytes(1);
421                 tuples.add(rowVal);
422             }
423
424             return buildResultSet(fields, tuples);
425         } finally {
426             if (results != null) {
427                 try {
428                     results.close();
429                 } catch (SQLException JavaDoc sqlEx) {
430                     AssertionFailedException.shouldNotHappen(sqlEx);
431                 }
432
433                 results = null;
434             }
435
436             if (stmt != null) {
437                 try {
438                     stmt.close();
439                 } catch (SQLException JavaDoc sqlEx) {
440                     AssertionFailedException.shouldNotHappen(sqlEx);
441                 }
442
443                 stmt = null;
444             }
445         }
446     }
447
448     /**
449      * Get a description of the access rights for a table's columns.
450      *
451      * <P>
452      * Only privileges matching the column name criteria are returned. They
453      * are ordered by COLUMN_NAME and PRIVILEGE.
454      * </p>
455      *
456      * <P>
457      * Each privilige description has the following columns:
458      *
459      * <OL>
460      * <li>
461      * <B>TABLE_CAT</B> String => table catalog (may be null)
462      * </li>
463      * <li>
464      * <B>TABLE_SCHEM</B> String => table schema (may be null)
465      * </li>
466      * <li>
467      * <B>TABLE_NAME</B> String => table name
468      * </li>
469      * <li>
470      * <B>COLUMN_NAME</B> String => column name
471      * </li>
472      * <li>
473      * <B>GRANTOR</B> => grantor of access (may be null)
474      * </li>
475      * <li>
476      * <B>GRANTEE</B> String => grantee of access
477      * </li>
478      * <li>
479      * <B>PRIVILEGE</B> String => name of access (SELECT, INSERT, UPDATE,
480      * REFRENCES, ...)
481      * </li>
482      * <li>
483      * <B>IS_GRANTABLE</B> String => "YES" if grantee is permitted to grant to
484      * others; "NO" if not; null if unknown
485      * </li>
486      * </ol>
487      * </p>
488      *
489      * @param catalog a catalog name; "" retrieves those without a catalog
490      * @param schema a schema name; "" retrieves those without a schema
491      * @param table a table name
492      * @param columnNamePattern a column name pattern
493      *
494      * @return ResultSet each row is a column privilege description
495      *
496      * @throws java.sql.SQLException if a database access error occurs
497      *
498      * @see #getSearchStringEscape
499      */

500     public java.sql.ResultSet JavaDoc getColumnPrivileges(String JavaDoc catalog,
501         String JavaDoc schema, String JavaDoc table, String JavaDoc columnNamePattern)
502         throws java.sql.SQLException JavaDoc {
503         Field[] fields = new Field[8];
504         fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 64);
505         fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 1);
506         fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 64);
507         fields[3] = new Field("", "COLUMN_NAME", Types.CHAR, 64);
508         fields[4] = new Field("", "GRANTOR", Types.CHAR, 77);
509         fields[5] = new Field("", "GRANTEE", Types.CHAR, 77);
510         fields[6] = new Field("", "PRIVILEGE", Types.CHAR, 64);
511         fields[7] = new Field("", "IS_GRANTABLE", Types.CHAR, 3);
512
513         StringBuffer JavaDoc grantQuery = new StringBuffer JavaDoc(
514                 "SELECT c.host, c.db, t.grantor, c.user, "
515                 + "c.table_name, c.column_name, c.column_priv "
516                 + "from mysql.columns_priv c, mysql.tables_priv t "
517                 + "where c.host = t.host and c.db = t.db and "
518                 + "c.table_name = t.table_name ");
519
520         if ((catalog != null) && (catalog.length() != 0)) {
521             grantQuery.append(" AND c.db='");
522             grantQuery.append(catalog);
523             grantQuery.append("' ");
524             ;
525         }
526
527         grantQuery.append(" AND c.table_name ='");
528         grantQuery.append(table);
529         grantQuery.append("' AND c.column_name like '");
530         grantQuery.append(columnNamePattern);
531         grantQuery.append("'");
532
533         Statement stmt = null;
534         ResultSet results = null;
535         ArrayList JavaDoc grantRows = new ArrayList JavaDoc();
536
537         try {
538             stmt = this.conn.createStatement();
539             
540             if (stmt.getMaxRows() != 0) {
541                 stmt.setMaxRows(0);
542             }
543             
544             results = stmt.executeQuery(grantQuery.toString());
545
546             while (results.next()) {
547                 String JavaDoc host = results.getString(1);
548                 String JavaDoc database = results.getString(2);
549                 String JavaDoc grantor = results.getString(3);
550                 String JavaDoc user = results.getString(4);
551
552                 if ((user == null) || (user.length() == 0)) {
553                     user = "%";
554                 }
555
556                 StringBuffer JavaDoc fullUser = new StringBuffer JavaDoc(user);
557
558                 if ((host != null) && this.conn.useHostsInPrivileges()) {
559                     fullUser.append("@");
560                     fullUser.append(host);
561                 }
562
563                 String JavaDoc columnName = results.getString(6);
564                 String JavaDoc allPrivileges = results.getString(7);
565
566                 if (allPrivileges != null) {
567                     allPrivileges = allPrivileges.toUpperCase();
568
569                     StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(allPrivileges, ",");
570
571                     while (st.hasMoreTokens()) {
572                         String JavaDoc privilege = st.nextToken().trim();
573                         byte[][] tuple = new byte[8][];
574                         tuple[0] = s2b(database);
575                         tuple[1] = null;
576                         tuple[2] = s2b(table);
577                         tuple[3] = s2b(columnName);
578
579                         if (grantor != null) {
580                             tuple[4] = s2b(grantor);
581                         } else {
582                             tuple[4] = null;
583                         }
584
585                         tuple[5] = s2b(fullUser.toString());
586                         tuple[6] = s2b(privilege);
587                         tuple[7] = null;
588                         grantRows.add(tuple);
589                     }
590                 }
591             }
592         } finally {
593             if (results != null) {
594                 try {
595                     results.close();
596                 } catch (Exception JavaDoc ex) {
597                     ;
598                 }
599
600                 results = null;
601             }
602
603             if (stmt != null) {
604                 try {
605                     stmt.close();
606                 } catch (Exception JavaDoc ex) {
607                     ;
608                 }
609
610                 stmt = null;
611             }
612         }
613
614         return buildResultSet(fields, grantRows);
615     }
616
617     /**
618      * Get a description of table columns available in a catalog.
619      *
620      * <P>
621      * Only column descriptions matching the catalog, schema, table and column
622      * name criteria are returned. They are ordered by TABLE_SCHEM,
623      * TABLE_NAME and ORDINAL_POSITION.
624      * </p>
625      *
626      * <P>
627      * Each column description has the following columns:
628      *
629      * <OL>
630      * <li>
631      * <B>TABLE_CAT</B> String => table catalog (may be null)
632      * </li>
633      * <li>
634      * <B>TABLE_SCHEM</B> String => table schema (may be null)
635      * </li>
636      * <li>
637      * <B>TABLE_NAME</B> String => table name
638      * </li>
639      * <li>
640      * <B>COLUMN_NAME</B> String => column name
641      * </li>
642      * <li>
643      * <B>DATA_TYPE</B> short => SQL type from java.sql.Types
644      * </li>
645      * <li>
646      * <B>TYPE_NAME</B> String => Data source dependent type name
647      * </li>
648      * <li>
649      * <B>COLUMN_SIZE</B> int => column size. For char or date types this is
650      * the maximum number of characters, for numeric or decimal types this is
651      * precision.
652      * </li>
653      * <li>
654      * <B>BUFFER_LENGTH</B> is not used.
655      * </li>
656      * <li>
657      * <B>DECIMAL_DIGITS</B> int => the number of fractional digits
658      * </li>
659      * <li>
660      * <B>NUM_PREC_RADIX</B> int => Radix (typically either 10 or 2)
661      * </li>
662      * <li>
663      * <B>NULLABLE</B> int => is NULL allowed?
664      *
665      * <UL>
666      * <li>
667      * columnNoNulls - might not allow NULL values
668      * </li>
669      * <li>
670      * columnNullable - definitely allows NULL values
671      * </li>
672      * <li>
673      * columnNullableUnknown - nullability unknown
674      * </li>
675      * </ul>
676      *
677      * </li>
678      * <li>
679      * <B>REMARKS</B> String => comment describing column (may be null)
680      * </li>
681      * <li>
682      * <B>COLUMN_DEF</B> String => default value (may be null)
683      * </li>
684      * <li>
685      * <B>SQL_DATA_TYPE</B> int => unused
686      * </li>
687      * <li>
688      * <B>SQL_DATETIME_SUB</B> int => unused
689      * </li>
690      * <li>
691      * <B>CHAR_OCTET_LENGTH</B> int => for char types the maximum number of
692      * bytes in the column
693      * </li>
694      * <li>
695      * <B>ORDINAL_POSITION</B> int => index of column in table (starting at 1)
696      * </li>
697      * <li>
698      * <B>IS_NULLABLE</B> String => "NO" means column definitely does not allow
699      * NULL values; "YES" means the column might allow NULL values. An empty
700      * string means nobody knows.
701      * </li>
702      * </ol>
703      * </p>
704      *
705      * @param catalog a catalog name; "" retrieves those without a catalog
706      * @param schemaPattern a schema name pattern; "" retrieves those without a
707      * schema
708      * @param tableName a table name pattern
709      * @param columnNamePattern a column name pattern
710      *
711      * @return ResultSet each row is a column description
712      *
713      * @throws java.sql.SQLException if a database access error occurs
714      *
715      * @see #getSearchStringEscape
716      */

717     public java.sql.ResultSet JavaDoc getColumns(String JavaDoc catalog, String JavaDoc schemaPattern,
718         String JavaDoc tableName, String JavaDoc columnNamePattern)
719         throws java.sql.SQLException JavaDoc {
720         String JavaDoc databasePart = "";
721
722         if (columnNamePattern == null) {
723             columnNamePattern = "%";
724         }
725
726         if (catalog != null) {
727             if (!catalog.equals("")) {
728                 databasePart = " FROM " + this.quotedId + catalog
729                     + this.quotedId;
730             }
731         } else {
732             databasePart = " FROM " + this.quotedId + this.database
733                 + this.quotedId;
734         }
735
736         ArrayList JavaDoc tableNameList = new ArrayList JavaDoc();
737         int tablenameLength = 0;
738
739         if (tableName == null) {
740             // Select from all tables
741
java.sql.ResultSet JavaDoc tables = null;
742
743             try {
744                 tables = getTables(catalog, schemaPattern, "%", new String JavaDoc[0]);
745
746                 while (tables.next()) {
747                     String JavaDoc tableNameFromList = tables.getString("TABLE_NAME");
748                     tableNameList.add(tableNameFromList);
749
750                     if (tableNameFromList.length() > tablenameLength) {
751                         tablenameLength = tableNameFromList.length();
752                     }
753                 }
754             } finally {
755                 if (tables != null) {
756                     try {
757                         tables.close();
758                     } catch (Exception JavaDoc sqlEx) {
759                         AssertionFailedException.shouldNotHappen(sqlEx);
760                     }
761
762                     tables = null;
763                 }
764             }
765         } else {
766             java.sql.ResultSet JavaDoc tables = null;
767
768             try {
769                 tables = getTables(catalog, schemaPattern, tableName,
770                         new String JavaDoc[0]);
771
772                 while (tables.next()) {
773                     String JavaDoc tableNameFromList = tables.getString("TABLE_NAME");
774                     tableNameList.add(tableNameFromList);
775
776                     if (tableNameFromList.length() > tablenameLength) {
777                         tablenameLength = tableNameFromList.length();
778                     }
779                 }
780             } finally {
781                 if (tables != null) {
782                     try {
783                         tables.close();
784                     } catch (SQLException JavaDoc sqlEx) {
785                         AssertionFailedException.shouldNotHappen(sqlEx);
786                     }
787
788                     tables = null;
789                 }
790             }
791         }
792
793         int catalogLength = 0;
794
795         if (catalog != null) {
796             catalogLength = catalog.length();
797         } else {
798             catalog = "";
799             catalogLength = 0;
800         }
801
802         java.util.Iterator JavaDoc tableNames = tableNameList.iterator();
803         Field[] fields = new Field[18];
804         fields[0] = new Field("", "TABLE_CAT", Types.CHAR, catalogLength);
805         fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 0);
806         fields[2] = new Field("", "TABLE_NAME", Types.CHAR, tablenameLength);
807         fields[3] = new Field("", "COLUMN_NAME", Types.CHAR, 32);
808         fields[4] = new Field("", "DATA_TYPE", Types.SMALLINT, 5);
809         fields[5] = new Field("", "TYPE_NAME", Types.CHAR, 16);
810         fields[6] = new Field("", "COLUMN_SIZE", Types.INTEGER,
811                 Integer.toString(Integer.MAX_VALUE).length());
812         fields[7] = new Field("", "BUFFER_LENGTH", Types.INTEGER, 10);
813         fields[8] = new Field("", "DECIMAL_DIGITS", Types.INTEGER, 10);
814         fields[9] = new Field("", "NUM_PREC_RADIX", Types.INTEGER, 10);
815         fields[10] = new Field("", "NULLABLE", Types.INTEGER, 10);
816         fields[11] = new Field("", "REMARKS", Types.CHAR, 0);
817         fields[12] = new Field("", "COLUMN_DEF", Types.CHAR, 0);
818         fields[13] = new Field("", "SQL_DATA_TYPE", Types.INTEGER, 10);
819         fields[14] = new Field("", "SQL_DATETIME_SUB", Types.INTEGER, 10);
820         fields[15] = new Field("", "CHAR_OCTET_LENGTH", Types.INTEGER,
821                 Integer.toString(Integer.MAX_VALUE).length());
822         fields[16] = new Field("", "ORDINAL_POSITION", Types.INTEGER, 10);
823         fields[17] = new Field("", "IS_NULLABLE", Types.CHAR, 3);
824
825         ArrayList JavaDoc tuples = new ArrayList JavaDoc();
826
827         byte[] connectionCatalogAsBytes = null;
828
829         if (catalog == null) {
830             connectionCatalogAsBytes = s2b(this.conn.getCatalog());
831         } else {
832             connectionCatalogAsBytes = s2b(catalog);
833         }
834
835         while (tableNames.hasNext()) {
836             String JavaDoc tableNamePattern = (String JavaDoc) tableNames.next();
837             Statement stmt = null;
838             ResultSet results = null;
839
840             try {
841                 stmt = this.conn.createStatement();
842                 
843                 if (stmt.getMaxRows() != 0) {
844                     stmt.setMaxRows(0);
845                 }
846
847                 StringBuffer JavaDoc queryBuf = new StringBuffer JavaDoc("SHOW COLUMNS FROM ");
848                 queryBuf.append(this.quotedId);
849                 queryBuf.append(tableNamePattern);
850                 queryBuf.append(this.quotedId);
851                 queryBuf.append(databasePart);
852                 queryBuf.append(" LIKE '");
853                 queryBuf.append(columnNamePattern);
854                 queryBuf.append("'");
855
856                 results = stmt.executeQuery(queryBuf.toString());
857
858                 int ordPos = 1;
859
860                 while (results.next()) {
861                     byte[][] rowVal = new byte[18][];
862                     rowVal[0] = connectionCatalogAsBytes; // TABLE_CAT
863
rowVal[1] = null;
864
865                     // TABLE_SCHEM (No schemas in MySQL)
866
rowVal[2] = s2b(tableNamePattern); // TABLE_NAME
867
rowVal[3] = results.getBytes("Field");
868
869                     String JavaDoc typeInfo = results.getString("Type");
870
871                     if (Driver.DEBUG) {
872                         System.out.println("Type: " + typeInfo);
873                     }
874
875                     String JavaDoc mysqlType = "";
876
877                     if (typeInfo.indexOf("(") != -1) {
878                         mysqlType = typeInfo.substring(0, typeInfo.indexOf("("));
879                     } else {
880                         mysqlType = typeInfo;
881                     }
882
883                     if (this.conn.capitalizeDBMDTypes()) {
884                         mysqlType = mysqlType.toUpperCase();
885                     }
886
887                     /*
888                      * Convert to XOPEN (thanks JK)
889                      */

890                     rowVal[4] = Integer.toString(MysqlDefs.mysqlToJavaType(
891                                 mysqlType)).getBytes();
892
893                     // DATA_TYPE (jdbc)
894
rowVal[5] = s2b(mysqlType); // TYPE_NAME (native)
895

896                     // Figure Out the Size
897
if (typeInfo != null) {
898                         if (StringUtils.startsWithIgnoreCase(typeInfo, "enum")
899                                 || StringUtils.startsWithIgnoreCase(typeInfo,
900                                     "set")) {
901                             String JavaDoc temp = typeInfo.substring(typeInfo.indexOf(
902                                         "("), typeInfo.lastIndexOf(")"));
903                             java.util.StringTokenizer JavaDoc tokenizer = new java.util.StringTokenizer JavaDoc(temp,
904                                     ",");
905                             int maxLength = 0;
906
907                             while (tokenizer.hasMoreTokens()) {
908                                 maxLength = Math.max(maxLength,
909                                         (tokenizer.nextToken().length() - 2));
910                             }
911
912                             rowVal[6] = Integer.toString(maxLength).getBytes();
913                             rowVal[8] = new byte[] { (byte) '0' };
914                         } else if (typeInfo.indexOf(",") != -1) {
915                             // Numeric with decimals
916
String JavaDoc size = typeInfo.substring((typeInfo.indexOf(
917                                         "(") + 1), (typeInfo.indexOf(",")));
918                             String JavaDoc decimals = typeInfo.substring((typeInfo
919                                     .indexOf(",") + 1), (typeInfo.indexOf(")")));
920                             rowVal[6] = s2b(size);
921                             rowVal[8] = s2b(decimals);
922                         } else {
923                             String JavaDoc size = "0";
924
925                             /* If the size is specified with the DDL, use that */
926                             if (typeInfo.indexOf("(") != -1) {
927                                 size = typeInfo.substring((typeInfo.indexOf("(")
928                                         + 1), (typeInfo.indexOf(")")));
929                             } else if (typeInfo.equalsIgnoreCase("tinyint")) {
930                                 size = "1";
931                             } else if (typeInfo.equalsIgnoreCase("smallint")) {
932                                 size = "6";
933                             } else if (typeInfo.equalsIgnoreCase("mediumint")) {
934                                 size = "6";
935                             } else if (typeInfo.equalsIgnoreCase("int")) {
936                                 size = "11";
937                             } else if (typeInfo.equalsIgnoreCase("integer")) {
938                                 size = "11";
939                             } else if (typeInfo.equalsIgnoreCase("bigint")) {
940                                 size = "25";
941                             } else if (typeInfo.equalsIgnoreCase("int24")) {
942                                 size = "25";
943                             } else if (typeInfo.equalsIgnoreCase("real")) {
944                                 size = "12";
945                             } else if (typeInfo.equalsIgnoreCase("float")) {
946                                 size = "12";
947                             } else if (typeInfo.equalsIgnoreCase("decimal")) {
948                                 size = "12";
949                             } else if (typeInfo.equalsIgnoreCase("numeric")) {
950                                 size = "12";
951                             } else if (typeInfo.equalsIgnoreCase("double")) {
952                                 size = "22";
953                             } else if (typeInfo.equalsIgnoreCase("char")) {
954                                 size = "1";
955                             } else if (typeInfo.equalsIgnoreCase("varchar")) {
956                                 size = "255";
957                             } else if (typeInfo.equalsIgnoreCase("date")) {
958                                 size = "10";
959                             } else if (typeInfo.equalsIgnoreCase("time")) {
960                                 size = "8";
961                             } else if (typeInfo.equalsIgnoreCase("timestamp")) {
962                                 size = "19";
963                             } else if (typeInfo.equalsIgnoreCase("datetime")) {
964                                 size = "19";
965                             } else if (typeInfo.equalsIgnoreCase("tinyblob")) {
966                                 size = "255";
967                             } else if (typeInfo.equalsIgnoreCase("blob")) {
968                                 size = "65535";
969                             } else if (typeInfo.equalsIgnoreCase("mediumblob")) {
970                                 size = "16277215";
971                             } else if (typeInfo.equalsIgnoreCase("longblob")) {
972                                 size = Integer.toString(Integer.MAX_VALUE);
973                             } else if (typeInfo.equalsIgnoreCase("tinytext")) {
974                                 size = "255";
975                             } else if (typeInfo.equalsIgnoreCase("text")) {
976                                 size = "65535";
977                             } else if (typeInfo.equalsIgnoreCase("mediumtext")) {
978                                 size = "16277215";
979                             } else if (typeInfo.equalsIgnoreCase("longtext")) {
980                                 size = Integer.toString(Integer.MAX_VALUE);
981                             } else if (typeInfo.equalsIgnoreCase("enum")) {
982                                 size = "255";
983                             } else if (typeInfo.equalsIgnoreCase("set")) {
984                                 size = "255";
985                             }
986
987                             rowVal[6] = size.getBytes();
988                             rowVal[8] = new byte[] { (byte) '0' };
989                         }
990                     } else {
991                         rowVal[8] = new byte[] { (byte) '0' };
992                         rowVal[6] = new byte[] { (byte) '0' };
993                     }
994
995                     rowVal[7] = Integer.toString(MysqlIO.getMaxBuf()).getBytes();
996
997                     // BUFFER_LENGTH
998
rowVal[9] = new byte[] { (byte) '1', (byte) '0' };
999
1000                    // NUM_PREC_RADIX (is this right for char?)
1001
String JavaDoc nullable = results.getString("Null");
1002
1003                    // Nullable?
1004
if (nullable != null) {
1005                        if (nullable.equals("YES")) {
1006                            rowVal[10] = Integer.toString(java.sql.DatabaseMetaData.columnNullable)
1007                                                .getBytes();
1008                            rowVal[17] = new String JavaDoc("YES").getBytes();
1009
1010                            // IS_NULLABLE
1011
} else {
1012                            rowVal[10] = Integer.toString(java.sql.DatabaseMetaData.columnNoNulls)
1013                                                .getBytes();
1014                            rowVal[17] = "NO".getBytes();
1015                        }
1016                    } else {
1017                        rowVal[10] = Integer.toString(java.sql.DatabaseMetaData.columnNoNulls)
1018                                            .getBytes();
1019                        rowVal[17] = "NO".getBytes();
1020                    }
1021
1022                    //
1023
// Doesn't always have this field, depending on version
1024
//
1025
//
1026
// REMARK column
1027
//
1028
try {
1029                        rowVal[11] = results.getBytes("Extra");
1030                    } catch (Exception JavaDoc E) {
1031                        rowVal[11] = new byte[0];
1032                    }
1033
1034                    // COLUMN_DEF
1035
rowVal[12] = results.getBytes("Default");
1036
1037                    rowVal[13] = new byte[] { (byte) '0' }; // SQL_DATA_TYPE
1038
rowVal[14] = new byte[] { (byte) '0' }; // SQL_DATE_TIME_SUB
1039
rowVal[15] = rowVal[6]; // CHAR_OCTET_LENGTH
1040
rowVal[16] = Integer.toString(ordPos++).getBytes();
1041
1042                    // ORDINAL_POSITION
1043
tuples.add(rowVal);
1044                }
1045            } finally {
1046                if (results != null) {
1047                    try {
1048                        results.close();
1049                    } catch (Exception JavaDoc ex) {
1050                        ;
1051                    }
1052
1053                    results = null;
1054                }
1055
1056                if (stmt != null) {
1057                    try {
1058                        stmt.close();
1059                    } catch (Exception JavaDoc ex) {
1060                        ;
1061                    }
1062
1063                    stmt = null;
1064                }
1065            }
1066        }
1067
1068        java.sql.ResultSet JavaDoc results = buildResultSet(fields, tuples);
1069
1070        return results;
1071    }
1072
1073    /**
1074     * JDBC 2.0 Return the connection that produced this metadata object.
1075     *
1076     * @return the connection that produced this metadata object.
1077     *
1078     * @throws SQLException if a database error occurs
1079     */

1080    public java.sql.Connection JavaDoc getConnection() throws SQLException JavaDoc {
1081        return (java.sql.Connection JavaDoc) this.conn;
1082    }
1083
1084    /**
1085     * Get a description of the foreign key columns in the foreign key table
1086     * that reference the primary key columns of the primary key table
1087     * (describe how one table imports another's key.) This should normally
1088     * return a single foreign key/primary key pair (most tables only import a
1089     * foreign key from a table once.) They are ordered by FKTABLE_CAT,
1090     * FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.
1091     *
1092     * <P>
1093     * Each foreign key column description has the following columns:
1094     *
1095     * <OL>
1096     * <li>
1097     * <B>PKTABLE_CAT</B> String => primary key table catalog (may be null)
1098     * </li>
1099     * <li>
1100     * <B>PKTABLE_SCHEM</B> String => primary key table schema (may be null)
1101     * </li>
1102     * <li>
1103     * <B>PKTABLE_NAME</B> String => primary key table name
1104     * </li>
1105     * <li>
1106     * <B>PKCOLUMN_NAME</B> String => primary key column name
1107     * </li>
1108     * <li>
1109     * <B>FKTABLE_CAT</B> String => foreign key table catalog (may be null)
1110     * being exported (may be null)
1111     * </li>
1112     * <li>
1113     * <B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null)
1114     * being exported (may be null)
1115     * </li>
1116     * <li>
1117     * <B>FKTABLE_NAME</B> String => foreign key table name being exported
1118     * </li>
1119     * <li>
1120     * <B>FKCOLUMN_NAME</B> String => foreign key column name being exported
1121     * </li>
1122     * <li>
1123     * <B>KEY_SEQ</B> short => sequence number within foreign key
1124     * </li>
1125     * <li>
1126     * <B>UPDATE_RULE</B> short => What happens to foreign key when primary is
1127     * updated:
1128     *
1129     * <UL>
1130     * <li>
1131     * importedKeyCascade - change imported key to agree with primary key
1132     * update
1133     * </li>
1134     * <li>
1135     * importedKeyRestrict - do not allow update of primary key if it has been
1136     * imported
1137     * </li>
1138     * <li>
1139     * importedKeySetNull - change imported key to NULL if its primary key has
1140     * been updated
1141     * </li>
1142     * </ul>
1143     *
1144     * </li>
1145     * <li>
1146     * <B>DELETE_RULE</B> short => What happens to the foreign key when primary
1147     * is deleted.
1148     *
1149     * <UL>
1150     * <li>
1151     * importedKeyCascade - delete rows that import a deleted key
1152     * </li>
1153     * <li>
1154     * importedKeyRestrict - do not allow delete of primary key if it has been
1155     * imported
1156     * </li>
1157     * <li>
1158     * importedKeySetNull - change imported key to NULL if its primary key has
1159     * been deleted
1160     * </li>
1161     * </ul>
1162     *
1163     * </li>
1164     * <li>
1165     * <B>FK_NAME</B> String => foreign key identifier (may be null)
1166     * </li>
1167     * <li>
1168     * <B>PK_NAME</B> String => primary key identifier (may be null)
1169     * </li>
1170     * </ol>
1171     * </p>
1172     *
1173     * @param primaryCatalog a catalog name; "" retrieves those without a
1174     * catalog
1175     * @param primarySchema a schema name pattern; "" retrieves those without a
1176     * schema
1177     * @param primaryTable a table name
1178     * @param foreignCatalog a catalog name; "" retrieves those without a
1179     * catalog
1180     * @param foreignSchema a schema name pattern; "" retrieves those without a
1181     * schema
1182     * @param foreignTable a table name
1183     *
1184     * @return ResultSet each row is a foreign key column description
1185     *
1186     * @throws java.sql.SQLException if a database access error occurs
1187     */

1188    public java.sql.ResultSet JavaDoc getCrossReference(String JavaDoc primaryCatalog,
1189        String JavaDoc primarySchema, String JavaDoc primaryTable, String JavaDoc foreignCatalog,
1190        String JavaDoc foreignSchema, String JavaDoc foreignTable) throws java.sql.SQLException JavaDoc {
1191        if (Driver.TRACE) {
1192            Object JavaDoc[] args = {
1193                primaryCatalog, primarySchema, primaryTable, foreignCatalog,
1194                foreignSchema, foreignTable
1195            };
1196            Debug.methodCall(this, "getCrossReference", args);
1197        }
1198
1199        if (primaryTable == null) {
1200            throw new java.sql.SQLException JavaDoc("Table not specified.", SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
1201        }
1202
1203        Field[] fields = new Field[14];
1204        fields[0] = new Field("", "PKTABLE_CAT", Types.CHAR, 255);
1205        fields[1] = new Field("", "PKTABLE_SCHEM", Types.CHAR, 0);
1206        fields[2] = new Field("", "PKTABLE_NAME", Types.CHAR, 255);
1207        fields[3] = new Field("", "PKCOLUMN_NAME", Types.CHAR, 32);
1208        fields[4] = new Field("", "FKTABLE_CAT", Types.CHAR, 255);
1209        fields[5] = new Field("", "FKTABLE_SCHEM", Types.CHAR, 0);
1210        fields[6] = new Field("", "FKTABLE_NAME", Types.CHAR, 255);
1211        fields[7] = new Field("", "FKCOLUMN_NAME", Types.CHAR, 32);
1212        fields[8] = new Field("", "KEY_SEQ", Types.SMALLINT, 2);
1213        fields[9] = new Field("", "UPDATE_RULE", Types.SMALLINT, 2);
1214        fields[10] = new Field("", "DELETE_RULE", Types.SMALLINT, 2);
1215        fields[11] = new Field("", "FK_NAME", Types.CHAR, 255);
1216        fields[12] = new Field("", "PK_NAME", Types.CHAR, 0);
1217        fields[13] = new Field("", "DEFERRABILITY", Types.INTEGER, 2);
1218
1219        if (this.conn.getIO().versionMeetsMinimum(3, 23, 0)) {
1220            Statement stmt = null;
1221            ResultSet fkresults = null;
1222
1223            try {
1224                /*
1225                 * Get foreign key information for table
1226                 */

1227                if (this.conn.getIO().versionMeetsMinimum(3, 23, 50)) {
1228                    // we can use 'SHOW CREATE TABLE'
1229
String JavaDoc database = this.database;
1230
1231                    if (foreignCatalog != null) {
1232                        if (!foreignCatalog.equals("")) {
1233                            database = foreignCatalog;
1234                        }
1235                    }
1236
1237                    fkresults = extractForeignKeyFromCreateTable(this.conn,
1238                            this, database, null);
1239                } else {
1240                    String JavaDoc databasePart = "";
1241
1242                    if (foreignCatalog != null) {
1243                        if (!foreignCatalog.equals("")) {
1244                            databasePart = " FROM " + foreignCatalog;
1245                        }
1246                    } else {
1247                        databasePart = " FROM " + this.database;
1248                    }
1249
1250                    stmt = this.conn.createStatement();
1251                    
1252                    if (stmt.getMaxRows() != 0) {
1253                        stmt.setMaxRows(0);
1254                    }
1255                    
1256                    fkresults = stmt.executeQuery("show table status "
1257                            + databasePart);
1258                }
1259
1260                String JavaDoc foreignTableWithCase = getTableNameWithCase(foreignTable);
1261                String JavaDoc primaryTableWithCase = getTableNameWithCase(primaryTable);
1262
1263                /*
1264                * Parse imported foreign key information
1265                */

1266                ArrayList JavaDoc tuples = new ArrayList JavaDoc();
1267                String JavaDoc dummy;
1268
1269                while (fkresults.next()) {
1270                    String JavaDoc tableType = fkresults.getString("Type");
1271
1272                    if ((tableType != null)
1273                            && (tableType.equalsIgnoreCase("innodb")
1274                            || tableType.equalsIgnoreCase(SUPPORTS_FK))) {
1275                        String JavaDoc comment = fkresults.getString("Comment").trim();
1276
1277                        if (comment != null) {
1278                            StringTokenizer JavaDoc commentTokens = new StringTokenizer JavaDoc(comment,
1279                                    ";", false);
1280
1281                            if (commentTokens.hasMoreTokens()) {
1282                                dummy = commentTokens.nextToken();
1283
1284                                // Skip InnoDB comment
1285
}
1286
1287                            while (commentTokens.hasMoreTokens()) {
1288                                String JavaDoc keys = commentTokens.nextToken();
1289
1290                                // simple-columned keys: (m) REFER airline/tt(a)
1291
// multi-columned keys : (m n) REFER airline/vv(a b)
1292
int firstLeftParenIndex = keys.indexOf('(');
1293                                int firstRightParenIndex = keys.indexOf(')');
1294
1295                                String JavaDoc constraintName = keys.substring(0,
1296                                        firstLeftParenIndex);
1297
1298                                String JavaDoc referencingColumns = keys.substring(firstLeftParenIndex
1299                                        + 1, firstRightParenIndex);
1300                                StringTokenizer JavaDoc referencingColumnsTokenizer = new StringTokenizer JavaDoc(referencingColumns,
1301                                        ", ");
1302                                int secondLeftParenIndex = keys.indexOf('(',
1303                                        firstRightParenIndex + 1);
1304                                int secondRightParenIndex = keys.indexOf(')',
1305                                        firstRightParenIndex + 1);
1306                                String JavaDoc referencedColumns = keys.substring(secondLeftParenIndex
1307                                        + 1, secondRightParenIndex);
1308                                StringTokenizer JavaDoc referencedColumnsTokenizer = new StringTokenizer JavaDoc(referencedColumns,
1309                                        ", ");
1310                                int slashIndex = keys.indexOf('/');
1311                                String JavaDoc referencedTable = keys.substring(slashIndex
1312                                        + 1, secondLeftParenIndex);
1313                                int keySeq = 0;
1314
1315                                while (referencingColumnsTokenizer
1316                                        .hasMoreTokens()) {
1317                                    String JavaDoc referencingColumn = referencingColumnsTokenizer
1318                                        .nextToken();
1319
1320                                    // one tuple for each table between parenthesis
1321
byte[][] tuple = new byte[14][];
1322                                    tuple[4] = ((foreignCatalog == null) ? null
1323                                                                         : s2b(foreignCatalog));
1324                                    tuple[5] = ((foreignSchema == null) ? null
1325                                                                        : s2b(foreignSchema));
1326                                    dummy = fkresults.getString("Name"); // FKTABLE_NAME
1327

1328                                    if (dummy.compareTo(foreignTableWithCase) != 0) {
1329                                        continue;
1330                                    } else {
1331                                        tuple[6] = s2b(dummy);
1332                                    }
1333
1334                                    tuple[7] = s2b(referencingColumn); // FKCOLUMN_NAME
1335
tuple[0] = ((primaryCatalog == null) ? null
1336                                                                         : s2b(primaryCatalog));
1337                                    tuple[1] = ((primarySchema == null) ? null
1338                                                                        : s2b(primarySchema));
1339
1340                                    // Skip foreign key if it doesn't refer to the right table
1341
if (referencedTable.compareTo(
1342                                                primaryTableWithCase) != 0) {
1343                                        continue;
1344                                    }
1345
1346                                    tuple[2] = s2b(referencedTable); // PKTABLE_NAME
1347
tuple[3] = s2b(referencedColumnsTokenizer
1348                                            .nextToken()); // PKCOLUMN_NAME
1349
tuple[8] = Integer.toString(keySeq)
1350                                                      .getBytes(); // KEY_SEQ
1351

1352                                    int[] actions = getForeignKeyActions(keys);
1353
1354                                    tuple[9] = Integer.toString(actions[1])
1355                                                      .getBytes();
1356                                    tuple[10] = Integer.toString(actions[0])
1357                                                       .getBytes();
1358                                    tuple[11] = s2b(constraintName); // FK_NAME
1359
tuple[12] = null; // PK_NAME
1360
tuple[13] = Integer.toString(java.sql.DatabaseMetaData.importedKeyNotDeferrable)
1361                                                       .getBytes();
1362                                    tuples.add(tuple);
1363                                    keySeq++;
1364                                }
1365                            }
1366                        }
1367                    }
1368                }
1369
1370                if (Driver.TRACE) {
1371                    StringBuffer JavaDoc rows = new StringBuffer JavaDoc();
1372                    rows.append("\n");
1373
1374                    for (int i = 0; i < tuples.size(); i++) {
1375                        byte[][] b = (byte[][]) tuples.get(i);
1376                        rows.append("[Row] ");
1377
1378                        boolean firstTime = true;
1379
1380                        for (int j = 0; j < b.length; j++) {
1381                            if (!firstTime) {
1382                                rows.append(", ");
1383                            } else {
1384                                firstTime = false;
1385                            }
1386
1387                            if (b[j] == null) {
1388                                rows.append("null");
1389                            } else {
1390                                rows.append(new String JavaDoc(b[j]));
1391                            }
1392                        }
1393
1394                        rows.append("\n");
1395                    }
1396
1397                    Debug.returnValue(this, "getCrossReference", rows.toString());
1398                }
1399
1400                return buildResultSet(fields, tuples);
1401            } finally {
1402                if (fkresults != null) {
1403                    try {
1404                        fkresults.close();
1405                    } catch (Exception JavaDoc sqlEx) {
1406                        AssertionFailedException.shouldNotHappen(sqlEx);
1407                    }
1408
1409                    fkresults = null;
1410                }
1411
1412                if (stmt != null) {
1413                    try {
1414                        stmt.close();
1415                    } catch (Exception JavaDoc ex) {
1416                        ;
1417                    }
1418
1419                    stmt = null;
1420                }
1421            }
1422        } else {
1423            return buildResultSet(fields, new ArrayList JavaDoc());
1424        }
1425    }
1426
1427    /**
1428     * @see DatabaseMetaData#getDatabaseMajorVersion()
1429     */

1430    public int getDatabaseMajorVersion() throws SQLException JavaDoc {
1431        return this.conn.getServerMajorVersion();
1432    }
1433
1434    /**
1435     * @see DatabaseMetaData#getDatabaseMinorVersion()
1436     */

1437    public int getDatabaseMinorVersion() throws SQLException JavaDoc {
1438        return this.conn.getServerMinorVersion();
1439    }
1440
1441    /**
1442     * What's the name of this database product?
1443     *
1444     * @return database product name
1445     *
1446     * @throws java.sql.SQLException DOCUMENT ME!
1447     */

1448    public String JavaDoc getDatabaseProductName() throws java.sql.SQLException JavaDoc {
1449        return "MySQL";
1450    }
1451
1452    /**
1453     * What's the version of this database product?
1454     *
1455     * @return database version
1456     *
1457     * @throws java.sql.SQLException DOCUMENT ME!
1458     */

1459    public String JavaDoc getDatabaseProductVersion() throws java.sql.SQLException JavaDoc {
1460        return this.conn.getServerVersion();
1461    }
1462
1463    //----------------------------------------------------------------------
1464

1465    /**
1466     * What's the database's default transaction isolation level? The values
1467     * are defined in java.sql.Connection.
1468     *
1469     * @return the default isolation level
1470     *
1471     * @throws java.sql.SQLException if a database access error occurs
1472     *
1473     * @see Connection
1474     */

1475    public int getDefaultTransactionIsolation() throws java.sql.SQLException JavaDoc {
1476        if (this.conn.supportsIsolationLevel()) {
1477            return java.sql.Connection.TRANSACTION_READ_COMMITTED;
1478        } else {
1479            return java.sql.Connection.TRANSACTION_NONE;
1480        }
1481    }
1482
1483    /**
1484     * What's this JDBC driver's major version number?
1485     *
1486     * @return JDBC driver major version
1487     */

1488    public int getDriverMajorVersion() {
1489        return Driver.getMajorVersionInternal();
1490    }
1491
1492    /**
1493     * What's this JDBC driver's minor version number?
1494     *
1495     * @return JDBC driver minor version number
1496     */

1497    public int getDriverMinorVersion() {
1498        return Driver.getMinorVersionInternal();
1499    }
1500
1501    /**
1502     * What's the name of this JDBC driver?
1503     *
1504     * @return JDBC driver name
1505     *
1506     * @throws java.sql.SQLException DOCUMENT ME!
1507     */

1508    public String JavaDoc getDriverName() throws java.sql.SQLException JavaDoc {
1509        return "MySQL-AB JDBC Driver";
1510    }
1511
1512    /**
1513     * What's the version of this JDBC driver?
1514     *
1515     * @return JDBC driver version
1516     *
1517     * @throws java.sql.SQLException DOCUMENT ME!
1518     */

1519    public String JavaDoc getDriverVersion() throws java.sql.SQLException JavaDoc {
1520        return "mysql-connector-java-3.0.11-stable ( $Date: 2004/02/04 02:47:36 $, $Revision: 1.27.2.34 $ )";
1521    }
1522
1523    /**
1524     * Get a description of a foreign key columns that reference a table's
1525     * primary key columns (the foreign keys exported by a table). They are
1526     * ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.
1527     *
1528     * <P>
1529     * Each foreign key column description has the following columns:
1530     *
1531     * <OL>
1532     * <li>
1533     * <B>PKTABLE_CAT</B> String => primary key table catalog (may be null)
1534     * </li>
1535     * <li>
1536     * <B>PKTABLE_SCHEM</B> String => primary key table schema (may be null)
1537     * </li>
1538     * <li>
1539     * <B>PKTABLE_NAME</B> String => primary key table name
1540     * </li>
1541     * <li>
1542     * <B>PKCOLUMN_NAME</B> String => primary key column name
1543     * </li>
1544     * <li>
1545     * <B>FKTABLE_CAT</B> String => foreign key table catalog (may be null)
1546     * being exported (may be null)
1547     * </li>
1548     * <li>
1549     * <B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null)
1550     * being exported (may be null)
1551     * </li>
1552     * <li>
1553     * <B>FKTABLE_NAME</B> String => foreign key table name being exported
1554     * </li>
1555     * <li>
1556     * <B>FKCOLUMN_NAME</B> String => foreign key column name being exported
1557     * </li>
1558     * <li>
1559     * <B>KEY_SEQ</B> short => sequence number within foreign key
1560     * </li>
1561     * <li>
1562     * <B>UPDATE_RULE</B> short => What happens to foreign key when primary is
1563     * updated:
1564     *
1565     * <UL>
1566     * <li>
1567     * importedKeyCascade - change imported key to agree with primary key
1568     * update
1569     * </li>
1570     * <li>
1571     * importedKeyRestrict - do not allow update of primary key if it has been
1572     * imported
1573     * </li>
1574     * <li>
1575     * importedKeySetNull - change imported key to NULL if its primary key has
1576     * been updated
1577     * </li>
1578     * </ul>
1579     *
1580     * </li>
1581     * <li>
1582     * <B>DELETE_RULE</B> short => What happens to the foreign key when primary
1583     * is deleted.
1584     *
1585     * <UL>
1586     * <li>
1587     * importedKeyCascade - delete rows that import a deleted key
1588     * </li>
1589     * <li>
1590     * importedKeyRestrict - do not allow delete of primary key if it has been
1591     * imported
1592     * </li>
1593     * <li>
1594     * importedKeySetNull - change imported key to NULL if its primary key has
1595     * been deleted
1596     * </li>
1597     * </ul>
1598     *
1599     * </li>
1600     * <li>
1601     * <B>FK_NAME</B> String => foreign key identifier (may be null)
1602     * </li>
1603     * <li>
1604     * <B>PK_NAME</B> String => primary key identifier (may be null)
1605     * </li>
1606     * </ol>
1607     * </p>
1608     *
1609     * @param catalog a catalog name; "" retrieves those without a catalog
1610     * @param schema a schema name pattern; "" retrieves those without a schema
1611     * @param table a table name
1612     *
1613     * @return ResultSet each row is a foreign key column description
1614     *
1615     * @throws java.sql.SQLException if a database access error occurs
1616     *
1617     * @see #getImportedKeys
1618     */

1619    public java.sql.ResultSet JavaDoc getExportedKeys(String JavaDoc catalog, String JavaDoc schema,
1620        String JavaDoc table) throws java.sql.SQLException JavaDoc {
1621        if (Driver.TRACE) {
1622            Object JavaDoc[] args = { catalog, schema, table };
1623            Debug.methodCall(this, "getExportedKeys", args);
1624        }
1625
1626        if (table == null) {
1627            throw new java.sql.SQLException JavaDoc("Table not specified.", SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
1628        }
1629
1630        Field[] fields = new Field[14];
1631        fields[0] = new Field("", "PKTABLE_CAT", Types.CHAR, 255);
1632        fields[1] = new Field("", "PKTABLE_SCHEM", Types.CHAR, 0);
1633        fields[2] = new Field("", "PKTABLE_NAME", Types.CHAR, 255);
1634        fields[3] = new Field("", "PKCOLUMN_NAME", Types.CHAR, 32);
1635        fields[4] = new Field("", "FKTABLE_CAT", Types.CHAR, 255);
1636        fields[5] = new Field("", "FKTABLE_SCHEM", Types.CHAR, 0);
1637        fields[6] = new Field("", "FKTABLE_NAME", Types.CHAR, 255);
1638        fields[7] = new Field("", "FKCOLUMN_NAME", Types.CHAR, 32);
1639        fields[8] = new Field("", "KEY_SEQ", Types.SMALLINT, 2);
1640        fields[9] = new Field("", "UPDATE_RULE", Types.SMALLINT, 2);
1641        fields[10] = new Field("", "DELETE_RULE", Types.SMALLINT, 2);
1642        fields[11] = new Field("", "FK_NAME", Types.CHAR, 255);
1643        fields[12] = new Field("", "PK_NAME", Types.CHAR, 0);
1644        fields[13] = new Field("", "DEFERRABILITY", Types.INTEGER, 2);
1645
1646        if (this.conn.getIO().versionMeetsMinimum(3, 23, 0)) {
1647            Statement stmt = null;
1648            ResultSet fkresults = null;
1649
1650            try {
1651                /*
1652                 * Get foreign key information for table
1653                 */

1654                if (this.conn.getIO().versionMeetsMinimum(3, 23, 50)) {
1655                    // we can use 'SHOW CREATE TABLE'
1656
String JavaDoc database = this.database;
1657
1658                    if (catalog != null) {
1659                        if (!catalog.equals("")) {
1660                            database = catalog;
1661                        }
1662                    }
1663
1664                    fkresults = extractForeignKeyFromCreateTable(this.conn,
1665                            this, database, null);
1666                } else {
1667                    String JavaDoc databasePart = "";
1668
1669                    if (catalog != null) {
1670                        if (!catalog.equals("")) {
1671                            databasePart = " FROM " + catalog;
1672                        }
1673                    } else {
1674                        databasePart = " FROM " + this.database;
1675                    }
1676
1677                    stmt = this.conn.createStatement();
1678                    
1679                    if (stmt.getMaxRows() != 0) {
1680                        stmt.setMaxRows(0);
1681                    }
1682                    
1683                    fkresults = stmt.executeQuery("show table status "
1684                            + databasePart);
1685                }
1686
1687                // lower-case table name might be turned on
1688
String JavaDoc tableNameWithCase = getTableNameWithCase(table);
1689
1690                /*
1691                * Parse imported foreign key information
1692                */

1693                ArrayList JavaDoc tuples = new ArrayList JavaDoc();
1694
1695                while (fkresults.next()) {
1696                    String JavaDoc tableType = fkresults.getString("Type");
1697
1698                    if ((tableType != null)
1699                            && (tableType.equalsIgnoreCase("innodb")
1700                            || tableType.equalsIgnoreCase(SUPPORTS_FK))) {
1701                        String JavaDoc comment = fkresults.getString("Comment").trim();
1702
1703                        if (comment != null) {
1704                            StringTokenizer JavaDoc commentTokens = new StringTokenizer JavaDoc(comment,
1705                                    ";", false);
1706
1707                            if (commentTokens.hasMoreTokens()) {
1708                                commentTokens.nextToken(); // Skip InnoDB comment
1709

1710                                while (commentTokens.hasMoreTokens()) {
1711                                    String JavaDoc keys = commentTokens.nextToken();
1712                                    getExportKeyResults(catalog,
1713                                        tableNameWithCase, keys, tuples,
1714                                        fkresults.getString("Name"));
1715                                }
1716                            }
1717                        }
1718                    }
1719                }
1720
1721                if (Driver.TRACE) {
1722                    StringBuffer JavaDoc rows = new StringBuffer JavaDoc();
1723                    rows.append("\n");
1724
1725                    for (int i = 0; i < tuples.size(); i++) {
1726                        byte[][] b = (byte[][]) tuples.get(i);
1727                        rows.append("[Row] ");
1728
1729                        boolean firstTime = true;
1730
1731                        for (int j = 0; j < b.length; j++) {
1732                            if (!firstTime) {
1733                                rows.append(", ");
1734                            } else {
1735                                firstTime = false;
1736                            }
1737
1738                            if (b[j] == null) {
1739                                rows.append("null");
1740                            } else {
1741                                rows.append(new String JavaDoc(b[j]));
1742                            }
1743                        }
1744
1745                        rows.append("\n");
1746                    }
1747
1748                    Debug.returnValue(this, "getExportedKeys", rows.toString());
1749                }
1750
1751                return buildResultSet(fields, tuples);
1752            } finally {
1753                if (fkresults != null) {
1754                    try {
1755                        fkresults.close();
1756                    } catch (SQLException JavaDoc sqlEx) {
1757                        AssertionFailedException.shouldNotHappen(sqlEx);
1758                    }
1759
1760                    fkresults = null;
1761                }
1762
1763                if (stmt != null) {
1764                    try {
1765                        stmt.close();
1766                    } catch (Exception JavaDoc ex) {
1767                        AssertionFailedException.shouldNotHappen(ex);
1768                    }
1769
1770                    stmt = null;
1771                }
1772            }
1773        } else {
1774            return buildResultSet(fields, new ArrayList JavaDoc());
1775        }
1776    }
1777
1778    /**
1779     * Get all the "extra" characters that can be used in unquoted identifier
1780     * names (those beyond a-z, 0-9 and _).
1781     *
1782     * @return the string containing the extra characters
1783     *
1784     * @throws java.sql.SQLException DOCUMENT ME!
1785     */

1786    public String JavaDoc getExtraNameCharacters() throws java.sql.SQLException JavaDoc {
1787        return "#@";
1788    }
1789
1790    /**
1791     * What's the string used to quote SQL identifiers? This returns a space "
1792     * " if identifier quoting isn't supported. A JDBC compliant driver always
1793     * uses a double quote character.
1794     *
1795     * @return the quoting string
1796     *
1797     * @throws java.sql.SQLException DOCUMENT ME!
1798     */

1799    public String JavaDoc getIdentifierQuoteString() throws java.sql.SQLException JavaDoc {
1800        if (this.conn.supportsQuotedIdentifiers()) {
1801            if (!this.conn.useAnsiQuotedIdentifiers()) {
1802                return "`";
1803            } else {
1804                return "\"";
1805            }
1806        } else {
1807            return " ";
1808        }
1809    }
1810
1811    /**
1812     * Get a description of the primary key columns that are referenced by a
1813     * table's foreign key columns (the primary keys imported by a table).
1814     * They are ordered by PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME, and
1815     * KEY_SEQ.
1816     *
1817     * <P>
1818     * Each primary key column description has the following columns:
1819     *
1820     * <OL>
1821     * <li>
1822     * <B>PKTABLE_CAT</B> String => primary key table catalog being imported
1823     * (may be null)
1824     * </li>
1825     * <li>
1826     * <B>PKTABLE_SCHEM</B> String => primary key table schema being imported
1827     * (may be null)
1828     * </li>
1829     * <li>
1830     * <B>PKTABLE_NAME</B> String => primary key table name being imported
1831     * </li>
1832     * <li>
1833     * <B>PKCOLUMN_NAME</B> String => primary key column name being imported
1834     * </li>
1835     * <li>
1836     * <B>FKTABLE_CAT</B> String => foreign key table catalog (may be null)
1837     * </li>
1838     * <li>
1839     * <B>FKTABLE_SCHEM</B> String => foreign key table schema (may be null)
1840     * </li>
1841     * <li>
1842     * <B>FKTABLE_NAME</B> String => foreign key table name
1843     * </li>
1844     * <li>
1845     * <B>FKCOLUMN_NAME</B> String => foreign key column name
1846     * </li>
1847     * <li>
1848     * <B>KEY_SEQ</B> short => sequence number within foreign key
1849     * </li>
1850     * <li>
1851     * <B>UPDATE_RULE</B> short => What happens to foreign key when primary is
1852     * updated:
1853     *
1854     * <UL>
1855     * <li>
1856     * importedKeyCascade - change imported key to agree with primary key
1857     * update
1858     * </li>
1859     * <li>
1860     * importedKeyRestrict - do not allow update of primary key if it has been
1861     * imported
1862     * </li>
1863     * <li>
1864     * importedKeySetNull - change imported key to NULL if its primary key has
1865     * been updated
1866     * </li>
1867     * </ul>
1868     *
1869     * </li>
1870     * <li>
1871     * <B>DELETE_RULE</B> short => What happens to the foreign key when primary
1872     * is deleted.
1873     *
1874     * <UL>
1875     * <li>
1876     * importedKeyCascade - delete rows that import a deleted key
1877     * </li>
1878     * <li>
1879     * importedKeyRestrict - do not allow delete of primary key if it has been
1880     * imported
1881     * </li>
1882     * <li>
1883     * importedKeySetNull - change imported key to NULL if its primary key has
1884     * been deleted
1885     * </li>
1886     * </ul>
1887     *
1888     * </li>
1889     * <li>
1890     * <B>FK_NAME</B> String => foreign key name (may be null)
1891     * </li>
1892     * <li>
1893     * <B>PK_NAME</B> String => primary key name (may be null)
1894     * </li>
1895     * </ol>
1896     * </p>
1897     *
1898     * @param catalog a catalog name; "" retrieves those without a catalog
1899     * @param schema a schema name pattern; "" retrieves those without a schema
1900     * @param table a table name
1901     *
1902     * @return ResultSet each row is a primary key column description
1903     *
1904     * @throws java.sql.SQLException if a database access error occurs
1905     *
1906     * @see #getExportedKeys
1907     */

1908    public java.sql.ResultSet JavaDoc getImportedKeys(String JavaDoc catalog, String JavaDoc schema,
1909        String JavaDoc table) throws java.sql.SQLException JavaDoc {
1910        if (Driver.TRACE) {
1911            Object JavaDoc[] args = { catalog, schema, table };
1912            Debug.methodCall(this, "getImportedKeys", args);
1913        }
1914
1915        if (table == null) {
1916            throw new java.sql.SQLException JavaDoc("Table not specified.", SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
1917        }
1918
1919        Field[] fields = new Field[14];
1920        fields[0] = new Field("", "PKTABLE_CAT", Types.CHAR, 255);
1921        fields[1] = new Field("", "PKTABLE_SCHEM", Types.CHAR, 0);
1922        fields[2] = new Field("", "PKTABLE_NAME", Types.CHAR, 255);
1923        fields[3] = new Field("", "PKCOLUMN_NAME", Types.CHAR, 32);
1924        fields[4] = new Field("", "FKTABLE_CAT", Types.CHAR, 255);
1925        fields[5] = new Field("", "FKTABLE_SCHEM", Types.CHAR, 0);
1926        fields[6] = new Field("", "FKTABLE_NAME", Types.CHAR, 255);
1927        fields[7] = new Field("", "FKCOLUMN_NAME", Types.CHAR, 32);
1928        fields[8] = new Field("", "KEY_SEQ", Types.SMALLINT, 2);
1929        fields[9] = new Field("", "UPDATE_RULE", Types.SMALLINT, 2);
1930        fields[10] = new Field("", "DELETE_RULE", Types.SMALLINT, 2);
1931        fields[11] = new Field("", "FK_NAME", Types.CHAR, 255);
1932        fields[12] = new Field("", "PK_NAME", Types.CHAR, 0);
1933        fields[13] = new Field("", "DEFERRABILITY", Types.INTEGER, 2);
1934
1935        if (this.conn.getIO().versionMeetsMinimum(3, 23, 0)) {
1936            Statement stmt = null;
1937            ResultSet fkresults = null;
1938
1939            try {
1940                /*
1941                 * Get foreign key information for table
1942                 */

1943                if (this.conn.getIO().versionMeetsMinimum(3, 23, 50)) {
1944                    // we can use 'SHOW CREATE TABLE'
1945
String JavaDoc database = this.database;
1946
1947                    if (catalog != null) {
1948                        if (!catalog.equals("")) {
1949                            database = catalog;
1950                        }
1951                    }
1952
1953                    fkresults = extractForeignKeyFromCreateTable(this.conn,
1954                            this, database, table);
1955                } else {
1956                    String JavaDoc databasePart = "";
1957
1958                    if (catalog != null) {
1959                        if (!catalog.equals("")) {
1960                            databasePart = " FROM " + catalog;
1961                        }
1962                    } else {
1963                        databasePart = " FROM " + this.database;
1964                    }
1965
1966                    stmt = this.conn.createStatement();
1967                    
1968                    if (stmt.getMaxRows() != 0) {
1969                        stmt.setMaxRows(0);
1970                    }
1971                    
1972                    fkresults = stmt.executeQuery("show table status "
1973                            + databasePart + " like '" + table + "'");
1974                }
1975
1976                /*
1977                * Parse imported foreign key information
1978                */

1979                ArrayList JavaDoc tuples = new ArrayList JavaDoc();
1980
1981                while (fkresults.next()) {
1982                    String JavaDoc tableType = fkresults.getString("Type");
1983
1984                    if ((tableType != null)
1985                            && (tableType.equalsIgnoreCase("innodb")
1986                            || tableType.equalsIgnoreCase(SUPPORTS_FK))) {
1987                        String JavaDoc comment = fkresults.getString("Comment").trim();
1988
1989                        if (comment != null) {
1990                            StringTokenizer JavaDoc commentTokens = new StringTokenizer JavaDoc(comment,
1991                                    ";", false);
1992
1993                            if (commentTokens.hasMoreTokens()) {
1994                                commentTokens.nextToken(); // Skip InnoDB comment
1995

1996                                while (commentTokens.hasMoreTokens()) {
1997                                    String JavaDoc keys = commentTokens.nextToken();
1998                                    getImportKeyResults(catalog, table, keys,
1999                                        tuples);
2000                                }
2001                            }
2002                        }
2003                    }
2004                }
2005
2006                if (Driver.TRACE) {
2007                    StringBuffer JavaDoc rows = new StringBuffer JavaDoc();
2008                    rows.append("\n");
2009
2010                    for (int i = 0; i < tuples.size(); i++) {
2011                        byte[][] b = (byte[][]) tuples.get(i);
2012                        rows.append("[Row] ");
2013
2014                        boolean firstTime = true;
2015
2016                        for (int j = 0; j < b.length; j++) {
2017                            if (!firstTime) {
2018                                rows.append(", ");
2019                            } else {
2020                                firstTime = false;
2021                            }
2022
2023                            if (b[j] == null) {
2024                                rows.append("null");
2025                            } else {
2026                                rows.append(new String JavaDoc(b[j]));
2027                            }
2028                        }
2029
2030                        rows.append("\n");
2031                    }
2032
2033                    Debug.returnValue(this, "getImportedKeys", rows.toString());
2034                }
2035
2036                return buildResultSet(fields, tuples);
2037            } finally {
2038                if (fkresults != null) {
2039                    try {
2040                        fkresults.close();
2041                    } catch (SQLException JavaDoc sqlEx) {
2042                        AssertionFailedException.shouldNotHappen(sqlEx);
2043                    }
2044
2045                    fkresults = null;
2046                }
2047
2048                if (stmt != null) {
2049                    try {
2050                        stmt.close();
2051                    } catch (Exception JavaDoc ex) {
2052                        AssertionFailedException.shouldNotHappen(ex);
2053                    }
2054
2055                    stmt = null;
2056                }
2057            }
2058        } else {
2059            return buildResultSet(fields, new ArrayList JavaDoc());
2060        }
2061    }
2062
2063    /**
2064     * Get a description of a table's indices and statistics. They are ordered
2065     * by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.
2066     *
2067     * <P>
2068     * Each index column description has the following columns:
2069     *
2070     * <OL>
2071     * <li>
2072     * <B>TABLE_CAT</B> String => table catalog (may be null)
2073     * </li>
2074     * <li>
2075     * <B>TABLE_SCHEM</B> String => table schema (may be null)
2076     * </li>
2077     * <li>
2078     * <B>TABLE_NAME</B> String => table name
2079     * </li>
2080     * <li>
2081     * <B>NON_UNIQUE</B> boolean => Can index values be non-unique? false when
2082     * TYPE is tableIndexStatistic
2083     * </li>
2084     * <li>
2085     * <B>INDEX_QUALIFIER</B> String => index catalog (may be null); null when
2086     * TYPE is tableIndexStatistic
2087     * </li>
2088     * <li>
2089     * <B>INDEX_NAME</B> String => index name; null when TYPE is
2090     * tableIndexStatistic
2091     * </li>
2092     * <li>
2093     * <B>TYPE</B> short => index type:
2094     *
2095     * <UL>
2096     * <li>
2097     * tableIndexStatistic - this identifies table statistics that are returned
2098     * in conjuction with a table's index descriptions
2099     * </li>
2100     * <li>
2101     * tableIndexClustered - this is a clustered index
2102     * </li>
2103     * <li>
2104     * tableIndexHashed - this is a hashed index
2105     * </li>
2106     * <li>
2107     * tableIndexOther - this is some other style of index
2108     * </li>
2109     * </ul>
2110     *
2111     * </li>
2112     * <li>
2113     * <B>ORDINAL_POSITION</B> short => column sequence number within index;
2114     * zero when TYPE is tableIndexStatistic
2115     * </li>
2116     * <li>
2117     * <B>COLUMN_NAME</B> String => column name; null when TYPE is
2118     * tableIndexStatistic
2119     * </li>
2120     * <li>
2121     * <B>ASC_OR_DESC</B> String => column sort sequence, "A" => ascending, "D"
2122     * => descending, may be null if sort sequence is not supported; null when
2123     * TYPE is tableIndexStatistic
2124     * </li>
2125     * <li>
2126     * <B>CARDINALITY</B> int => When TYPE is tableIndexStatisic then this is
2127     * the number of rows in the table; otherwise it is the number of unique
2128     * values in the index.
2129     * </li>
2130     * <li>
2131     * <B>PAGES</B> int => When TYPE is tableIndexStatisic then this is the
2132     * number of pages used for the table, otherwise it is the number of pages
2133     * used for the current index.
2134     * </li>
2135     * <li>
2136     * <B>FILTER_CONDITION</B> String => Filter condition, if any. (may be
2137     * null)
2138     * </li>
2139     * </ol>
2140     * </p>
2141     *
2142     * @param catalog a catalog name; "" retrieves those without a catalog
2143     * @param schema a schema name pattern; "" retrieves those without a schema
2144     * @param table a table name
2145     * @param unique when true, return only indices for unique values; when
2146     * false, return indices regardless of whether unique or not
2147     * @param approximate when true, result is allowed to reflect approximate
2148     * or out of data values; when false, results are requested to be
2149     * accurate
2150     *
2151     * @return ResultSet each row is an index column description
2152     *
2153     * @throws java.sql.SQLException DOCUMENT ME!
2154     */

2155    public java.sql.ResultSet JavaDoc getIndexInfo(String JavaDoc catalog, String JavaDoc schema,
2156        String JavaDoc table, boolean unique, boolean approximate)
2157        throws java.sql.SQLException JavaDoc {
2158        /*
2159         * MySQL stores index information in the following fields:
2160         *
2161         * Table
2162         * Non_unique
2163         * Key_name
2164         * Seq_in_index
2165         * Column_name
2166         * Collation
2167         * Cardinality
2168         * Sub_part
2169         */

2170        String JavaDoc databasePart = "";
2171
2172        if (catalog != null) {
2173            if (!catalog.equals("")) {
2174                databasePart = " FROM " + this.quotedId + catalog
2175                    + this.quotedId;
2176            }
2177        } else {
2178            databasePart = " FROM " + this.quotedId + this.database
2179                + this.quotedId;
2180        }
2181
2182        Statement stmt = null;
2183        ResultSet results = null;
2184
2185        try {
2186            stmt = this.conn.createStatement();
2187            
2188            if (stmt.getMaxRows() != 0) {
2189                stmt.setMaxRows(0);
2190            }
2191
2192            StringBuffer JavaDoc queryBuf = new StringBuffer JavaDoc("SHOW INDEX FROM ");
2193            queryBuf.append(this.quotedId);
2194            queryBuf.append(table);
2195            queryBuf.append(this.quotedId);
2196            queryBuf.append(databasePart);
2197
2198            results = stmt.executeQuery(queryBuf.toString());
2199
2200            Field[] fields = new Field[13];
2201            fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 255);
2202            fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 0);
2203            fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 255);
2204            fields[3] = new Field("", "NON_UNIQUE", Types.CHAR, 3);
2205            fields[4] = new Field("", "INDEX_QUALIFIER", Types.CHAR, 1);
2206            fields[5] = new Field("", "INDEX_NAME", Types.CHAR, 32);
2207            fields[6] = new Field("", "TYPE", Types.CHAR, 32);
2208            fields[7] = new Field("", "ORDINAL_POSITION", Types.SMALLINT, 5);
2209            fields[8] = new Field("", "COLUMN_NAME", Types.CHAR, 32);
2210            fields[9] = new Field("", "ASC_OR_DESC", Types.CHAR, 1);
2211            fields[10] = new Field("", "CARDINALITY", Types.INTEGER, 10);
2212            fields[11] = new Field("", "PAGES", Types.INTEGER, 10);
2213            fields[12] = new Field("", "FILTER_CONDITION", Types.CHAR, 32);
2214
2215            byte[] connectionCatalogAsBytes;
2216
2217            if (catalog == null) {
2218                connectionCatalogAsBytes = s2b(this.conn.getCatalog());
2219            } else {
2220                connectionCatalogAsBytes = s2b(catalog);
2221            }
2222
2223            ArrayList JavaDoc rows = new ArrayList JavaDoc();
2224
2225            while (results.next()) {
2226                byte[][] row = new byte[14][];
2227                row[0] = connectionCatalogAsBytes;
2228                row[1] = null;
2229                row[2] = results.getBytes("Table");
2230                row[3] = ((results.getInt("Non_unique") != 0) ? s2b("true")
2231                                                              : s2b("false"));
2232                row[4] = new byte[0];
2233                row[5] = results.getBytes("Key_name");
2234                row[6] = Integer.toString(java.sql.DatabaseMetaData.tableIndexOther)
2235                                .getBytes();
2236                row[7] = results.getBytes("Seq_in_index");
2237                row[8] = results.getBytes("Column_name");
2238                row[9] = results.getBytes("Collation");
2239                row[10] = results.getBytes("Cardinality");
2240                row[11] = s2b("0");
2241                row[12] = null;
2242                rows.add(row);
2243            }
2244
2245            java.sql.ResultSet JavaDoc indexInfo = buildResultSet(fields, rows);
2246
2247            return indexInfo;
2248        } finally {
2249            if (results != null) {
2250                try {
2251                    results.close();
2252                } catch (Exception JavaDoc ex) {
2253                    ;
2254                }
2255
2256                results = null;
2257            }
2258
2259            if (stmt != null) {
2260                try {
2261                    stmt.close();
2262                } catch (Exception JavaDoc ex) {
2263                    ;
2264                }
2265
2266                stmt = null;
2267            }
2268        }
2269    }
2270
2271    /**
2272     * @see DatabaseMetaData#getJDBCMajorVersion()
2273     */

2274    public int getJDBCMajorVersion() throws SQLException JavaDoc {
2275        return 3;
2276    }
2277
2278    /**
2279     * @see DatabaseMetaData#getJDBCMinorVersion()
2280     */

2281    public int getJDBCMinorVersion() throws SQLException JavaDoc {
2282        return 0;
2283    }
2284
2285    //----------------------------------------------------------------------
2286
// The following group of methods exposes various limitations
2287
// based on the target database with the current driver.
2288
// Unless otherwise specified, a result of zero means there is no
2289
// limit, or the limit is not known.
2290

2291    /**
2292     * How many hex characters can you have in an inline binary literal?
2293     *
2294     * @return max literal length
2295     *
2296     * @throws java.sql.SQLException DOCUMENT ME!
2297     */

2298    public int getMaxBinaryLiteralLength() throws java.sql.SQLException JavaDoc {
2299        return 16777208;
2300    }
2301
2302    /**
2303     * What's the maximum length of a catalog name?
2304     *
2305     * @return max name length in bytes
2306     *
2307     * @throws java.sql.SQLException DOCUMENT ME!
2308     */

2309    public int getMaxCatalogNameLength() throws java.sql.SQLException JavaDoc {
2310        return 32;
2311    }
2312
2313    /**
2314     * What's the max length for a character literal?
2315     *
2316     * @return max literal length
2317     *
2318     * @throws java.sql.SQLException DOCUMENT ME!
2319     */

2320    public int getMaxCharLiteralLength() throws java.sql.SQLException JavaDoc {
2321        return 16777208;
2322    }
2323
2324    /**
2325     * What's the limit on column name length?
2326     *
2327     * @return max literal length
2328     *
2329     * @throws java.sql.SQLException DOCUMENT ME!
2330     */

2331    public int getMaxColumnNameLength() throws java.sql.SQLException JavaDoc {
2332        return 64;
2333    }
2334
2335    /**
2336     * What's the maximum number of columns in a "GROUP BY" clause?
2337     *
2338     * @return max number of columns
2339     *
2340     * @throws java.sql.SQLException DOCUMENT ME!
2341     */

2342    public int getMaxColumnsInGroupBy() throws java.sql.SQLException JavaDoc {
2343        return 64;
2344    }
2345
2346    /**
2347     * What's the maximum number of columns allowed in an index?
2348     *
2349     * @return max columns
2350     *
2351     * @throws java.sql.SQLException DOCUMENT ME!
2352     */

2353    public int getMaxColumnsInIndex() throws java.sql.SQLException JavaDoc {
2354        return 16;
2355    }
2356
2357    /**
2358     * What's the maximum number of columns in an "ORDER BY" clause?
2359     *
2360     * @return max columns
2361     *
2362     * @throws java.sql.SQLException DOCUMENT ME!
2363     */

2364    public int getMaxColumnsInOrderBy() throws java.sql.SQLException JavaDoc {
2365        return 64;
2366    }
2367
2368    /**
2369     * What's the maximum number of columns in a "SELECT" list?
2370     *
2371     * @return max columns
2372     *
2373     * @throws java.sql.SQLException DOCUMENT ME!
2374     */

2375    public int getMaxColumnsInSelect() throws java.sql.SQLException JavaDoc {
2376        return 256;
2377    }
2378
2379    /**
2380     * What's maximum number of columns in a table?
2381     *
2382     * @return max columns
2383     *
2384     * @throws java.sql.SQLException DOCUMENT ME!
2385     */

2386    public int getMaxColumnsInTable() throws java.sql.SQLException JavaDoc {
2387        return 512;
2388    }
2389
2390    /**
2391     * How many active connections can we have at a time to this database?
2392     *
2393     * @return max connections
2394     *
2395     * @throws java.sql.SQLException DOCUMENT ME!
2396     */

2397    public int getMaxConnections() throws java.sql.SQLException JavaDoc {
2398        return 0;
2399    }
2400
2401    /**
2402     * What's the maximum cursor name length?
2403     *
2404     * @return max cursor name length in bytes
2405     *
2406     * @throws java.sql.SQLException DOCUMENT ME!
2407     */

2408    public int getMaxCursorNameLength() throws java.sql.SQLException JavaDoc {
2409        return 64;
2410    }
2411
2412    /**
2413     * What's the maximum length of an index (in bytes)?
2414     *
2415     * @return max index length in bytes
2416     *
2417     * @throws java.sql.SQLException DOCUMENT ME!
2418     */

2419    public int getMaxIndexLength() throws java.sql.SQLException JavaDoc {
2420        return 256;
2421    }
2422
2423    /**
2424     * What's the maximum length of a procedure name?
2425     *
2426     * @return max name length in bytes
2427     *
2428     * @throws java.sql.SQLException DOCUMENT ME!
2429     */

2430    public int getMaxProcedureNameLength() throws java.sql.SQLException JavaDoc {
2431        return 0;
2432    }
2433
2434    /**
2435     * What's the maximum length of a single row?
2436     *
2437     * @return max row size in bytes
2438     *
2439     * @throws java.sql.SQLException DOCUMENT ME!
2440     */

2441    public int getMaxRowSize() throws java.sql.SQLException JavaDoc {
2442        return Integer.MAX_VALUE - 8; // Max buffer size - HEADER
2443
}
2444
2445    /**
2446     * What's the maximum length allowed for a schema name?
2447     *
2448     * @return max name length in bytes
2449     *
2450     * @throws java.sql.SQLException DOCUMENT ME!
2451     */

2452    public int getMaxSchemaNameLength() throws java.sql.SQLException JavaDoc {
2453        return 0;
2454    }
2455
2456    /**
2457     * What's the maximum length of a SQL statement?
2458     *
2459     * @return max length in bytes
2460     *
2461     * @throws java.sql.SQLException DOCUMENT ME!
2462     */

2463    public int getMaxStatementLength() throws java.sql.SQLException JavaDoc {
2464        return MysqlIO.getMaxBuf() - 4; // Max buffer - header
2465
}
2466
2467    /**
2468     * How many active statements can we have open at one time to this
2469     * database?
2470     *
2471     * @return the maximum
2472     *
2473     * @throws java.sql.SQLException DOCUMENT ME!
2474     */

2475    public int getMaxStatements() throws java.sql.SQLException JavaDoc {
2476        return 0;
2477    }
2478
2479    /**
2480     * What's the maximum length of a table name?
2481     *
2482     * @return max name length in bytes
2483     *
2484     * @throws java.sql.SQLException DOCUMENT ME!
2485     */

2486    public int getMaxTableNameLength() throws java.sql.SQLException JavaDoc {
2487        return 64;
2488    }
2489
2490    /**
2491     * What's the maximum number of tables in a SELECT?
2492     *
2493     * @return the maximum
2494     *
2495     * @throws java.sql.SQLException DOCUMENT ME!
2496     */

2497    public int getMaxTablesInSelect() throws java.sql.SQLException JavaDoc {
2498        return 256;
2499    }
2500
2501    /**
2502     * What's the maximum length of a user name?
2503     *
2504     * @return max name length in bytes
2505     *
2506     * @throws java.sql.SQLException DOCUMENT ME!
2507     */

2508    public int getMaxUserNameLength() throws java.sql.SQLException JavaDoc {
2509        return 16;
2510    }
2511
2512    /**
2513     * Get a comma separated list of math functions.
2514     *
2515     * @return the list
2516     *
2517     * @throws java.sql.SQLException DOCUMENT ME!
2518     */

2519    public String JavaDoc getNumericFunctions() throws java.sql.SQLException JavaDoc {
2520        return "ABS,ACOS,ASIN,ATAN,ATAN2,BIT_COUNT,CEILING,COS,"
2521        + "COT,DEGREES,EXP,FLOOR,LOG,LOG10,MAX,MIN,MOD,PI,POW,"
2522        + "POWER,RADIANS,RAND,ROUND,SIN,SQRT,TAN,TRUNCATE";
2523    }
2524
2525    /**
2526     * Get a description of a table's primary key columns. They are ordered by
2527     * COLUMN_NAME.
2528     *
2529     * <P>
2530     * Each column description has the following columns:
2531     *
2532     * <OL>
2533     * <li>
2534     * <B>TABLE_CAT</B> String => table catalog (may be null)
2535     * </li>
2536     * <li>
2537     * <B>TABLE_SCHEM</B> String => table schema (may be null)
2538     * </li>
2539     * <li>
2540     * <B>TABLE_NAME</B> String => table name
2541     * </li>
2542     * <li>
2543     * <B>COLUMN_NAME</B> String => column name
2544     * </li>
2545     * <li>
2546     * <B>KEY_SEQ</B> short => sequence number within primary key
2547     * </li>
2548     * <li>
2549     * <B>PK_NAME</B> String => primary key name (may be null)
2550     * </li>
2551     * </ol>
2552     * </p>
2553     *
2554     * @param catalog a catalog name; "" retrieves those without a catalog
2555     * @param schema a schema name pattern; "" retrieves those without a schema
2556     * @param table a table name
2557     *
2558     * @return ResultSet each row is a primary key column description
2559     *
2560     * @throws java.sql.SQLException DOCUMENT ME!
2561     */

2562    public java.sql.ResultSet JavaDoc getPrimaryKeys(String JavaDoc catalog, String JavaDoc schema,
2563        String JavaDoc table) throws java.sql.SQLException JavaDoc {
2564        Field[] fields = new Field[6];
2565        fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 255);
2566        fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 0);
2567        fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 255);
2568        fields[3] = new Field("", "COLUMN_NAME", Types.CHAR, 32);
2569        fields[4] = new Field("", "KEY_SEQ", Types.SMALLINT, 5);
2570        fields[5] = new Field("", "PK_NAME", Types.CHAR, 32);
2571
2572        String JavaDoc dbSub = "";
2573
2574        if (catalog != null) {
2575            if (!catalog.equals("")) {
2576                dbSub = " FROM " + this.quotedId + catalog + this.quotedId;
2577            }
2578        } else {
2579            dbSub = " FROM " + this.quotedId + this.database + this.quotedId;
2580        }
2581
2582        if (table == null) {
2583            throw new java.sql.SQLException JavaDoc("Table not specified.", SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
2584        }
2585
2586        Statement stmt = null;
2587        ResultSet rs = null;
2588
2589        try {
2590            stmt = this.conn.createStatement();
2591            
2592            if (stmt.getMaxRows() != 0) {
2593                stmt.setMaxRows(0);
2594            }
2595
2596            StringBuffer JavaDoc queryBuf = new StringBuffer JavaDoc("SHOW KEYS FROM ");
2597            queryBuf.append(this.quotedId);
2598            queryBuf.append(table);
2599            queryBuf.append(this.quotedId);
2600            queryBuf.append(dbSub);
2601
2602            rs = stmt.executeQuery(queryBuf.toString());
2603
2604            byte[] connectionCatalogAsBytes;
2605
2606            if (catalog == null) {
2607                connectionCatalogAsBytes = s2b(this.conn.getCatalog());
2608            } else {
2609                connectionCatalogAsBytes = s2b(catalog);
2610            }
2611
2612            ArrayList JavaDoc tuples = new ArrayList JavaDoc();
2613            TreeMap JavaDoc sortMap = new TreeMap JavaDoc();
2614
2615            while (rs.next()) {
2616                String JavaDoc keyType = rs.getString("Key_name");
2617
2618                if (keyType != null) {
2619                    if (keyType.equalsIgnoreCase("PRIMARY")
2620                            || keyType.equalsIgnoreCase("PRI")) {
2621                        byte[][] tuple = new byte[6][];
2622                        tuple[0] = connectionCatalogAsBytes;
2623                        tuple[1] = null;
2624                        tuple[2] = s2b(table);
2625
2626                        String JavaDoc columnName = rs.getString("Column_name");
2627                        tuple[3] = s2b(columnName);
2628                        tuple[4] = s2b(rs.getString("Seq_in_index"));
2629                        tuple[5] = s2b(keyType);
2630                        sortMap.put(columnName, tuple);
2631                    }
2632                }
2633            }
2634
2635            // Now pull out in column name sorted order
2636
Iterator JavaDoc sortedIterator = sortMap.values().iterator();
2637
2638            while (sortedIterator.hasNext()) {
2639                tuples.add(sortedIterator.next());
2640            }
2641
2642            return buildResultSet(fields, tuples);
2643        } finally {
2644            if (rs != null) {
2645                try {
2646                    rs.close();
2647                } catch (Exception JavaDoc ex) {
2648                    ;
2649                }
2650
2651                rs = null;
2652            }
2653
2654            if (stmt != null) {
2655                try {
2656                    stmt.close();
2657                } catch (Exception JavaDoc ex) {
2658                    ;
2659                }
2660
2661                stmt = null;
2662            }
2663        }
2664    }
2665
2666    /**
2667     * Get a description of a catalog's stored procedure parameters and result
2668     * columns.
2669     *
2670     * <P>
2671     * Only descriptions matching the schema, procedure and parameter name
2672     * criteria are returned. They are ordered by PROCEDURE_SCHEM and
2673     * PROCEDURE_NAME. Within this, the return value, if any, is first. Next
2674     * are the parameter descriptions in call order. The column descriptions
2675     * follow in column number order.
2676     * </p>
2677     *
2678     * <P>
2679     * Each row in the ResultSet is a parameter desription or column
2680     * description with the following fields:
2681     *
2682     * <OL>
2683     * <li>
2684     * <B>PROCEDURE_CAT</B> String => procedure catalog (may be null)
2685     * </li>
2686     * <li>
2687     * <B>PROCEDURE_SCHEM</B> String => procedure schema (may be null)
2688     * </li>
2689     * <li>
2690     * <B>PROCEDURE_NAME</B> String => procedure name
2691     * </li>
2692     * <li>
2693     * <B>COLUMN_NAME</B> String => column/parameter name
2694     * </li>
2695     * <li>
2696     * <B>COLUMN_TYPE</B> Short => kind of column/parameter:
2697     *
2698     * <UL>
2699     * <li>
2700     * procedureColumnUnknown - nobody knows
2701     * </li>
2702     * <li>
2703     * procedureColumnIn - IN parameter
2704     * </li>
2705     * <li>
2706     * procedureColumnInOut - INOUT parameter
2707     * </li>
2708     * <li>
2709     * procedureColumnOut - OUT parameter
2710     * </li>
2711     * <li>
2712     * procedureColumnReturn - procedure return value
2713     * </li>
2714     * <li>
2715     * procedureColumnResult - result column in ResultSet
2716     * </li>
2717     * </ul>
2718     *
2719     * </li>
2720     * <li>
2721     * <B>DATA_TYPE</B> short => SQL type from java.sql.Types
2722     * </li>
2723     * <li>
2724     * <B>TYPE_NAME</B> String => SQL type name
2725     * </li>
2726     * <li>
2727     * <B>PRECISION</B> int => precision
2728     * </li>
2729     * <li>
2730     * <B>LENGTH</B> int => length in bytes of data
2731     * </li>
2732     * <li>
2733     * <B>SCALE</B> short => scale
2734     * </li>
2735     * <li>
2736     * <B>RADIX</B> short => radix
2737     * </li>
2738     * <li>
2739     * <B>NULLABLE</B> short => can it contain NULL?
2740     *
2741     * <UL>
2742     * <li>
2743     * procedureNoNulls - does not allow NULL values
2744     * </li>
2745     * <li>
2746     * procedureNullable - allows NULL values
2747     * </li>
2748     * <li>
2749     * procedureNullableUnknown - nullability unknown
2750     * </li>
2751     * </ul>
2752     *
2753     * </li>
2754     * <li>
2755     * <B>REMARKS</B> String => comment describing parameter/column
2756     * </li>
2757     * </ol>
2758     * </p>
2759     *
2760     * <P>
2761     * <B>Note:</B> Some databases may not return the column descriptions for a
2762     * procedure. Additional columns beyond REMARKS can be defined by the
2763     * database.
2764     * </p>
2765     *
2766     * @param catalog a catalog name; "" retrieves those without a catalog
2767     * @param schemaPattern a schema name pattern; "" retrieves those without a
2768     * schema
2769     * @param procedureNamePattern a procedure name pattern
2770     * @param columnNamePattern a column name pattern
2771     *
2772     * @return ResultSet each row is a stored procedure parameter or column
2773     * description
2774     *
2775     * @throws java.sql.SQLException if a database access error occurs
2776     *
2777     * @see #getSearchStringEscape
2778     */

2779    public java.sql.ResultSet JavaDoc getProcedureColumns(String JavaDoc catalog,
2780        String JavaDoc schemaPattern, String JavaDoc procedureNamePattern,
2781        String JavaDoc columnNamePattern) throws java.sql.SQLException JavaDoc {
2782        Field[] fields = new Field[14];
2783        fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 0);
2784        fields[1] = new Field("", "PROCEDURE_CAT", Types.CHAR, 0);
2785        fields[2] = new Field("", "PROCEDURE_SCHEM", Types.CHAR, 0);
2786        fields[3] = new Field("", "PROCEDURE_NAME", Types.CHAR, 0);
2787        fields[4] = new Field("", "COLUMN_NAME", Types.CHAR, 0);
2788        fields[5] = new Field("", "COLUMN_TYPE", Types.CHAR, 0);
2789        fields[6] = new Field("", "DATA_TYPE", Types.SMALLINT, 0);
2790        fields[7] = new Field("", "TYPE_NAME", Types.CHAR, 0);
2791        fields[8] = new Field("", "PRECISION", Types.INTEGER, 0);
2792        fields[9] = new Field("", "LENGTH", Types.INTEGER, 0);
2793        fields[10] = new Field("", "SCALE", Types.SMALLINT, 0);
2794        fields[11] = new Field("", "RADIX", Types.SMALLINT, 0);
2795        fields[12] = new Field("", "NULLABLE", Types.SMALLINT, 0);
2796        fields[13] = new Field("", "REMARKS", Types.CHAR, 0);
2797
2798        return buildResultSet(fields, new ArrayList JavaDoc());
2799    }
2800
2801    /**
2802     * What's the database vendor's preferred term for "procedure"?
2803     *
2804     * @return the vendor term
2805     *
2806     * @throws java.sql.SQLException DOCUMENT ME!
2807     */

2808    public String JavaDoc getProcedureTerm() throws java.sql.SQLException JavaDoc {
2809        return "";
2810    }
2811
2812    /**
2813     * Get a description of stored procedures available in a catalog.
2814     *
2815     * <P>
2816     * Only procedure descriptions matching the schema and procedure name
2817     * criteria are returned. They are ordered by PROCEDURE_SCHEM, and
2818     * PROCEDURE_NAME.
2819     * </p>
2820     *
2821     * <P>
2822     * Each procedure description has the the following columns:
2823     *
2824     * <OL>
2825     * <li>
2826     * <B>PROCEDURE_CAT</B> String => procedure catalog (may be null)
2827     * </li>
2828     * <li>
2829     * <B>PROCEDURE_SCHEM</B> String => procedure schema (may be null)
2830     * </li>
2831     * <li>
2832     * <B>PROCEDURE_NAME</B> String => procedure name
2833     * </li>
2834     * <li>
2835     * reserved for future use
2836     * </li>
2837     * <li>
2838     * reserved for future use
2839     * </li>
2840     * <li>
2841     * reserved for future use
2842     * </li>
2843     * <li>
2844     * <B>REMARKS</B> String => explanatory comment on the procedure
2845     * </li>
2846     * <li>
2847     * <B>PROCEDURE_TYPE</B> short => kind of procedure:
2848     *
2849     * <UL>
2850     * <li>
2851     * procedureResultUnknown - May return a result
2852     * </li>
2853     * <li>
2854     * procedureNoResult - Does not return a result
2855     * </li>
2856     * <li>
2857     * procedureReturnsResult - Returns a result
2858     * </li>
2859     * </ul>
2860     *
2861     * </li>
2862     * </ol>
2863     * </p>
2864     *
2865     * @param catalog a catalog name; "" retrieves those without a catalog
2866     * @param schemaPattern a schema name pattern; "" retrieves those without a
2867     * schema
2868     * @param procedureNamePattern a procedure name pattern
2869     *
2870     * @return ResultSet each row is a procedure description
2871     *
2872     * @throws java.sql.SQLException if a database access error occurs
2873     *
2874     * @see #getSearchStringEscape
2875     */

2876    public java.sql.ResultSet JavaDoc getProcedures(String JavaDoc catalog,
2877        String JavaDoc schemaPattern, String JavaDoc procedureNamePattern)
2878        throws java.sql.SQLException JavaDoc {
2879        Field[] fields = new Field[8];
2880        fields[0] = new Field("", "PROCEDURE_CAT", Types.CHAR, 0);
2881        fields[1] = new Field("", "PROCEDURE_SCHEM", Types.CHAR, 0);
2882        fields[2] = new Field("", "PROCEDURE_NAME", Types.CHAR, 0);
2883        fields[3] = new Field("", "resTABLE_CAT", Types.CHAR, 0);
2884        fields[4] = new Field("", "resTABLE_CAT", Types.CHAR, 0);
2885        fields[5] = new Field("", "resTABLE_CAT", Types.CHAR, 0);
2886        fields[6] = new Field("", "REMARKS", Types.CHAR, 0);
2887        fields[7] = new Field("", "PROCEDURE_TYPE", Types.SMALLINT, 0);
2888
2889        return buildResultSet(fields, new ArrayList JavaDoc());
2890    }
2891
2892    /**
2893     * Is the database in read-only mode?
2894     *
2895     * @return true if so
2896     *
2897     * @throws java.sql.SQLException DOCUMENT ME!
2898     */

2899    public boolean isReadOnly() throws java.sql.SQLException JavaDoc {
2900        return false;
2901    }
2902
2903    /**
2904     * @see DatabaseMetaData#getResultSetHoldability()
2905     */

2906    public int getResultSetHoldability() throws SQLException JavaDoc {
2907        return ResultSet.CLOSE_CURSORS_AT_COMMIT;
2908    }
2909
2910    /**
2911     * Get a comma separated list of all a database's SQL keywords that are NOT
2912     * also SQL92 keywords.
2913     *
2914     * @return the list
2915     *
2916     * @throws java.sql.SQLException DOCUMENT ME!
2917     */

2918    public String JavaDoc getSQLKeywords() throws java.sql.SQLException JavaDoc {
2919        return "AUTO_INCREMENT,BINARY,BLOB,ENUM,INFILE,LOAD,MEDIUMINT,OPTION,OUTFILE,REPLACE,SET,TEXT,UNSIGNED,ZEROFILL";
2920    }
2921
2922    /**
2923     * @see DatabaseMetaData#getSQLStateType()
2924     */

2925    public int getSQLStateType() throws SQLException JavaDoc {
2926        return 0;
2927    }
2928
2929    /**
2930     * What's the database vendor's preferred term for "schema"?
2931     *
2932     * @return the vendor term
2933     *
2934     * @throws java.sql.SQLException DOCUMENT ME!
2935     */

2936    public String JavaDoc getSchemaTerm() throws java.sql.SQLException JavaDoc {
2937        return "";
2938    }
2939
2940    /**
2941     * Get the schema names available in this database. The results are
2942     * ordered by schema name.
2943     *
2944     * <P>
2945     * The schema column is:
2946     *
2947     * <OL>
2948     * <li>
2949     * <B>TABLE_SCHEM</B> String => schema name
2950     * </li>
2951     * </ol>
2952     * </p>
2953     *
2954     * @return ResultSet each row has a single String column that is a schema
2955     * name
2956     *
2957     * @throws java.sql.SQLException DOCUMENT ME!
2958     */

2959    public java.sql.ResultSet JavaDoc getSchemas() throws java.sql.SQLException JavaDoc {
2960        Field[] fields = new Field[1];
2961        fields[0] = new Field("", "TABLE_SCHEM", java.sql.Types.CHAR, 0);
2962
2963        ArrayList JavaDoc tuples = new ArrayList JavaDoc();
2964        java.sql.ResultSet JavaDoc results = buildResultSet(fields, tuples);
2965
2966        return results;
2967    }
2968
2969    /**
2970     * This is the string that can be used to escape '_' or '%' in the string
2971     * pattern style catalog search parameters.
2972     *
2973     * <P>
2974     * The '_' character represents any single character.
2975     * </p>
2976     *
2977     * <P>
2978     * The '%' character represents any sequence of zero or more characters.
2979     * </p>
2980     *
2981     * @return the string used to escape wildcard characters
2982     *
2983     * @throws java.sql.SQLException DOCUMENT ME!
2984     */

2985    public String JavaDoc getSearchStringEscape() throws java.sql.SQLException JavaDoc {
2986        return "\\";
2987    }
2988
2989    /**
2990     * Get a comma separated list of string functions.
2991     *
2992     * @return the list
2993     *
2994     * @throws java.sql.SQLException DOCUMENT ME!
2995     */

2996    public String JavaDoc getStringFunctions() throws java.sql.SQLException JavaDoc {
2997        return "ASCII,BIN,BIT_LENGTH,CHAR,CHARACTER_LENGTH,CHAR_LENGTH,CONCAT,"
2998        + "CONCAT_WS,CONV,ELT,EXPORT_SET,FIELD,FIND_IN_SET,HEX,INSERT,"
2999        + "INSTR,LCASE,LEFT,LENGTH,LOAD_FILE,LOCATE,LOCATE,LOWER,LPAD,"
3000        + "LTRIM,MAKE_SET,MATCH,MID,OCT,OCTET_LENGTH,ORD,POSITION,"
3001        + "QUOTE,REPEAT,REPLACE,REVERSE,RIGHT,RPAD,RTRIM,SOUNDEX,"
3002        + "SPACE,STRCMP,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING,"
3003        + "SUBSTRING_INDEX,TRIM,UCASE,UPPER";
3004    }
3005
3006    /**
3007     * @see DatabaseMetaData#getSuperTables(String, String, String)
3008     */

3009    public java.sql.ResultSet JavaDoc getSuperTables(String JavaDoc arg0, String JavaDoc arg1,
3010        String JavaDoc arg2) throws SQLException JavaDoc {
3011        Field[] fields = new Field[4];
3012        fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 32);
3013        fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 32);
3014        fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 32);
3015        fields[3] = new Field("", "SUPERTABLE_NAME", Types.CHAR, 32);
3016
3017        return buildResultSet(fields, new ArrayList JavaDoc());
3018    }
3019
3020    /**
3021     * @see DatabaseMetaData#getSuperTypes(String, String, String)
3022     */

3023    public java.sql.ResultSet JavaDoc getSuperTypes(String JavaDoc arg0, String JavaDoc arg1,
3024        String JavaDoc arg2) throws SQLException JavaDoc {
3025        Field[] fields = new Field[6];
3026        fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 32);
3027        fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 32);
3028        fields[2] = new Field("", "TYPE_NAME", Types.CHAR, 32);
3029        fields[3] = new Field("", "SUPERTYPE_CAT", Types.CHAR, 32);
3030        fields[4] = new Field("", "SUPERTYPE_SCHEM", Types.CHAR, 32);
3031        fields[5] = new Field("", "SUPERTYPE_NAME", Types.CHAR, 32);
3032
3033        return buildResultSet(fields, new ArrayList JavaDoc());
3034    }
3035
3036    /**
3037     * Get a comma separated list of system functions.
3038     *
3039     * @return the list
3040     *
3041     * @throws java.sql.SQLException DOCUMENT ME!
3042     */

3043    public String JavaDoc getSystemFunctions() throws java.sql.SQLException JavaDoc {
3044        return "DATABASE,USER,SYSTEM_USER,SESSION_USER,PASSWORD,ENCRYPT,LAST_INSERT_ID,VERSION";
3045    }
3046
3047    /**
3048     * Get a description of the access rights for each table available in a
3049     * catalog.
3050     *
3051     * <P>
3052     * Only privileges matching the schema and table name criteria are
3053     * returned. They are ordered by TABLE_SCHEM, TABLE_NAME, and PRIVILEGE.
3054     * </p>
3055     *
3056     * <P>
3057     * Each privilige description has the following columns:
3058     *
3059     * <OL>
3060     * <li>
3061     * <B>TABLE_CAT</B> String => table catalog (may be null)
3062     * </li>
3063     * <li>
3064     * <B>TABLE_SCHEM</B> String => table schema (may be null)
3065     * </li>
3066     * <li>
3067     * <B>TABLE_NAME</B> String => table name
3068     * </li>
3069     * <li>
3070     * <B>COLUMN_NAME</B> String => column name
3071     * </li>
3072     * <li>
3073     * <B>GRANTOR</B> => grantor of access (may be null)
3074     * </li>
3075     * <li>
3076     * <B>GRANTEE</B> String => grantee of access
3077     * </li>
3078     * <li>
3079     * <B>PRIVILEGE</B> String => name of access (SELECT, INSERT, UPDATE,
3080     * REFRENCES, ...)
3081     * </li>
3082     * <li>
3083     * <B>IS_GRANTABLE</B> String => "YES" if grantee is permitted to grant to
3084     * others; "NO" if not; null if unknown
3085     * </li>
3086     * </ol>
3087     * </p>
3088     *
3089     * @param catalog a catalog name; "" retrieves those without a catalog
3090     * @param schemaPattern a schema name pattern; "" retrieves those without a
3091     * schema
3092     * @param tableNamePattern a table name pattern
3093     *
3094     * @return ResultSet each row is a table privilege description
3095     *
3096     * @throws java.sql.SQLException if a database access error occurs
3097     *
3098     * @see #getSearchStringEscape
3099     */

3100    public java.sql.ResultSet JavaDoc getTablePrivileges(String JavaDoc catalog,
3101        String JavaDoc schemaPattern, String JavaDoc tableNamePattern)
3102        throws java.sql.SQLException JavaDoc {
3103        Field[] fields = new Field[7];
3104        fields[0] = new Field("", "TABLE_CAT", Types.CHAR, 64);
3105        fields[1] = new Field("", "TABLE_SCHEM", Types.CHAR, 1);
3106        fields[2] = new Field("", "TABLE_NAME", Types.CHAR, 64);
3107        fields[3] = new Field("", "GRANTOR", Types.CHAR, 77);
3108        fields[4] = new Field("", "GRANTEE", Types.CHAR, 77);
3109        fields[5] = new Field("", "PRIVILEGE", Types.CHAR, 64);
3110        fields[6] = new Field("", "IS_GRANTABLE", Types.CHAR, 3);
3111
3112        StringBuffer JavaDoc grantQuery = new StringBuffer JavaDoc(
3113                "SELECT host,db,table_name,grantor,user,table_priv from mysql.tables_priv ");
3114        grantQuery.append(" WHERE ");
3115
3116        if ((catalog != null) && (catalog.length() != 0)) {
3117            grantQuery.append(" db='");
3118            grantQuery.append(catalog);
3119            grantQuery.append("' AND ");
3120        }
3121
3122        grantQuery.append("table_name like '");
3123        grantQuery.append(tableNamePattern);
3124        grantQuery.append("'");
3125
3126        ResultSet results = null;
3127        ArrayList JavaDoc grantRows = new ArrayList JavaDoc();
3128        Statement stmt = null;
3129
3130        try {
3131            stmt = this.conn.createStatement();
3132            
3133            if (stmt.getMaxRows() != 0) {
3134                stmt.setMaxRows(0);
3135            }
3136            
3137            results = stmt.executeQuery(grantQuery.toString());
3138
3139            while (results.next()) {
3140                String JavaDoc host = results.getString(1);
3141                String JavaDoc database = results.getString(2);
3142                String JavaDoc table = results.getString(3);
3143                String JavaDoc grantor = results.getString(4);
3144                String JavaDoc user = results.getString(5);
3145
3146                if ((user == null) || (user.length() == 0)) {
3147                    user = "%";
3148                }
3149
3150                StringBuffer JavaDoc fullUser = new StringBuffer JavaDoc(user);
3151
3152                if ((host != null) && this.conn.useHostsInPrivileges()) {
3153                    fullUser.append("@");
3154                    fullUser.append(host);
3155                }
3156
3157                String JavaDoc allPrivileges = results.getString(6);
3158
3159                if (allPrivileges != null) {
3160                    allPrivileges = allPrivileges.toUpperCase();
3161
3162                    StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(allPrivileges, ",");
3163
3164                    while (st.hasMoreTokens()) {
3165                        String JavaDoc privilege = st.nextToken().trim();
3166
3167                        // Loop through every column in the table
3168
java.sql.ResultSet JavaDoc columnResults = null;
3169
3170                        try {
3171                            columnResults = getColumns(catalog, schemaPattern,
3172                                    table, "%");
3173
3174                            while (columnResults.next()) {
3175                                byte[][] tuple = new byte[8][];
3176                                tuple[0] = s2b(database);
3177                                tuple[1] = null;
3178                                tuple[2] = s2b(table);
3179
3180                                if (grantor != null) {
3181                                    tuple[3] = s2b(grantor);
3182                                } else {
3183                                    tuple[3] = null;
3184                                }
3185
3186                                tuple[4] = s2b(fullUser.toString());
3187                                tuple[5] = s2b(privilege);
3188                                tuple[6] = null;
3189                                grantRows.add(tuple);
3190                            }
3191                        } finally {
3192                            if (columnResults != null) {
3193                                try {
3194                                    columnResults.close();
3195                                } catch (Exception JavaDoc ex) {
3196                                    ;
3197                                }
3198                            }
3199                        }
3200                    }
3201                }
3202            }
3203        } finally {
3204            if (results != null) {
3205                try {
3206                    results.close();
3207                } catch (Exception JavaDoc ex) {
3208                    ;
3209                }
3210
3211                results = null;
3212            }
3213
3214            if (stmt != null) {
3215                try {
3216                    stmt.close();
3217                } catch (Exception JavaDoc ex) {
3218                    ;
3219                }
3220
3221                stmt = null;
3222            }
3223        }
3224
3225        return buildResultSet(fields, grantRows);
3226    }
3227
3228    /**
3229     * Get the table types available in this database. The results are ordered
3230     * by table type.
3231     *
3232     * <P>
3233     * The table type is:
3234     *
3235     * <OL>
3236     * <li>
3237     * <B>TABLE_TYPE</B> String => table type. Typical types are "TABLE",
3238     * "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS",
3239     * "SYNONYM".
3240     * </li>
3241     * </ol>
3242     * </p>
3243     *
3244     * @return ResultSet each row has a single String column that is a table
3245     * type
3246     *
3247     * @throws java.sql.SQLException DOCUMENT ME!
3248     */

3249    public java.sql.ResultSet JavaDoc getTableTypes() throws java.sql.SQLException JavaDoc {
3250        ArrayList JavaDoc tuples = new ArrayList JavaDoc();
3251        Field[] fields = new Field[1];
3252        fields[0] = new Field("", "TABLE_TYPE", Types.VARCHAR, 5);
3253
3254        byte[][] tableTypeRow = new byte[1][];
3255        tableTypeRow[0] = TABLE_AS_BYTES;
3256        tuples.add(tableTypeRow);
3257
3258        byte[][] tempTypeRow = new byte[1][];
3259        tempTypeRow[0] = s2b("LOCAL TEMPORARY");
3260        tuples.add(tempTypeRow);
3261
3262        return buildResultSet(fields, tuples);
3263    }
3264
3265    /**
3266     * Get a description of tables available in a catalog.
3267     *
3268     * <P>
3269     * Only table descriptions matching the catalog, schema, table name and
3270     * type criteria are returned. They are ordered by TABLE_TYPE,
3271     * TABLE_SCHEM and TABLE_NAME.
3272     * </p>
3273     *
3274     * <P>
3275     * Each table description has the following columns:
3276     *
3277     * <OL>
3278     * <li>
3279     * <B>TABLE_CAT</B> String => table catalog (may be null)
3280     * </li>
3281     * <li>
3282     * <B>TABLE_SCHEM</B> String => table schema (may be null)
3283     * </li>
3284     * <li>
3285     * <B>TABLE_NAME</B> String => table name
3286     * </li>
3287     * <li>
3288     * <B>TABLE_TYPE</B> String => table type. Typical types are "TABLE",
3289     * "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS",
3290     * "SYNONYM".
3291     * </li>
3292     * <li>
3293     * <B>REMARKS</B> String => explanatory comment on the table
3294     * </li>
3295     * </ol>
3296     * </p>
3297     *
3298     * <P>
3299     * <B>Note:</B> Some databases may not return information for all tables.
3300     * </p>
3301     *
3302     * @param catalog a catalog name; "" retrieves those without a catalog
3303     * @param schemaPattern a schema name pattern; "" retrieves those without a
3304     * schema
3305     * @param tableNamePattern a table name pattern
3306     * @param types a list of table types to include; null returns all types
3307     *
3308     * @return ResultSet each row is a table description
3309     *
3310     * @throws java.sql.SQLException DOCUMENT ME!
3311     *
3312     * @see #getSearchStringEscape
3313     */

3314    public java.sql.ResultSet JavaDoc getTables(String JavaDoc catalog, String JavaDoc schemaPattern,
3315        String JavaDoc tableNamePattern, String JavaDoc[] types) throws java.sql.SQLException JavaDoc {
3316        String JavaDoc databasePart = "";
3317
3318        if (catalog != null) {
3319            if (!catalog.equals("")) {
3320                databasePart = " FROM " + this.quotedId + catalog
3321                    + this.quotedId;
3322            }
3323        } else {
3324            databasePart = " FROM " + this.quotedId + this.database
3325                + this.quotedId;
3326        }
3327
3328        if (tableNamePattern == null) {
3329            tableNamePattern = "%";
3330        }
3331
3332        Statement stmt = null;
3333        ResultSet results = null;
3334
3335        try {
3336            stmt = this.conn.createStatement();
3337            
3338            if (stmt.getMaxRows() != 0) {
3339                stmt.setMaxRows(0);
3340            }
3341            
3342            results = stmt.executeQuery("SHOW TABLES " + databasePart
3343                    + " LIKE '" + tableNamePattern + "'");
3344
3345            Field[] fields = new Field[5];
3346            fields[0] = new Field("", "TABLE_CAT", java.sql.Types.VARCHAR,
3347                    (catalog == null) ? 0 : catalog.length());
3348            fields[1] = new Field("", "TABLE_SCHEM", java.sql.Types.VARCHAR, 0);
3349            fields[2] = new Field("", "TABLE_NAME", java.sql.Types.VARCHAR, 255);
3350            fields[3] = new Field("", "TABLE_TYPE", java.sql.Types.VARCHAR, 5);
3351            fields[4] = new Field("", "REMARKS", java.sql.Types.VARCHAR, 0);
3352
3353            ArrayList JavaDoc tuples = new ArrayList JavaDoc();
3354            byte[][] row = null;
3355
3356            byte[] connectionCatalogAsBytes = null;
3357
3358            if (catalog == null) {
3359                connectionCatalogAsBytes = s2b(this.conn.getCatalog());
3360            } else {
3361                connectionCatalogAsBytes = s2b(catalog);
3362            }
3363
3364            while (results.next()) {
3365                row = new byte[5][];
3366                row[0] = connectionCatalogAsBytes;
3367                row[1] = null;
3368                row[2] = results.getBytes(1);
3369                row[3] = TABLE_AS_BYTES;
3370                row[4] = new byte[0];
3371                tuples.add(row);
3372            }
3373
3374            java.sql.ResultSet JavaDoc tables = buildResultSet(fields, tuples);
3375
3376            return tables;
3377        } finally {
3378            if (results != null) {
3379                try {
3380                    results.close();
3381                } catch (Exception JavaDoc ex) {
3382                    ;
3383                }
3384
3385                results = null;
3386            }
3387
3388            if (stmt != null) {
3389                try {
3390                    stmt.close();
3391                } catch (Exception JavaDoc ex) {
3392                    ;
3393                }
3394
3395                stmt = null;
3396            }
3397        }
3398    }
3399
3400    /**
3401     * Get a comma separated list of time and date functions.
3402     *
3403     * @return the list
3404     *
3405     * @throws java.sql.SQLException DOCUMENT ME!
3406     */

3407    public String JavaDoc getTimeDateFunctions() throws java.sql.SQLException JavaDoc {
3408        return "DAYOFWEEK,WEEKDAY,DAYOFMONTH,DAYOFYEAR,MONTH,DAYNAME,"
3409        + "MONTHNAME,QUARTER,WEEK,YEAR,HOUR,MINUTE,SECOND,PERIOD_ADD,"
3410        + "PERIOD_DIFF,TO_DAYS,FROM_DAYS,DATE_FORMAT,TIME_FORMAT,"
3411        + "CURDATE,CURRENT_DATE,CURTIME,CURRENT_TIME,NOW,SYSDATE,"
3412        + "CURRENT_TIMESTAMP,UNIX_TIMESTAMP,FROM_UNIXTIME,"
3413        + "SEC_TO_TIME,TIME_TO_SEC";
3414    }
3415
3416    /**
3417     * Get a description of all the standard SQL types supported by this
3418     * database. They are ordered by DATA_TYPE and then by how closely the
3419     * data type maps to the corresponding JDBC SQL type.
3420     *
3421     * <P>
3422     * Each type description has the following columns:
3423     *
3424     * <OL>
3425     * <li>
3426     * <B>TYPE_NAME</B> String => Type name
3427     * </li>
3428     * <li>
3429     * <B>DATA_TYPE</B> short => SQL data type from java.sql.Types
3430     * </li>
3431     * <li>
3432     * <B>PRECISION</B> int => maximum precision
3433     * </li>
3434     * <li>
3435     * <B>LITERAL_PREFIX</B> String => prefix used to quote a literal (may be
3436     * null)
3437     * </li>
3438     * <li>
3439     * <B>LITERAL_SUFFIX</B> String => suffix used to quote a literal (may be
3440     * null)
3441     * </li>
3442     * <li>
3443     * <B>CREATE_PARAMS</B> String => parameters used in creating the type (may
3444     * be null)
3445     * </li>
3446     * <li>
3447     * <B>NULLABLE</B> short => can you use NULL for this type?
3448     *
3449     * <UL>
3450     * <li>
3451     * typeNoNulls - does not allow NULL values
3452     * </li>
3453     * <li>
3454     * typeNullable - allows NULL values
3455     * </li>
3456     * <li>
3457     * typeNullableUnknown - nullability unknown
3458     * </li>
3459     * </ul>
3460     *
3461     * </li>
3462     * <li>
3463     * <B>CASE_SENSITIVE</B> boolean=> is it case sensitive?
3464     * </li>
3465     * <li>
3466     * <B>SEARCHABLE</B> short => can you use "WHERE" based on this type:
3467     *
3468     * <UL>
3469     * <li>
3470     * typePredNone - No support
3471     * </li>
3472     * <li>
3473     * typePredChar - Only supported with WHERE .. LIKE
3474     * </li>
3475     * <li>
3476     * typePredBasic - Supported except for WHERE .. LIKE
3477     * </li>
3478     * <li>
3479     * typeSearchable - Supported for all WHERE ..
3480     * </li>
3481     * </ul>
3482     *
3483     * </li>
3484     * <li>
3485     * <B>UNSIGNED_ATTRIBUTE</B> boolean => is it unsigned?
3486     * </li>
3487     * <li>
3488     * <B>FIXED_PREC_SCALE</B> boolean => can it be a money value?
3489     * </li>
3490     * <li>
3491     * <B>AUTO_INCREMENT</B> boolean => can it be used for an auto-increment
3492     * value?
3493     * </li>
3494     * <li>
3495     * <B>LOCAL_TYPE_NAME</B> String => localized version of type name (may be
3496     * null)
3497     * </li>
3498     * <li>
3499     * <B>MINIMUM_SCALE</B> short => minimum scale supported
3500     * </li>
3501     * <li>
3502     * <B>MAXIMUM_SCALE</B> short => maximum scale supported
3503     * </li>
3504     * <li>
3505     * <B>SQL_DATA_TYPE</B> int => unused
3506     * </li>
3507     * <li>
3508     * <B>SQL_DATETIME_SUB</B> int => unused
3509     * </li>
3510     * <li>
3511     * <B>NUM_PREC_RADIX</B> int => usually 2 or 10
3512     * </li>
3513     * </ol>
3514     * </p>
3515     *
3516     * @return ResultSet each row is a SQL type description
3517     *
3518     * @throws java.sql.SQLException DOCUMENT ME!
3519     */

3520    /**
3521     * Get a description of all the standard SQL types supported by this
3522     * database. They are ordered by DATA_TYPE and then by how closely the
3523     * data type maps to the corresponding JDBC SQL type.
3524     *
3525     * <P>
3526     * Each type description has the following columns:
3527     *
3528     * <OL>
3529     * <li>
3530     * <B>TYPE_NAME</B> String => Type name
3531     * </li>
3532     * <li>
3533     * <B>DATA_TYPE</B> short => SQL data type from java.sql.Types
3534     * </li>
3535     * <li>
3536     * <B>PRECISION</B> int => maximum precision
3537     * </li>
3538     * <li>
3539     * <B>LITERAL_PREFIX</B> String => prefix used to quote a literal (may be
3540     * null)
3541     * </li>
3542     * <li>
3543     * <B>LITERAL_SUFFIX</B> String => suffix used to quote a literal (may be
3544     * null)
3545     * </li>
3546     * <li>
3547     * <B>CREATE_PARAMS</B> String => parameters used in creating the type (may
3548     * be null)
3549     * </li>
3550     * <li>
3551     * <B>NULLABLE</B> short => can you use NULL for this type?
3552     *
3553     * <UL>
3554     * <li>
3555     * typeNoNulls - does not allow NULL values
3556     * </li>
3557     * <li>
3558     * typeNullable - allows NULL values
3559     * </li>
3560     * <li>
3561     * typeNullableUnknown - nullability unknown
3562     * </li>
3563     * </ul>
3564     *
3565     * </li>
3566     * <li>
3567     * <B>CASE_SENSITIVE</B> boolean=> is it case sensitive?
3568     * </li>
3569     * <li>
3570     * <B>SEARCHABLE</B> short => can you use "WHERE" based on this type:
3571     *
3572     * <UL>
3573     * <li>
3574     * typePredNone - No support
3575     * </li>
3576     * <li>
3577     * typePredChar - Only supported with WHERE .. LIKE
3578     * </li>
3579     * <li>
3580     * typePredBasic - Supported except for WHERE .. LIKE
3581     * </li>
3582     * <li>
3583     * typeSearchable - Supported for all WHERE ..
3584     * </li>
3585     * </ul>
3586     *
3587     * </li>
3588     * <li>
3589     * <B>UNSIGNED_ATTRIBUTE</B> boolean => is it unsigned?
3590     * </li>
3591     * <li>
3592     * <B>FIXED_PREC_SCALE</B> boolean => can it be a money value?
3593     * </li>
3594     * <li>
3595     * <B>AUTO_INCREMENT</B> boolean => can it be used for an auto-increment
3596     * value?
3597     * </li>
3598     * <li>
3599     * <B>LOCAL_TYPE_NAME</B> String => localized version of type name (may be
3600     * null)
3601     * </li>
3602     * <li>
3603     * <B>MINIMUM_SCALE</B> short => minimum scale supported
3604     * </li>
3605     * <li>
3606     * <B>MAXIMUM_SCALE</B> short => maximum scale supported
3607     * </li>
3608     * <li>
3609     * <B>SQL_DATA_TYPE</B> int => unused
3610     * </li>
3611     * <li>
3612     * <B>SQL_DATETIME_SUB</B> int => unused
3613     * </li>
3614     * <li>
3615     * <B>NUM_PREC_RADIX</B> int => usually 2 or 10
3616     * </li>
3617     * </ol>
3618     * </p>
3619     *
3620     * @return ResultSet each row is a SQL type description
3621     *
3622     * @throws java.sql.SQLException DOCUMENT ME!
3623     */

3624    public java.sql.ResultSet JavaDoc getTypeInfo() throws java.sql.SQLException JavaDoc {
3625        Field[] fields = new Field[18];
3626        fields[0] = new Field("", "TYPE_NAME", Types.CHAR, 32);
3627        fields[1] = new Field("", "DATA_TYPE", Types.SMALLINT, 5);
3628        fields[2] = new Field("", "PRECISION", Types.INTEGER, 10);
3629        fields[3] = new Field("", "LITERAL_PREFIX", Types.CHAR, 4);
3630        fields[4] = new Field("", "LITERAL_SUFFIX", Types.CHAR, 4);
3631        fields[5] = new Field("", "CREATE_PARAMS", Types.CHAR, 32);
3632        fields[6] = new Field("", "NULLABLE", Types.SMALLINT, 5);
3633        fields[7] = new Field("", "CASE_SENSITIVE", Types.CHAR, 3);
3634        fields[8] = new Field("", "SEARCHABLE", Types.SMALLINT, 3);
3635        fields[9] = new Field("", "UNSIGNED_ATTRIBUTE", Types.CHAR, 3);
3636        fields[10] = new Field("", "FIXED_PREC_SCALE", Types.CHAR, 3);
3637        fields[11] = new Field("", "AUTO_INCREMENT", Types.CHAR, 3);
3638        fields[12] = new Field("", "LOCAL_TYPE_NAME", Types.CHAR, 32);
3639        fields[13] = new Field("", "MINIMUM_SCALE", Types.SMALLINT, 5);
3640        fields[14] = new Field("", "MAXIMUM_SCALE", Types.SMALLINT, 5);
3641        fields[15] = new Field("", "SQL_DATA_TYPE", Types.INTEGER, 10);
3642        fields[16] = new Field("", "SQL_DATETIME_SUB", Types.INTEGER, 10);
3643        fields[17] = new Field("", "NUM_PREC_RADIX", Types.INTEGER, 10);
3644
3645        byte[][] rowVal = null;
3646        ArrayList JavaDoc tuples = new ArrayList JavaDoc();
3647
3648        /*
3649         * The following are ordered by java.sql.Types, and
3650         * then by how closely the MySQL type matches the
3651         * JDBC Type (per spec)
3652         */

3653        /*
3654         * MySQL Type: BIT (silently converted to TINYINT(1))
3655         * JDBC Type: BIT
3656         */

3657        rowVal = new byte[18][];
3658        rowVal[0] = s2b("BIT");
3659        rowVal[1] = Integer.toString(java.sql.Types.BIT).getBytes();
3660
3661        // JDBC Data type
3662
rowVal[2] = s2b("1"); // Precision
3663
rowVal[3] = s2b(""); // Literal Prefix
3664
rowVal[4] = s2b(""); // Literal Suffix
3665
rowVal[5] = s2b(""); // Create Params
3666
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
3667                           .getBytes();
3668
3669        // Nullable
3670
rowVal[7] = s2b("true"); // Case Sensitive
3671
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
3672                           .getBytes();
3673
3674        // Searchable
3675
rowVal[9] = s2b("false"); // Unsignable
3676
rowVal[10] = s2b("false"); // Fixed Prec Scale
3677
rowVal[11] = s2b("false"); // Auto Increment
3678
rowVal[12] = s2b("BIT"); // Locale Type Name
3679
rowVal[13] = s2b("0"); // Minimum Scale
3680
rowVal[14] = s2b("0"); // Maximum Scale
3681
rowVal[15] = s2b("0"); // SQL Data Type (not used)
3682
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
3683
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
3684
tuples.add(rowVal);
3685
3686        /*
3687         * MySQL Type: BOOL (silently converted to TINYINT(1))
3688         * JDBC Type: BIT
3689         */

3690        rowVal = new byte[18][];
3691        rowVal[0] = s2b("BOOL");
3692        rowVal[1] = Integer.toString(java.sql.Types.BIT).getBytes();
3693
3694        // JDBC Data type
3695
rowVal[2] = s2b("1"); // Precision
3696
rowVal[3] = s2b(""); // Literal Prefix
3697
rowVal[4] = s2b(""); // Literal Suffix
3698
rowVal[5] = s2b(""); // Create Params
3699
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
3700                           .getBytes();
3701
3702        // Nullable
3703
rowVal[7] = s2b("true"); // Case Sensitive
3704
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
3705                           .getBytes();
3706
3707        // Searchable
3708
rowVal[9] = s2b("false"); // Unsignable
3709
rowVal[10] = s2b("false"); // Fixed Prec Scale
3710
rowVal[11] = s2b("false"); // Auto Increment
3711
rowVal[12] = s2b("BOOL"); // Locale Type Name
3712
rowVal[13] = s2b("0"); // Minimum Scale
3713
rowVal[14] = s2b("0"); // Maximum Scale
3714
rowVal[15] = s2b("0"); // SQL Data Type (not used)
3715
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
3716
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
3717
tuples.add(rowVal);
3718
3719        /*
3720         * MySQL Type: TINYINT
3721         * JDBC Type: TINYINT
3722         */

3723        rowVal = new byte[18][];
3724        rowVal[0] = s2b("TINYINT");
3725        rowVal[1] = Integer.toString(java.sql.Types.TINYINT).getBytes();
3726
3727        // JDBC Data type
3728
rowVal[2] = s2b("3"); // Precision
3729
rowVal[3] = s2b(""); // Literal Prefix
3730
rowVal[4] = s2b(""); // Literal Suffix
3731
rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params
3732
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
3733                           .getBytes();
3734
3735        // Nullable
3736
rowVal[7] = s2b("false"); // Case Sensitive
3737
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
3738                           .getBytes();
3739
3740        // Searchable
3741
rowVal[9] = s2b("true"); // Unsignable
3742
rowVal[10] = s2b("false"); // Fixed Prec Scale
3743
rowVal[11] = s2b("true"); // Auto Increment
3744
rowVal[12] = s2b("TINYINT"); // Locale Type Name
3745
rowVal[13] = s2b("0"); // Minimum Scale
3746
rowVal[14] = s2b("0"); // Maximum Scale
3747
rowVal[15] = s2b("0"); // SQL Data Type (not used)
3748
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
3749
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
3750
tuples.add(rowVal);
3751
3752        /*
3753         * MySQL Type: BIGINT
3754         * JDBC Type: BIGINT
3755         */

3756        rowVal = new byte[18][];
3757        rowVal[0] = s2b("BIGINT");
3758        rowVal[1] = Integer.toString(java.sql.Types.BIGINT).getBytes();
3759
3760        // JDBC Data type
3761
rowVal[2] = s2b("19"); // Precision
3762
rowVal[3] = s2b(""); // Literal Prefix
3763
rowVal[4] = s2b(""); // Literal Suffix
3764
rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params
3765
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
3766                           .getBytes();
3767
3768        // Nullable
3769
rowVal[7] = s2b("false"); // Case Sensitive
3770
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
3771                           .getBytes();
3772
3773        // Searchable
3774
rowVal[9] = s2b("true"); // Unsignable
3775
rowVal[10] = s2b("false"); // Fixed Prec Scale
3776
rowVal[11] = s2b("true"); // Auto Increment
3777
rowVal[12] = s2b("BIGINT"); // Locale Type Name
3778
rowVal[13] = s2b("0"); // Minimum Scale
3779
rowVal[14] = s2b("0"); // Maximum Scale
3780
rowVal[15] = s2b("0"); // SQL Data Type (not used)
3781
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
3782
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
3783
tuples.add(rowVal);
3784
3785        /*
3786         * MySQL Type: LONG VARBINARY
3787         * JDBC Type: LONGVARBINARY
3788         */

3789        rowVal = new byte[18][];
3790        rowVal[0] = s2b("LONG VARBINARY");
3791        rowVal[1] = Integer.toString(java.sql.Types.LONGVARBINARY).getBytes();
3792
3793        // JDBC Data type
3794
rowVal[2] = s2b("16777215"); // Precision
3795
rowVal[3] = s2b("'"); // Literal Prefix
3796
rowVal[4] = s2b("'"); // Literal Suffix
3797
rowVal[5] = s2b(""); // Create Params
3798
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
3799                           .getBytes();
3800
3801        // Nullable
3802
rowVal[7] = s2b("true"); // Case Sensitive
3803
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
3804                           .getBytes();
3805
3806        // Searchable
3807
rowVal[9] = s2b("false"); // Unsignable
3808
rowVal[10] = s2b("false"); // Fixed Prec Scale
3809
rowVal[11] = s2b("false"); // Auto Increment
3810
rowVal[12] = s2b("LONG VARBINARY"); // Locale Type Name
3811
rowVal[13] = s2b("0"); // Minimum Scale
3812
rowVal[14] = s2b("0"); // Maximum Scale
3813
rowVal[15] = s2b("0"); // SQL Data Type (not used)
3814
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
3815
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
3816
tuples.add(rowVal);
3817
3818        /*
3819         * MySQL Type: MEDIUMBLOB
3820         * JDBC Type: LONGVARBINARY
3821         */

3822        rowVal = new byte[18][];
3823        rowVal[0] = s2b("MEDIUMBLOB");
3824        rowVal[1] = Integer.toString(java.sql.Types.LONGVARBINARY).getBytes();
3825
3826        // JDBC Data type
3827
rowVal[2] = s2b("16777215"); // Precision
3828
rowVal[3] = s2b("'"); // Literal Prefix
3829
rowVal[4] = s2b("'"); // Literal Suffix
3830
rowVal[5] = s2b(""); // Create Params
3831
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
3832                           .getBytes();
3833
3834        // Nullable
3835
rowVal[7] = s2b("true"); // Case Sensitive
3836
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
3837                           .getBytes();
3838
3839        // Searchable
3840
rowVal[9] = s2b("false"); // Unsignable
3841
rowVal[10] = s2b("false"); // Fixed Prec Scale
3842
rowVal[11] = s2b("false"); // Auto Increment
3843
rowVal[12] = s2b("MEDIUMBLOB"); // Locale Type Name
3844
rowVal[13] = s2b("0"); // Minimum Scale
3845
rowVal[14] = s2b("0"); // Maximum Scale
3846
rowVal[15] = s2b("0"); // SQL Data Type (not used)
3847
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
3848
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
3849
tuples.add(rowVal);
3850
3851        /*
3852         * MySQL Type: LONGBLOB
3853         * JDBC Type: LONGVARBINARY
3854         */

3855        rowVal = new byte[18][];
3856        rowVal[0] = s2b("LONGBLOB");
3857        rowVal[1] = Integer.toString(java.sql.Types.LONGVARBINARY).getBytes();
3858
3859        // JDBC Data type
3860
rowVal[2] = Integer.toString(Integer.MAX_VALUE).getBytes();
3861
3862        // Precision
3863
rowVal[3] = s2b("'"); // Literal Prefix
3864
rowVal[4] = s2b("'"); // Literal Suffix
3865
rowVal[5] = s2b(""); // Create Params
3866
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
3867                           .getBytes();
3868
3869        // Nullable
3870
rowVal[7] = s2b("true"); // Case Sensitive
3871
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
3872                           .getBytes();
3873
3874        // Searchable
3875
rowVal[9] = s2b("false"); // Unsignable
3876
rowVal[10] = s2b("false"); // Fixed Prec Scale
3877
rowVal[11] = s2b("false"); // Auto Increment
3878
rowVal[12] = s2b("LONGBLOB"); // Locale Type Name
3879
rowVal[13] = s2b("0"); // Minimum Scale
3880
rowVal[14] = s2b("0"); // Maximum Scale
3881
rowVal[15] = s2b("0"); // SQL Data Type (not used)
3882
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
3883
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
3884
tuples.add(rowVal);
3885
3886        /*
3887         * MySQL Type: BLOB
3888         * JDBC Type: LONGVARBINARY
3889         */

3890        rowVal = new byte[18][];
3891        rowVal[0] = s2b("BLOB");
3892        rowVal[1] = Integer.toString(java.sql.Types.LONGVARBINARY).getBytes();
3893
3894        // JDBC Data type
3895
rowVal[2] = s2b("65535"); // Precision
3896
rowVal[3] = s2b("'"); // Literal Prefix
3897
rowVal[4] = s2b("'"); // Literal Suffix
3898
rowVal[5] = s2b(""); // Create Params
3899
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
3900                           .getBytes();
3901
3902        // Nullable
3903
rowVal[7] = s2b("true"); // Case Sensitive
3904
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
3905                           .getBytes();
3906
3907        // Searchable
3908
rowVal[9] = s2b("false"); // Unsignable
3909
rowVal[10] = s2b("false"); // Fixed Prec Scale
3910
rowVal[11] = s2b("false"); // Auto Increment
3911
rowVal[12] = s2b("BLOB"); // Locale Type Name
3912
rowVal[13] = s2b("0"); // Minimum Scale
3913
rowVal[14] = s2b("0"); // Maximum Scale
3914
rowVal[15] = s2b("0"); // SQL Data Type (not used)
3915
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
3916
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
3917
tuples.add(rowVal);
3918
3919        /*
3920         * MySQL Type: TINYBLOB
3921         * JDBC Type: LONGVARBINARY
3922         */

3923        rowVal = new byte[18][];
3924        rowVal[0] = s2b("TINYBLOB");
3925        rowVal[1] = Integer.toString(java.sql.Types.LONGVARBINARY).getBytes();
3926
3927        // JDBC Data type
3928
rowVal[2] = s2b("255"); // Precision
3929
rowVal[3] = s2b("'"); // Literal Prefix
3930
rowVal[4] = s2b("'"); // Literal Suffix
3931
rowVal[5] = s2b(""); // Create Params
3932
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
3933                           .getBytes();
3934
3935        // Nullable
3936
rowVal[7] = s2b("true"); // Case Sensitive
3937
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
3938                           .getBytes();
3939
3940        // Searchable
3941
rowVal[9] = s2b("false"); // Unsignable
3942
rowVal[10] = s2b("false"); // Fixed Prec Scale
3943
rowVal[11] = s2b("false"); // Auto Increment
3944
rowVal[12] = s2b("TINYBLOB"); // Locale Type Name
3945
rowVal[13] = s2b("0"); // Minimum Scale
3946
rowVal[14] = s2b("0"); // Maximum Scale
3947
rowVal[15] = s2b("0"); // SQL Data Type (not used)
3948
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
3949
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
3950
tuples.add(rowVal);
3951
3952        /*
3953         * MySQL Type: VARBINARY (sliently converted to VARCHAR(M) BINARY)
3954         * JDBC Type: VARBINARY
3955         */

3956        rowVal = new byte[18][];
3957        rowVal[0] = s2b("VARBINARY");
3958        rowVal[1] = Integer.toString(java.sql.Types.VARBINARY).getBytes();
3959
3960        // JDBC Data type
3961
rowVal[2] = s2b("255"); // Precision
3962
rowVal[3] = s2b("'"); // Literal Prefix
3963
rowVal[4] = s2b("'"); // Literal Suffix
3964
rowVal[5] = s2b("(M)"); // Create Params
3965
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
3966                           .getBytes();
3967
3968        // Nullable
3969
rowVal[7] = s2b("true"); // Case Sensitive
3970
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
3971                           .getBytes();
3972
3973        // Searchable
3974
rowVal[9] = s2b("false"); // Unsignable
3975
rowVal[10] = s2b("false"); // Fixed Prec Scale
3976
rowVal[11] = s2b("false"); // Auto Increment
3977
rowVal[12] = s2b("VARBINARY"); // Locale Type Name
3978
rowVal[13] = s2b("0"); // Minimum Scale
3979
rowVal[14] = s2b("0"); // Maximum Scale
3980
rowVal[15] = s2b("0"); // SQL Data Type (not used)
3981
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
3982
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
3983
tuples.add(rowVal);
3984
3985        /*
3986         * MySQL Type: BINARY (silently converted to CHAR(M) BINARY)
3987         * JDBC Type: BINARY
3988         */

3989        rowVal = new byte[18][];
3990        rowVal[0] = s2b("BINARY");
3991        rowVal[1] = Integer.toString(java.sql.Types.BINARY).getBytes();
3992
3993        // JDBC Data type
3994
rowVal[2] = s2b("255"); // Precision
3995
rowVal[3] = s2b("'"); // Literal Prefix
3996
rowVal[4] = s2b("'"); // Literal Suffix
3997
rowVal[5] = s2b("(M)"); // Create Params
3998
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
3999                           .getBytes();
4000
4001        // Nullable
4002
rowVal[7] = s2b("true"); // Case Sensitive
4003
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4004                           .getBytes();
4005
4006        // Searchable
4007
rowVal[9] = s2b("false"); // Unsignable
4008
rowVal[10] = s2b("false"); // Fixed Prec Scale
4009
rowVal[11] = s2b("false"); // Auto Increment
4010
rowVal[12] = s2b("BINARY"); // Locale Type Name
4011
rowVal[13] = s2b("0"); // Minimum Scale
4012
rowVal[14] = s2b("0"); // Maximum Scale
4013
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4014
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4015
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4016
tuples.add(rowVal);
4017
4018        /*
4019         * MySQL Type: LONG VARCHAR
4020         * JDBC Type: LONGVARCHAR
4021         */

4022        rowVal = new byte[18][];
4023        rowVal[0] = s2b("LONG VARCHAR");
4024        rowVal[1] = Integer.toString(java.sql.Types.LONGVARCHAR).getBytes();
4025
4026        // JDBC Data type
4027
rowVal[2] = s2b("16777215"); // Precision
4028
rowVal[3] = s2b("'"); // Literal Prefix
4029
rowVal[4] = s2b("'"); // Literal Suffix
4030
rowVal[5] = s2b(""); // Create Params
4031
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4032                           .getBytes();
4033
4034        // Nullable
4035
rowVal[7] = s2b("false"); // Case Sensitive
4036
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4037                           .getBytes();
4038
4039        // Searchable
4040
rowVal[9] = s2b("false"); // Unsignable
4041
rowVal[10] = s2b("false"); // Fixed Prec Scale
4042
rowVal[11] = s2b("false"); // Auto Increment
4043
rowVal[12] = s2b("LONG VARCHAR"); // Locale Type Name
4044
rowVal[13] = s2b("0"); // Minimum Scale
4045
rowVal[14] = s2b("0"); // Maximum Scale
4046
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4047
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4048
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4049
tuples.add(rowVal);
4050
4051        /*
4052         * MySQL Type: MEDIUMTEXT
4053         * JDBC Type: LONGVARCHAR
4054         */

4055        rowVal = new byte[18][];
4056        rowVal[0] = s2b("MEDIUMTEXT");
4057        rowVal[1] = Integer.toString(java.sql.Types.LONGVARCHAR).getBytes();
4058
4059        // JDBC Data type
4060
rowVal[2] = s2b("16777215"); // Precision
4061
rowVal[3] = s2b("'"); // Literal Prefix
4062
rowVal[4] = s2b("'"); // Literal Suffix
4063
rowVal[5] = s2b(""); // Create Params
4064
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4065                           .getBytes();
4066
4067        // Nullable
4068
rowVal[7] = s2b("false"); // Case Sensitive
4069
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4070                           .getBytes();
4071
4072        // Searchable
4073
rowVal[9] = s2b("false"); // Unsignable
4074
rowVal[10] = s2b("false"); // Fixed Prec Scale
4075
rowVal[11] = s2b("false"); // Auto Increment
4076
rowVal[12] = s2b("MEDIUMTEXT"); // Locale Type Name
4077
rowVal[13] = s2b("0"); // Minimum Scale
4078
rowVal[14] = s2b("0"); // Maximum Scale
4079
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4080
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4081
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4082
tuples.add(rowVal);
4083
4084        /*
4085         * MySQL Type: LONGTEXT
4086         * JDBC Type: LONGVARCHAR
4087         */

4088        rowVal = new byte[18][];
4089        rowVal[0] = s2b("LONGTEXT");
4090        rowVal[1] = Integer.toString(java.sql.Types.LONGVARCHAR).getBytes();
4091
4092        // JDBC Data type
4093
rowVal[2] = Integer.toString(Integer.MAX_VALUE).getBytes();
4094
4095        // Precision
4096
rowVal[3] = s2b("'"); // Literal Prefix
4097
rowVal[4] = s2b("'"); // Literal Suffix
4098
rowVal[5] = s2b(""); // Create Params
4099
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4100                           .getBytes();
4101
4102        // Nullable
4103
rowVal[7] = s2b("false"); // Case Sensitive
4104
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4105                           .getBytes();
4106
4107        // Searchable
4108
rowVal[9] = s2b("false"); // Unsignable
4109
rowVal[10] = s2b("false"); // Fixed Prec Scale
4110
rowVal[11] = s2b("false"); // Auto Increment
4111
rowVal[12] = s2b("LONGTEXT"); // Locale Type Name
4112
rowVal[13] = s2b("0"); // Minimum Scale
4113
rowVal[14] = s2b("0"); // Maximum Scale
4114
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4115
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4116
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4117
tuples.add(rowVal);
4118
4119        /*
4120         * MySQL Type: TEXT
4121         * JDBC Type: LONGVARCHAR
4122         */

4123        rowVal = new byte[18][];
4124        rowVal[0] = s2b("TEXT");
4125        rowVal[1] = Integer.toString(java.sql.Types.LONGVARCHAR).getBytes();
4126
4127        // JDBC Data type
4128
rowVal[2] = s2b("65535"); // Precision
4129
rowVal[3] = s2b("'"); // Literal Prefix
4130
rowVal[4] = s2b("'"); // Literal Suffix
4131
rowVal[5] = s2b(""); // Create Params
4132
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4133                           .getBytes();
4134
4135        // Nullable
4136
rowVal[7] = s2b("false"); // Case Sensitive
4137
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4138                           .getBytes();
4139
4140        // Searchable
4141
rowVal[9] = s2b("false"); // Unsignable
4142
rowVal[10] = s2b("false"); // Fixed Prec Scale
4143
rowVal[11] = s2b("false"); // Auto Increment
4144
rowVal[12] = s2b("TEXT"); // Locale Type Name
4145
rowVal[13] = s2b("0"); // Minimum Scale
4146
rowVal[14] = s2b("0"); // Maximum Scale
4147
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4148
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4149
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4150
tuples.add(rowVal);
4151
4152        /*
4153         * MySQL Type: TINYTEXT
4154         * JDBC Type: LONGVARCHAR
4155         */

4156        rowVal = new byte[18][];
4157        rowVal[0] = s2b("TINYTEXT");
4158        rowVal[1] = Integer.toString(java.sql.Types.LONGVARCHAR).getBytes();
4159
4160        // JDBC Data type
4161
rowVal[2] = s2b("255"); // Precision
4162
rowVal[3] = s2b("'"); // Literal Prefix
4163
rowVal[4] = s2b("'"); // Literal Suffix
4164
rowVal[5] = s2b(""); // Create Params
4165
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4166                           .getBytes();
4167
4168        // Nullable
4169
rowVal[7] = s2b("false"); // Case Sensitive
4170
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4171                           .getBytes();
4172
4173        // Searchable
4174
rowVal[9] = s2b("false"); // Unsignable
4175
rowVal[10] = s2b("false"); // Fixed Prec Scale
4176
rowVal[11] = s2b("false"); // Auto Increment
4177
rowVal[12] = s2b("TINYTEXT"); // Locale Type Name
4178
rowVal[13] = s2b("0"); // Minimum Scale
4179
rowVal[14] = s2b("0"); // Maximum Scale
4180
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4181
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4182
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4183
tuples.add(rowVal);
4184
4185        /*
4186         * MySQL Type: CHAR
4187         * JDBC Type: CHAR
4188         */

4189        rowVal = new byte[18][];
4190        rowVal[0] = s2b("CHAR");
4191        rowVal[1] = Integer.toString(java.sql.Types.CHAR).getBytes();
4192
4193        // JDBC Data type
4194
rowVal[2] = s2b("255"); // Precision
4195
rowVal[3] = s2b("'"); // Literal Prefix
4196
rowVal[4] = s2b("'"); // Literal Suffix
4197
rowVal[5] = s2b("(M)"); // Create Params
4198
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4199                           .getBytes();
4200
4201        // Nullable
4202
rowVal[7] = s2b("false"); // Case Sensitive
4203
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4204                           .getBytes();
4205
4206        // Searchable
4207
rowVal[9] = s2b("false"); // Unsignable
4208
rowVal[10] = s2b("false"); // Fixed Prec Scale
4209
rowVal[11] = s2b("false"); // Auto Increment
4210
rowVal[12] = s2b("CHAR"); // Locale Type Name
4211
rowVal[13] = s2b("0"); // Minimum Scale
4212
rowVal[14] = s2b("0"); // Maximum Scale
4213
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4214
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4215
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4216
tuples.add(rowVal);
4217
4218        /*
4219         * MySQL Type: NUMERIC (silently converted to DECIMAL)
4220         * JDBC Type: NUMERIC
4221         */

4222        rowVal = new byte[18][];
4223        rowVal[0] = s2b("NUMERIC");
4224        rowVal[1] = Integer.toString(java.sql.Types.NUMERIC).getBytes();
4225
4226        // JDBC Data type
4227
rowVal[2] = s2b("17"); // Precision
4228
rowVal[3] = s2b(""); // Literal Prefix
4229
rowVal[4] = s2b(""); // Literal Suffix
4230
rowVal[5] = s2b("[(M[,D])] [ZEROFILL]"); // Create Params
4231
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4232                           .getBytes();
4233
4234        // Nullable
4235
rowVal[7] = s2b("false"); // Case Sensitive
4236
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4237                           .getBytes();
4238
4239        // Searchable
4240
rowVal[9] = s2b("false"); // Unsignable
4241
rowVal[10] = s2b("false"); // Fixed Prec Scale
4242
rowVal[11] = s2b("true"); // Auto Increment
4243
rowVal[12] = s2b("NUMERIC"); // Locale Type Name
4244
rowVal[13] = s2b("308"); // Minimum Scale
4245
rowVal[14] = s2b("308"); // Maximum Scale
4246
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4247
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4248
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4249
tuples.add(rowVal);
4250
4251        /*
4252         * MySQL Type: DECIMAL
4253         * JDBC Type: DECIMAL
4254         */

4255        rowVal = new byte[18][];
4256        rowVal[0] = s2b("DECIMAL");
4257        rowVal[1] = Integer.toString(java.sql.Types.DECIMAL).getBytes();
4258
4259        // JDBC Data type
4260
rowVal[2] = s2b("17"); // Precision
4261
rowVal[3] = s2b(""); // Literal Prefix
4262
rowVal[4] = s2b(""); // Literal Suffix
4263
rowVal[5] = s2b("[(M[,D])] [ZEROFILL]"); // Create Params
4264
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4265                           .getBytes();
4266
4267        // Nullable
4268
rowVal[7] = s2b("false"); // Case Sensitive
4269
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4270                           .getBytes();
4271
4272        // Searchable
4273
rowVal[9] = s2b("false"); // Unsignable
4274
rowVal[10] = s2b("false"); // Fixed Prec Scale
4275
rowVal[11] = s2b("true"); // Auto Increment
4276
rowVal[12] = s2b("DECIMAL"); // Locale Type Name
4277
rowVal[13] = s2b("-308"); // Minimum Scale
4278
rowVal[14] = s2b("308"); // Maximum Scale
4279
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4280
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4281
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4282
tuples.add(rowVal);
4283
4284        /*
4285         * MySQL Type: INTEGER
4286         * JDBC Type: INTEGER
4287         */

4288        rowVal = new byte[18][];
4289        rowVal[0] = s2b("INTEGER");
4290        rowVal[1] = Integer.toString(java.sql.Types.INTEGER).getBytes();
4291
4292        // JDBC Data type
4293
rowVal[2] = s2b("10"); // Precision
4294
rowVal[3] = s2b(""); // Literal Prefix
4295
rowVal[4] = s2b(""); // Literal Suffix
4296
rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params
4297
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4298                           .getBytes();
4299
4300        // Nullable
4301
rowVal[7] = s2b("false"); // Case Sensitive
4302
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4303                           .getBytes();
4304
4305        // Searchable
4306
rowVal[9] = s2b("true"); // Unsignable
4307
rowVal[10] = s2b("false"); // Fixed Prec Scale
4308
rowVal[11] = s2b("true"); // Auto Increment
4309
rowVal[12] = s2b("INTEGER"); // Locale Type Name
4310
rowVal[13] = s2b("0"); // Minimum Scale
4311
rowVal[14] = s2b("0"); // Maximum Scale
4312
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4313
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4314
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4315
tuples.add(rowVal);
4316
4317        /*
4318         * MySQL Type: INT
4319         * JDBC Type: INTEGER
4320         */

4321        rowVal = new byte[18][];
4322        rowVal[0] = s2b("INT");
4323        rowVal[1] = Integer.toString(java.sql.Types.INTEGER).getBytes();
4324
4325        // JDBC Data type
4326
rowVal[2] = s2b("10"); // Precision
4327
rowVal[3] = s2b(""); // Literal Prefix
4328
rowVal[4] = s2b(""); // Literal Suffix
4329
rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params
4330
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4331                           .getBytes();
4332
4333        // Nullable
4334
rowVal[7] = s2b("false"); // Case Sensitive
4335
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4336                           .getBytes();
4337
4338        // Searchable
4339
rowVal[9] = s2b("true"); // Unsignable
4340
rowVal[10] = s2b("false"); // Fixed Prec Scale
4341
rowVal[11] = s2b("true"); // Auto Increment
4342
rowVal[12] = s2b("INT"); // Locale Type Name
4343
rowVal[13] = s2b("0"); // Minimum Scale
4344
rowVal[14] = s2b("0"); // Maximum Scale
4345
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4346
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4347
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4348
tuples.add(rowVal);
4349
4350        /*
4351         * MySQL Type: MEDIUMINT
4352         * JDBC Type: INTEGER
4353         */

4354        rowVal = new byte[18][];
4355        rowVal[0] = s2b("MEDIUMINT");
4356        rowVal[1] = Integer.toString(java.sql.Types.INTEGER).getBytes();
4357
4358        // JDBC Data type
4359
rowVal[2] = s2b("7"); // Precision
4360
rowVal[3] = s2b(""); // Literal Prefix
4361
rowVal[4] = s2b(""); // Literal Suffix
4362
rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params
4363
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4364                           .getBytes();
4365
4366        // Nullable
4367
rowVal[7] = s2b("false"); // Case Sensitive
4368
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4369                           .getBytes();
4370
4371        // Searchable
4372
rowVal[9] = s2b("true"); // Unsignable
4373
rowVal[10] = s2b("false"); // Fixed Prec Scale
4374
rowVal[11] = s2b("true"); // Auto Increment
4375
rowVal[12] = s2b("MEDIUMINT"); // Locale Type Name
4376
rowVal[13] = s2b("0"); // Minimum Scale
4377
rowVal[14] = s2b("0"); // Maximum Scale
4378
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4379
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4380
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4381
tuples.add(rowVal);
4382
4383        /*
4384         * MySQL Type: SMALLINT
4385         * JDBC Type: SMALLINT
4386         */

4387        rowVal = new byte[18][];
4388        rowVal[0] = s2b("SMALLINT");
4389        rowVal[1] = Integer.toString(java.sql.Types.SMALLINT).getBytes();
4390
4391        // JDBC Data type
4392
rowVal[2] = s2b("5"); // Precision
4393
rowVal[3] = s2b(""); // Literal Prefix
4394
rowVal[4] = s2b(""); // Literal Suffix
4395
rowVal[5] = s2b("[(M)] [UNSIGNED] [ZEROFILL]"); // Create Params
4396
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4397                           .getBytes();
4398
4399        // Nullable
4400
rowVal[7] = s2b("false"); // Case Sensitive
4401
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4402                           .getBytes();
4403
4404        // Searchable
4405
rowVal[9] = s2b("true"); // Unsignable
4406
rowVal[10] = s2b("false"); // Fixed Prec Scale
4407
rowVal[11] = s2b("true"); // Auto Increment
4408
rowVal[12] = s2b("SMALLINT"); // Locale Type Name
4409
rowVal[13] = s2b("0"); // Minimum Scale
4410
rowVal[14] = s2b("0"); // Maximum Scale
4411
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4412
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4413
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4414
tuples.add(rowVal);
4415
4416        /*
4417         * MySQL Type: DOUBLE
4418         * JDBC Type: FLOAT (is really an alias for DOUBLE from JDBC's perspective)
4419         */

4420        rowVal = new byte[18][];
4421        rowVal[0] = s2b("DOUBLE");
4422        rowVal[1] = Integer.toString(java.sql.Types.FLOAT).getBytes();
4423
4424        // JDBC Data type
4425
rowVal[2] = s2b("17"); // Precision
4426
rowVal[3] = s2b(""); // Literal Prefix
4427
rowVal[4] = s2b(""); // Literal Suffix
4428
rowVal[5] = s2b("[(M,D)] [ZEROFILL]"); // Create Params
4429
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4430                           .getBytes();
4431
4432        // Nullable
4433
rowVal[7] = s2b("false"); // Case Sensitive
4434
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4435                           .getBytes();
4436
4437        // Searchable
4438
rowVal[9] = s2b("false"); // Unsignable
4439
rowVal[10] = s2b("false"); // Fixed Prec Scale
4440
rowVal[11] = s2b("true"); // Auto Increment
4441
rowVal[12] = s2b("DOUBLE"); // Locale Type Name
4442
rowVal[13] = s2b("-308"); // Minimum Scale
4443
rowVal[14] = s2b("308"); // Maximum Scale
4444
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4445
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4446
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4447
tuples.add(rowVal);
4448
4449        /*
4450         * MySQL Type: FLOAT
4451         * JDBC Type: REAL (this is the SINGLE PERCISION floating point type)
4452         */

4453        rowVal = new byte[18][];
4454        rowVal[0] = s2b("FLOAT");
4455        rowVal[1] = Integer.toString(java.sql.Types.REAL).getBytes();
4456
4457        // JDBC Data type
4458
rowVal[2] = s2b("10"); // Precision
4459
rowVal[3] = s2b(""); // Literal Prefix
4460
rowVal[4] = s2b(""); // Literal Suffix
4461
rowVal[5] = s2b("[(M,D)] [ZEROFILL]"); // Create Params
4462
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4463                           .getBytes();
4464
4465        // Nullable
4466
rowVal[7] = s2b("false"); // Case Sensitive
4467
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4468                           .getBytes();
4469
4470        // Searchable
4471
rowVal[9] = s2b("false"); // Unsignable
4472
rowVal[10] = s2b("false"); // Fixed Prec Scale
4473
rowVal[11] = s2b("true"); // Auto Increment
4474
rowVal[12] = s2b("FLOAT"); // Locale Type Name
4475
rowVal[13] = s2b("-38"); // Minimum Scale
4476
rowVal[14] = s2b("38"); // Maximum Scale
4477
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4478
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4479
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4480
tuples.add(rowVal);
4481
4482        /*
4483         * MySQL Type: DOUBLE
4484         * JDBC Type: DOUBLE
4485         */

4486        rowVal = new byte[18][];
4487        rowVal[0] = s2b("DOUBLE");
4488        rowVal[1] = Integer.toString(java.sql.Types.DOUBLE).getBytes();
4489
4490        // JDBC Data type
4491
rowVal[2] = s2b("17"); // Precision
4492
rowVal[3] = s2b(""); // Literal Prefix
4493
rowVal[4] = s2b(""); // Literal Suffix
4494
rowVal[5] = s2b("[(M,D)] [ZEROFILL]"); // Create Params
4495
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4496                           .getBytes();
4497
4498        // Nullable
4499
rowVal[7] = s2b("false"); // Case Sensitive
4500
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4501                           .getBytes();
4502
4503        // Searchable
4504
rowVal[9] = s2b("false"); // Unsignable
4505
rowVal[10] = s2b("false"); // Fixed Prec Scale
4506
rowVal[11] = s2b("true"); // Auto Increment
4507
rowVal[12] = s2b("DOUBLE"); // Locale Type Name
4508
rowVal[13] = s2b("-308"); // Minimum Scale
4509
rowVal[14] = s2b("308"); // Maximum Scale
4510
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4511
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4512
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4513
tuples.add(rowVal);
4514
4515        /*
4516         * MySQL Type: DOUBLE PRECISION
4517         * JDBC Type: DOUBLE
4518         */

4519        rowVal = new byte[18][];
4520        rowVal[0] = s2b("DOUBLE PRECISION");
4521        rowVal[1] = Integer.toString(java.sql.Types.DOUBLE).getBytes();
4522
4523        // JDBC Data type
4524
rowVal[2] = s2b("17"); // Precision
4525
rowVal[3] = s2b(""); // Literal Prefix
4526
rowVal[4] = s2b(""); // Literal Suffix
4527
rowVal[5] = s2b("[(M,D)] [ZEROFILL]"); // Create Params
4528
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4529                           .getBytes();
4530
4531        // Nullable
4532
rowVal[7] = s2b("false"); // Case Sensitive
4533
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4534                           .getBytes();
4535
4536        // Searchable
4537
rowVal[9] = s2b("false"); // Unsignable
4538
rowVal[10] = s2b("false"); // Fixed Prec Scale
4539
rowVal[11] = s2b("true"); // Auto Increment
4540
rowVal[12] = s2b("DOUBLE PRECISION"); // Locale Type Name
4541
rowVal[13] = s2b("-308"); // Minimum Scale
4542
rowVal[14] = s2b("308"); // Maximum Scale
4543
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4544
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4545
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4546
tuples.add(rowVal);
4547
4548        /*
4549         * MySQL Type: REAL (does not map to Types.REAL)
4550         * JDBC Type: DOUBLE
4551         */

4552        rowVal = new byte[18][];
4553        rowVal[0] = s2b("REAL");
4554        rowVal[1] = Integer.toString(java.sql.Types.DOUBLE).getBytes();
4555
4556        // JDBC Data type
4557
rowVal[2] = s2b("17"); // Precision
4558
rowVal[3] = s2b(""); // Literal Prefix
4559
rowVal[4] = s2b(""); // Literal Suffix
4560
rowVal[5] = s2b("[(M,D)] [ZEROFILL]"); // Create Params
4561
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4562                           .getBytes();
4563
4564        // Nullable
4565
rowVal[7] = s2b("false"); // Case Sensitive
4566
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4567                           .getBytes();
4568
4569        // Searchable
4570
rowVal[9] = s2b("false"); // Unsignable
4571
rowVal[10] = s2b("false"); // Fixed Prec Scale
4572
rowVal[11] = s2b("true"); // Auto Increment
4573
rowVal[12] = s2b("REAL"); // Locale Type Name
4574
rowVal[13] = s2b("-308"); // Minimum Scale
4575
rowVal[14] = s2b("308"); // Maximum Scale
4576
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4577
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4578
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4579
tuples.add(rowVal);
4580
4581        /*
4582         * MySQL Type: VARCHAR
4583         * JDBC Type: VARCHAR
4584         */

4585        rowVal = new byte[18][];
4586        rowVal[0] = s2b("VARCHAR");
4587        rowVal[1] = Integer.toString(java.sql.Types.VARCHAR).getBytes();
4588
4589        // JDBC Data type
4590
rowVal[2] = s2b("255"); // Precision
4591
rowVal[3] = s2b("'"); // Literal Prefix
4592
rowVal[4] = s2b("'"); // Literal Suffix
4593
rowVal[5] = s2b("(M)"); // Create Params
4594
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4595                           .getBytes();
4596
4597        // Nullable
4598
rowVal[7] = s2b("false"); // Case Sensitive
4599
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4600                           .getBytes();
4601
4602        // Searchable
4603
rowVal[9] = s2b("false"); // Unsignable
4604
rowVal[10] = s2b("false"); // Fixed Prec Scale
4605
rowVal[11] = s2b("false"); // Auto Increment
4606
rowVal[12] = s2b("VARCHAR"); // Locale Type Name
4607
rowVal[13] = s2b("0"); // Minimum Scale
4608
rowVal[14] = s2b("0"); // Maximum Scale
4609
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4610
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4611
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4612
tuples.add(rowVal);
4613
4614        /*
4615         * MySQL Type: ENUM
4616         * JDBC Type: VARCHAR
4617         */

4618        rowVal = new byte[18][];
4619        rowVal[0] = s2b("ENUM");
4620        rowVal[1] = Integer.toString(java.sql.Types.VARCHAR).getBytes();
4621
4622        // JDBC Data type
4623
rowVal[2] = s2b("65535"); // Precision
4624
rowVal[3] = s2b("'"); // Literal Prefix
4625
rowVal[4] = s2b("'"); // Literal Suffix
4626
rowVal[5] = s2b(""); // Create Params
4627
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4628                           .getBytes();
4629
4630        // Nullable
4631
rowVal[7] = s2b("false"); // Case Sensitive
4632
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4633                           .getBytes();
4634
4635        // Searchable
4636
rowVal[9] = s2b("false"); // Unsignable
4637
rowVal[10] = s2b("false"); // Fixed Prec Scale
4638
rowVal[11] = s2b("false"); // Auto Increment
4639
rowVal[12] = s2b("ENUM"); // Locale Type Name
4640
rowVal[13] = s2b("0"); // Minimum Scale
4641
rowVal[14] = s2b("0"); // Maximum Scale
4642
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4643
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4644
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4645
tuples.add(rowVal);
4646
4647        /*
4648         * MySQL Type: SET
4649         * JDBC Type: VARCHAR
4650         */

4651        rowVal = new byte[18][];
4652        rowVal[0] = s2b("SET");
4653        rowVal[1] = Integer.toString(java.sql.Types.VARCHAR).getBytes();
4654
4655        // JDBC Data type
4656
rowVal[2] = s2b("64"); // Precision
4657
rowVal[3] = s2b("'"); // Literal Prefix
4658
rowVal[4] = s2b("'"); // Literal Suffix
4659
rowVal[5] = s2b(""); // Create Params
4660
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4661                           .getBytes();
4662
4663        // Nullable
4664
rowVal[7] = s2b("false"); // Case Sensitive
4665
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4666                           .getBytes();
4667
4668        // Searchable
4669
rowVal[9] = s2b("false"); // Unsignable
4670
rowVal[10] = s2b("false"); // Fixed Prec Scale
4671
rowVal[11] = s2b("false"); // Auto Increment
4672
rowVal[12] = s2b("SET"); // Locale Type Name
4673
rowVal[13] = s2b("0"); // Minimum Scale
4674
rowVal[14] = s2b("0"); // Maximum Scale
4675
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4676
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4677
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4678
tuples.add(rowVal);
4679
4680        /*
4681         * MySQL Type: DATE
4682         * JDBC Type: DATE
4683         */

4684        rowVal = new byte[18][];
4685        rowVal[0] = s2b("DATE");
4686        rowVal[1] = Integer.toString(java.sql.Types.DATE).getBytes();
4687
4688        // JDBC Data type
4689
rowVal[2] = s2b("0"); // Precision
4690
rowVal[3] = s2b("'"); // Literal Prefix
4691
rowVal[4] = s2b("'"); // Literal Suffix
4692
rowVal[5] = s2b(""); // Create Params
4693
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4694                           .getBytes();
4695
4696        // Nullable
4697
rowVal[7] = s2b("false"); // Case Sensitive
4698
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4699                           .getBytes();
4700
4701        // Searchable
4702
rowVal[9] = s2b("false"); // Unsignable
4703
rowVal[10] = s2b("false"); // Fixed Prec Scale
4704
rowVal[11] = s2b("false"); // Auto Increment
4705
rowVal[12] = s2b("DATE"); // Locale Type Name
4706
rowVal[13] = s2b("0"); // Minimum Scale
4707
rowVal[14] = s2b("0"); // Maximum Scale
4708
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4709
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4710
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4711
tuples.add(rowVal);
4712
4713        /*
4714         * MySQL Type: TIME
4715         * JDBC Type: TIME
4716         */

4717        rowVal = new byte[18][];
4718        rowVal[0] = s2b("TIME");
4719        rowVal[1] = Integer.toString(java.sql.Types.TIME).getBytes();
4720
4721        // JDBC Data type
4722
rowVal[2] = s2b("0"); // Precision
4723
rowVal[3] = s2b("'"); // Literal Prefix
4724
rowVal[4] = s2b("'"); // Literal Suffix
4725
rowVal[5] = s2b(""); // Create Params
4726
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4727                           .getBytes();
4728
4729        // Nullable
4730
rowVal[7] = s2b("false"); // Case Sensitive
4731
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4732                           .getBytes();
4733
4734        // Searchable
4735
rowVal[9] = s2b("false"); // Unsignable
4736
rowVal[10] = s2b("false"); // Fixed Prec Scale
4737
rowVal[11] = s2b("false"); // Auto Increment
4738
rowVal[12] = s2b("TIME"); // Locale Type Name
4739
rowVal[13] = s2b("0"); // Minimum Scale
4740
rowVal[14] = s2b("0"); // Maximum Scale
4741
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4742
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4743
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4744
tuples.add(rowVal);
4745
4746        /*
4747         * MySQL Type: DATETIME
4748         * JDBC Type: TIMESTAMP
4749         */

4750        rowVal = new byte[18][];
4751        rowVal[0] = s2b("DATETIME");
4752        rowVal[1] = Integer.toString(java.sql.Types.TIMESTAMP).getBytes();
4753
4754        // JDBC Data type
4755
rowVal[2] = s2b("0"); // Precision
4756
rowVal[3] = s2b("'"); // Literal Prefix
4757
rowVal[4] = s2b("'"); // Literal Suffix
4758
rowVal[5] = s2b(""); // Create Params
4759
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4760                           .getBytes();
4761
4762        // Nullable
4763
rowVal[7] = s2b("false"); // Case Sensitive
4764
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4765                           .getBytes();
4766
4767        // Searchable
4768
rowVal[9] = s2b("false"); // Unsignable
4769
rowVal[10] = s2b("false"); // Fixed Prec Scale
4770
rowVal[11] = s2b("false"); // Auto Increment
4771
rowVal[12] = s2b("DATETIME"); // Locale Type Name
4772
rowVal[13] = s2b("0"); // Minimum Scale
4773
rowVal[14] = s2b("0"); // Maximum Scale
4774
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4775
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4776
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4777
tuples.add(rowVal);
4778
4779        /*
4780         * MySQL Type: TIMESTAMP
4781         * JDBC Type: TIMESTAMP
4782         */

4783        rowVal = new byte[18][];
4784        rowVal[0] = s2b("TIMESTAMP");
4785        rowVal[1] = Integer.toString(java.sql.Types.TIMESTAMP).getBytes();
4786
4787        // JDBC Data type
4788
rowVal[2] = s2b("0"); // Precision
4789
rowVal[3] = s2b("'"); // Literal Prefix
4790
rowVal[4] = s2b("'"); // Literal Suffix
4791
rowVal[5] = s2b("[(M)]"); // Create Params
4792
rowVal[6] = Integer.toString(java.sql.DatabaseMetaData.typeNullable)
4793                           .getBytes();
4794
4795        // Nullable
4796
rowVal[7] = s2b("false"); // Case Sensitive
4797
rowVal[8] = Integer.toString(java.sql.DatabaseMetaData.typeSearchable)
4798                           .getBytes();
4799
4800        // Searchable
4801
rowVal[9] = s2b("false"); // Unsignable
4802
rowVal[10] = s2b("false"); // Fixed Prec Scale
4803
rowVal[11] = s2b("false"); // Auto Increment
4804
rowVal[12] = s2b("TIMESTAMP"); // Locale Type Name
4805
rowVal[13] = s2b("0"); // Minimum Scale
4806
rowVal[14] = s2b("0"); // Maximum Scale
4807
rowVal[15] = s2b("0"); // SQL Data Type (not used)
4808
rowVal[16] = s2b("0"); // SQL DATETIME SUB (not used)
4809
rowVal[17] = s2b("10"); // NUM_PREC_RADIX (2 or 10)
4810
tuples.add(rowVal);
4811
4812        return buildResultSet(fields, tuples);
4813    }
4814
4815    /**
4816     * JDBC 2.0 Get a description of the user-defined types defined in a
4817     * particular schema. Schema specific UDTs may have type JAVA_OBJECT,
4818     * STRUCT, or DISTINCT.
4819     *
4820     * <P>
4821     * Only types matching the catalog, schema, type name and type criteria
4822     * are returned. They are ordered by DATA_TYPE, TYPE_SCHEM and
4823     * TYPE_NAME. The type name parameter may be a fully qualified name. In
4824     * this case, the catalog and schemaPattern parameters are ignored.
4825     * </p>
4826     *
4827     * <P>
4828     * Each type description has the following columns:
4829     *
4830     * <OL>
4831     * <li>
4832     * <B>TYPE_CAT</B> String => the type's catalog (may be null)
4833     * </li>
4834     * <li>
4835     * <B>TYPE_SCHEM</B> String => type's schema (may be null)
4836     * </li>
4837     * <li>
4838     * <B>TYPE_NAME</B> String => type name
4839     * </li>
4840     * <li>
4841     * <B>CLASS_NAME</B> String => Java class name
4842     * </li>
4843     * <li>
4844     * <B>DATA_TYPE</B> String => type value defined in java.sql.Types. One
4845     * of JAVA_OBJECT, STRUCT, or DISTINCT
4846     * </li>
4847     * <li>
4848     * <B>REMARKS</B> String => explanatory comment on the type
4849     * </li>
4850     * </ol>
4851     * </p>
4852     *
4853     * <P>
4854     * <B>Note:</B> If the driver does not support UDTs then an empty result
4855     * set is returned.
4856     * </p>
4857     *
4858     * @param catalog a catalog name; "" retrieves those without a catalog;
4859     * null means drop catalog name from the selection criteria
4860     * @param schemaPattern a schema name pattern; "" retrieves those without a
4861     * schema
4862     * @param typeNamePattern a type name pattern; may be a fully qualified
4863     * name
4864     * @param types a list of user-named types to include (JAVA_OBJECT, STRUCT,
4865     * or DISTINCT); null returns all types
4866     *
4867     * @return ResultSet - each row is a type description
4868     *
4869     * @exception SQLException if a database-access error occurs.
4870     */

4871    public java.sql.ResultSet JavaDoc getUDTs(String JavaDoc catalog, String JavaDoc schemaPattern,
4872        String JavaDoc typeNamePattern, int[] types) throws SQLException JavaDoc {
4873        Field[] fields = new Field[6];
4874        fields[0] = new Field("", "TYPE_CAT", Types.VARCHAR, 32);
4875        fields[1] = new Field("", "TYPE_SCHEM", Types.VARCHAR, 32);
4876        fields[2] = new Field("", "TYPE_NAME", Types.VARCHAR, 32);
4877        fields[3] = new Field("", "CLASS_NAME", Types.VARCHAR, 32);
4878        fields[4] = new Field("", "DATA_TYPE", Types.VARCHAR, 32);
4879        fields[5] = new Field("", "REMARKS", Types.VARCHAR, 32);
4880
4881        ArrayList JavaDoc tuples = new ArrayList JavaDoc();
4882
4883        return buildResultSet(fields, tuples);
4884    }
4885
4886    /**
4887     * What's the url for this database?
4888     *
4889     * @return the url or null if it can't be generated
4890     *
4891     * @throws java.sql.SQLException DOCUMENT ME!
4892     */

4893    public String JavaDoc getURL() throws java.sql.SQLException JavaDoc {
4894        return this.conn.getURL();
4895    }
4896
4897    /**
4898     * What's our user name as known to the database?
4899     *
4900     * @return our database user name
4901     *
4902     * @throws java.sql.SQLException DOCUMENT ME!
4903     */

4904    public String JavaDoc getUserName() throws java.sql.SQLException JavaDoc {
4905        if (this.conn.useHostsInPrivileges()) {
4906            Statement stmt = null;
4907            ResultSet rs = null;
4908
4909            try {
4910                stmt = this.conn.createStatement();
4911                
4912                if (stmt.getMaxRows() != 0) {
4913                    stmt.setMaxRows(0);
4914                }
4915                
4916                rs = stmt.executeQuery("SELECT USER()");
4917                rs.next();
4918
4919                return rs.getString(1);
4920            } finally {
4921                if (rs != null) {
4922                    try {
4923                        rs.close();
4924                    } catch (Exception JavaDoc ex) {
4925                        AssertionFailedException.shouldNotHappen(ex);
4926                    }
4927
4928                    rs = null;
4929                }
4930
4931                if (stmt != null) {
4932                    try {
4933                        stmt.close();
4934                    } catch (Exception JavaDoc ex) {
4935                        AssertionFailedException.shouldNotHappen(ex);
4936                    }
4937
4938                    stmt = null;
4939                }
4940            }
4941        } else {
4942            return this.conn.getUser();
4943        }
4944    }
4945
4946    /**
4947     * Get a description of a table's columns that are automatically updated
4948     * when any value in a row is updated. They are unordered.
4949     *
4950     * <P>
4951     * Each column description has the following columns:
4952     *
4953     * <OL>
4954     * <li>
4955     * <B>SCOPE</B> short => is not used
4956     * </li>
4957     * <li>
4958     * <B>COLUMN_NAME</B> String => column name
4959     * </li>
4960     * <li>
4961     * <B>DATA_TYPE</B> short => SQL data type from java.sql.Types
4962     * </li>
4963     * <li>
4964     * <B>TYPE_NAME</B> String => Data source dependent type name
4965     * </li>
4966     * <li>
4967     * <B>COLUMN_SIZE</B> int => precision
4968     * </li>
4969     * <li>
4970     * <B>BUFFER_LENGTH</B> int => length of column value in bytes
4971     * </li>
4972     * <li>
4973     * <B>DECIMAL_DIGITS</B> short => scale
4974     * </li>
4975     * <li>
4976     * <B>PSEUDO_COLUMN</B> short => is this a pseudo column like an Oracle
4977     * ROWID
4978     *
4979     * <UL>
4980     * <li>
4981     * versionColumnUnknown - may or may not be pseudo column
4982     * </li>
4983     * <li>
4984     * versionColumnNotPseudo - is NOT a pseudo column
4985     * </li>
4986     * <li>
4987     * versionColumnPseudo - is a pseudo column
4988     * </li>
4989     * </ul>
4990     *
4991     * </li>
4992     * </ol>
4993     * </p>
4994     *
4995     * @param catalog a catalog name; "" retrieves those without a catalog
4996     * @param schema a schema name; "" retrieves those without a schema
4997     * @param table a table name
4998     *
4999     * @return ResultSet each row is a column description
5000     *
5001     * @throws java.sql.SQLException DOCUMENT ME!
5002     */

5003    public java.sql.ResultSet JavaDoc getVersionColumns(String JavaDoc catalog, String JavaDoc schema,
5004        String JavaDoc table) throws java.sql.SQLException JavaDoc {
5005        Field[] fields = new Field[8];
5006        fields[0] = new Field("", "SCOPE", Types.SMALLINT, 5);
5007        fields[1] = new Field("", "COLUMN_NAME", Types.CHAR, 32);
5008        fields[2] = new Field("", "DATA_TYPE", Types.SMALLINT, 5);
5009        fields[3] = new Field("", "TYPE_NAME", Types.CHAR, 16);
5010        fields[4] = new Field("", "COLUMN_SIZE", Types.CHAR, 16);
5011        fields[5] = new Field("", "BUFFER_LENGTH", Types.CHAR, 16);
5012        fields[6] = new Field("", "DECIMAL_DIGITS", Types.CHAR, 16);
5013        fields[7] = new Field("", "PSEUDO_COLUMN", Types.SMALLINT, 5);
5014
5015        return buildResultSet(fields, new ArrayList JavaDoc());
5016
5017        // do TIMESTAMP columns count?
5018
}
5019
5020    /**
5021     * Can all the procedures returned by getProcedures be called by the
5022     * current user?
5023     *
5024     * @return true if so
5025     *
5026     * @throws java.sql.SQLException DOCUMENT ME!
5027     */

5028    public boolean allProceduresAreCallable() throws java.sql.SQLException JavaDoc {
5029        return false;
5030    }
5031
5032    /**
5033     * Can all the tables returned by getTable be SELECTed by the current user?
5034     *
5035     * @return true if so
5036     *
5037     * @throws java.sql.SQLException DOCUMENT ME!
5038     */

5039    public boolean allTablesAreSelectable() throws java.sql.SQLException JavaDoc {
5040        return false;
5041    }
5042
5043    /**
5044     * Does a data definition statement within a transaction force the
5045     * transaction to commit?
5046     *
5047     * @return true if so
5048     *
5049     * @throws java.sql.SQLException DOCUMENT ME!
5050     */

5051    public boolean dataDefinitionCausesTransactionCommit()
5052        throws java.sql.SQLException JavaDoc {
5053        return true;
5054    }
5055
5056    /**
5057     * Is a data definition statement within a transaction ignored?
5058     *
5059     * @return true if so
5060     *
5061     * @throws java.sql.SQLException DOCUMENT ME!
5062     */

5063    public boolean dataDefinitionIgnoredInTransactions()
5064        throws java.sql.SQLException JavaDoc {
5065        return false;
5066    }
5067
5068    /**
5069     * JDBC 2.0 Determine whether or not a visible row delete can be detected
5070     * by calling ResultSet.rowDeleted(). If deletesAreDetected() returns
5071     * false, then deleted rows are removed from the result set.
5072     *
5073     * @param type set type, i.e. ResultSet.TYPE_XXX
5074     *
5075     * @return true if changes are detected by the resultset type
5076     *
5077     * @exception SQLException if a database-access error occurs.
5078     */

5079    public boolean deletesAreDetected(int type) throws SQLException JavaDoc {
5080        return false;
5081    }
5082
5083    /**
5084     * Did getMaxRowSize() include LONGVARCHAR and LONGVARBINARY blobs?
5085     *
5086     * @return true if so
5087     *
5088     * @throws java.sql.SQLException DOCUMENT ME!
5089     */

5090    public boolean doesMaxRowSizeIncludeBlobs() throws java.sql.SQLException JavaDoc {
5091        return true;
5092    }
5093
5094    /**
5095     * Extracts foreign key info for one table.
5096     *
5097     * @param rows the list of rows to add to
5098     * @param rs the result set from 'SHOW CREATE TABLE'
5099     * @param catalog the database name
5100     *
5101     * @return the list of rows with new rows added
5102     *
5103     * @throws SQLException if a database access error occurs
5104     */

5105    public List JavaDoc extractForeignKeyForTable(ArrayList JavaDoc rows,
5106        java.sql.ResultSet JavaDoc rs, String JavaDoc catalog) throws SQLException JavaDoc {
5107        byte[][] row = new byte[3][];
5108        row[0] = rs.getBytes(1);
5109        row[1] = s2b(SUPPORTS_FK);
5110
5111        String JavaDoc createTableString = rs.getString(2);
5112        StringTokenizer JavaDoc lineTokenizer = new StringTokenizer JavaDoc(createTableString,
5113                "\n");
5114        StringBuffer JavaDoc commentBuf = new StringBuffer JavaDoc("comment; ");
5115        boolean firstTime = true;
5116
5117        while (lineTokenizer.hasMoreTokens()) {
5118            String JavaDoc line = lineTokenizer.nextToken().trim();
5119
5120            String JavaDoc constraintName = null;
5121
5122            if (StringUtils.startsWithIgnoreCase(line, "CONSTRAINT")) {
5123                boolean usingBackTicks = true;
5124                int beginPos = line.indexOf("`");
5125
5126                if (beginPos == -1) {
5127                    beginPos = line.indexOf("\"");
5128                    usingBackTicks = false;
5129                }
5130
5131                if (beginPos != -1) {
5132                    int endPos = -1;
5133
5134                    if (usingBackTicks) {
5135                        endPos = line.indexOf("`", beginPos + 1);
5136                    } else {
5137                        endPos = line.indexOf("\"", beginPos + 1);
5138                    }
5139
5140                    if (endPos != -1) {
5141                        constraintName = line.substring(beginPos + 1, endPos);
5142                        line = line.substring(endPos + 1, line.length()).trim();
5143                    }
5144                }
5145            }
5146
5147            if (line.startsWith("FOREIGN KEY")) {
5148                if (line.endsWith(",")) {
5149                    line = line.substring(0, line.length() - 1);
5150                }
5151
5152                // Remove all back-ticks
5153
int lineLength = line.length();
5154                StringBuffer JavaDoc lineBuf = new StringBuffer JavaDoc(lineLength);
5155
5156                for (int i = 0; i < lineLength; i++) {
5157                    char c = line.charAt(i);
5158
5159                    if (c != '`') {
5160                        lineBuf.append(c);
5161                    }
5162                }
5163
5164                line = lineBuf.toString();
5165
5166                StringTokenizer JavaDoc keyTokens = new StringTokenizer JavaDoc(line, "()",
5167                        false);
5168                keyTokens.nextToken(); // eat 'FOREIGN KEY'
5169

5170                String JavaDoc localColumnNamesString = keyTokens.nextToken();
5171                String JavaDoc referCatalogTableString = keyTokens.nextToken();
5172
5173                StringTokenizer JavaDoc referSchemaTable = new StringTokenizer JavaDoc(referCatalogTableString
5174                        .trim(), " .");
5175                String JavaDoc referColumnNamesString = keyTokens.nextToken();
5176                referSchemaTable.nextToken(); //discard the REFERENCES token
5177

5178                int numTokensLeft = referSchemaTable.countTokens();
5179
5180                String JavaDoc referCatalog = null;
5181                String JavaDoc referTable = null;
5182
5183                if (numTokensLeft == 2) {
5184                    // some versions of MySQL don't report the database name
5185
referCatalog = referSchemaTable.nextToken();
5186                    referTable = referSchemaTable.nextToken();
5187                } else {
5188                    referTable = referSchemaTable.nextToken();
5189                    referCatalog = catalog;
5190                }
5191
5192                if (!firstTime) {
5193                    commentBuf.append("; ");
5194                } else {
5195                    firstTime = false;
5196                }
5197
5198                if (constraintName != null) {
5199                    commentBuf.append(constraintName);
5200                } else {
5201                    commentBuf.append("not_available");
5202                }
5203
5204                commentBuf.append("(");
5205                commentBuf.append(localColumnNamesString);
5206                commentBuf.append(") REFER ");
5207                commentBuf.append(referCatalog);
5208                commentBuf.append("/");
5209                commentBuf.append(referTable);
5210                commentBuf.append("(");
5211                commentBuf.append(referColumnNamesString);
5212                commentBuf.append(")");
5213
5214                int lastParenIndex = line.lastIndexOf(")");
5215
5216                if (lastParenIndex != (line.length() - 1)) {
5217                    String JavaDoc cascadeOptions = cascadeOptions = line.substring(lastParenIndex
5218                                + 1);
5219                    commentBuf.append(" ");
5220                    commentBuf.append(cascadeOptions);
5221                }
5222            }
5223        }
5224
5225        row[2] = s2b(commentBuf.toString());
5226        rows.add(row);
5227
5228        return rows;
5229    }
5230
5231    /**
5232     * Creates a result set similar enough to 'SHOW TABLE STATUS' to allow the
5233     * same code to work on extracting the foreign key data
5234     *
5235     * @param conn the database connection to use
5236     * @param metadata the DatabaseMetaData instance calling this method
5237     * @param catalog the database name to extract foreign key info for
5238     * @param tableName the table to extract foreign key info for
5239     *
5240     * @return A result set that has the structure of 'show table status'
5241     *
5242     * @throws SQLException if a database access error occurs.
5243     */

5244    public ResultSet extractForeignKeyFromCreateTable(
5245        java.sql.Connection JavaDoc conn, java.sql.DatabaseMetaData JavaDoc metadata,
5246        String JavaDoc catalog, String JavaDoc tableName) throws SQLException JavaDoc {
5247        ArrayList JavaDoc tableList = new ArrayList JavaDoc();
5248        java.sql.ResultSet JavaDoc rs = null;
5249        java.sql.Statement JavaDoc stmt = null;
5250
5251        if (tableName != null) {
5252            tableList.add(tableName);
5253        } else {
5254            try {
5255                rs = metadata.getTables(catalog, "", "%",
5256                        new String JavaDoc[] { "TABLE" });
5257
5258                while (rs.next()) {
5259                    tableList.add(rs.getString("TABLE_NAME"));
5260                }
5261            } finally {
5262                if (rs != null) {
5263                    rs.close();
5264                }
5265
5266                rs = null;
5267            }
5268        }
5269
5270        ArrayList JavaDoc rows = new ArrayList JavaDoc();
5271        Field[] fields = new Field[3];
5272        fields[0] = new Field("", "Name", Types.CHAR, Integer.MAX_VALUE);
5273        fields[1] = new Field("", "Type", Types.CHAR, 255);
5274        fields[2] = new Field("", "Comment", Types.CHAR, Integer.MAX_VALUE);
5275
5276        int numTables = tableList.size();
5277
5278        try {
5279            stmt = conn.createStatement();
5280            
5281            if (stmt.getMaxRows() != 0) {
5282                stmt.setMaxRows(0);
5283            }
5284
5285            for (int i = 0; i < numTables; i++) {
5286                String JavaDoc tableToExtract = (String JavaDoc) tableList.get(i);
5287
5288                String JavaDoc query = new StringBuffer JavaDoc("SHOW CREATE TABLE ").append(
5289                        "`").append(catalog).append("`.`").append(tableToExtract)
5290                                                                     .append("`")
5291                                                                     .toString();
5292                rs = stmt.executeQuery(query);
5293
5294                while (rs.next()) {
5295                    extractForeignKeyForTable(rows, rs, catalog);
5296                }
5297            }
5298        } finally {
5299            if (rs != null) {
5300                rs.close();
5301            }
5302
5303            rs = null;
5304
5305            if (stmt != null) {
5306                stmt.close();
5307            }
5308
5309            stmt = null;
5310        }
5311
5312        return buildResultSet(fields, rows);
5313    }
5314
5315    /**
5316     * JDBC 2.0 Determine whether or not a visible row insert can be detected
5317     * by calling ResultSet.rowInserted().
5318     *
5319     * @param type set type, i.e. ResultSet.TYPE_XXX
5320     *
5321     * @return true if changes are detected by the resultset type
5322     *
5323     * @exception SQLException if a database-access error occurs.
5324     */

5325    public boolean insertsAreDetected(int type) throws SQLException JavaDoc {
5326        return false;
5327    }
5328
5329    /**
5330     * @see DatabaseMetaData#locatorsUpdateCopy()
5331     */

5332    public boolean locatorsUpdateCopy() throws SQLException JavaDoc {
5333        return true;
5334    }
5335
5336    /**
5337     * Are concatenations between NULL and non-NULL values NULL? A JDBC
5338     * compliant driver always returns true.
5339     *
5340     * @return true if so
5341     *
5342     * @throws java.sql.SQLException DOCUMENT ME!
5343     */

5344    public boolean nullPlusNonNullIsNull() throws java.sql.SQLException JavaDoc {
5345        return true;
5346    }
5347
5348    /**
5349     * Are NULL values sorted at the end regardless of sort order?
5350     *
5351     * @return true if so
5352     *
5353     * @throws java.sql.SQLException DOCUMENT ME!
5354     */

5355    public boolean nullsAreSortedAtEnd() throws java.sql.SQLException JavaDoc {
5356        return false;
5357    }
5358
5359    /**
5360     * Are NULL values sorted at the start regardless of sort order?
5361     *
5362     * @return true if so
5363     *
5364     * @throws java.sql.SQLException DOCUMENT ME!
5365     */

5366    public boolean nullsAreSortedAtStart() throws java.sql.SQLException JavaDoc {
5367        if (this.conn.getIO().versionMeetsMinimum(4, 0, 2)
5368                && !this.conn.getIO().versionMeetsMinimum(4, 0, 11)) {
5369            return true;
5370        } else {
5371            return false;
5372        }
5373    }
5374
5375    /**
5376     * Are NULL values sorted high?
5377     *
5378     * @return true if so
5379     *
5380     * @throws java.sql.SQLException DOCUMENT ME!
5381     */

5382    public boolean nullsAreSortedHigh() throws java.sql.SQLException JavaDoc {
5383        return false;
5384    }
5385
5386    /**
5387     * Are NULL values sorted low?
5388     *
5389     * @return true if so
5390     *
5391     * @throws java.sql.SQLException DOCUMENT ME!
5392     */

5393    public boolean nullsAreSortedLow() throws java.sql.SQLException JavaDoc {
5394        return !nullsAreSortedHigh();
5395    }
5396
5397    /**
5398     * DOCUMENT ME!
5399     *
5400     * @param type DOCUMENT ME!
5401     *
5402     * @return DOCUMENT ME!
5403     *
5404     * @throws SQLException DOCUMENT ME!
5405     */

5406    public boolean othersDeletesAreVisible(int type) throws SQLException JavaDoc {
5407        return false;
5408    }
5409
5410    /**
5411     * DOCUMENT ME!
5412     *
5413     * @param type DOCUMENT ME!
5414     *
5415     * @return DOCUMENT ME!
5416     *
5417     * @throws SQLException DOCUMENT ME!
5418     */

5419    public boolean othersInsertsAreVisible(int type) throws SQLException JavaDoc {
5420        return false;
5421    }
5422
5423    /**
5424     * JDBC 2.0 Determine whether changes made by others are visible.
5425     *
5426     * @param type set type, i.e. ResultSet.TYPE_XXX
5427     *
5428     * @return true if changes are visible for the result set type
5429     *
5430     * @exception SQLException if a database-access error occurs.
5431     */

5432    public boolean othersUpdatesAreVisible(int type) throws SQLException JavaDoc {
5433        return false;
5434    }
5435
5436    /**
5437     * DOCUMENT ME!
5438     *
5439     * @param type DOCUMENT ME!
5440     *
5441     * @return DOCUMENT ME!
5442     *
5443     * @throws SQLException DOCUMENT ME!
5444     */

5445    public boolean ownDeletesAreVisible(int type) throws SQLException JavaDoc {
5446        return false;
5447    }
5448
5449    /**
5450     * DOCUMENT ME!
5451     *
5452     * @param type DOCUMENT ME!
5453     *
5454     * @return DOCUMENT ME!
5455     *
5456     * @throws SQLException DOCUMENT ME!
5457     */

5458    public boolean ownInsertsAreVisible(int type) throws SQLException JavaDoc {
5459        return false;
5460    }
5461
5462    /**
5463     * JDBC 2.0 Determine whether a result set's own changes visible.
5464     *
5465     * @param type set type, i.e. ResultSet.TYPE_XXX
5466     *
5467     * @return true if changes are visible for the result set type
5468     *
5469     * @exception SQLException if a database-access error occurs.
5470     */

5471    public boolean ownUpdatesAreVisible(int type) throws SQLException JavaDoc {
5472        return false;
5473    }
5474
5475    /**
5476     * Does the database store mixed case unquoted SQL identifiers in lower
5477     * case?
5478     *
5479     * @return true if so
5480     *
5481     * @throws java.sql.SQLException DOCUMENT ME!
5482     */

5483    public boolean storesLowerCaseIdentifiers() throws java.sql.SQLException JavaDoc {
5484        return false;
5485    }
5486
5487    /**
5488     * Does the database store mixed case quoted SQL identifiers in lower case?
5489     * A JDBC compliant driver will always return false.
5490     *
5491     * @return true if so
5492     *
5493     * @throws java.sql.SQLException DOCUMENT ME!
5494     */

5495    public boolean storesLowerCaseQuotedIdentifiers()
5496        throws java.sql.SQLException JavaDoc {
5497        return false;
5498    }
5499
5500    /**
5501     * Does the database store mixed case unquoted SQL identifiers in mixed
5502     * case?
5503     *
5504     * @return true if so
5505     *
5506     * @throws java.sql.SQLException DOCUMENT ME!
5507     */

5508    public boolean storesMixedCaseIdentifiers() throws java.sql.SQLException JavaDoc {
5509        return true;
5510    }
5511
5512    /**
5513     * Does the database store mixed case quoted SQL identifiers in mixed case?
5514     * A JDBC compliant driver will always return false.
5515     *
5516     * @return true if so
5517     *
5518     * @throws java.sql.SQLException DOCUMENT ME!
5519     */

5520    public boolean storesMixedCaseQuotedIdentifiers()
5521        throws java.sql.SQLException JavaDoc {
5522        return false;
5523    }
5524
5525    /**
5526     * Does the database store mixed case unquoted SQL identifiers in upper
5527     * case?
5528     *
5529     * @return true if so
5530     *
5531     * @throws java.sql.SQLException DOCUMENT ME!
5532     */

5533    public boolean storesUpperCaseIdentifiers() throws java.sql.SQLException JavaDoc {
5534        return false;
5535    }
5536
5537    /**
5538     * Does the database store mixed case quoted SQL identifiers in upper case?
5539     * A JDBC compliant driver will always return true.
5540     *
5541     * @return true if so
5542     *
5543     * @throws java.sql.SQLException DOCUMENT ME!
5544     */

5545    public boolean storesUpperCaseQuotedIdentifiers()
5546        throws java.sql.SQLException JavaDoc {
5547        return false;
5548    }
5549
5550    /**
5551     * Is the ANSI92 entry level SQL grammar supported? All JDBC compliant
5552     * drivers must return true.
5553     *
5554     * @return true if so
5555     *
5556     * @throws java.sql.SQLException DOCUMENT ME!
5557     */

5558    public boolean supportsANSI92EntryLevelSQL() throws java.sql.SQLException JavaDoc {
5559        return true;
5560    }
5561
5562    /**
5563     * Is the ANSI92 full SQL grammar supported?
5564     *
5565     * @return true if so
5566     *
5567     * @throws java.sql.SQLException DOCUMENT ME!
5568     */

5569    public boolean supportsANSI92FullSQL() throws java.sql.SQLException JavaDoc {
5570        return false;
5571    }
5572
5573    /**
5574     * Is the ANSI92 intermediate SQL grammar supported?
5575     *
5576     * @return true if so
5577     *
5578     * @throws java.sql.SQLException DOCUMENT ME!
5579     */

5580    public boolean supportsANSI92IntermediateSQL() throws java.sql.SQLException JavaDoc {
5581        return false;
5582    }
5583
5584    /**
5585     * Is "ALTER TABLE" with add column supported?
5586     *
5587     * @return true if so
5588     *
5589     * @throws java.sql.SQLException DOCUMENT ME!
5590     */

5591    public boolean supportsAlterTableWithAddColumn()
5592        throws java.sql.SQLException JavaDoc {
5593        return true;
5594    }
5595
5596    /**
5597     * Is "ALTER TABLE" with drop column supported?
5598     *
5599     * @return true if so
5600     *
5601     * @throws java.sql.SQLException DOCUMENT ME!
5602     */

5603    public boolean supportsAlterTableWithDropColumn()
5604        throws java.sql.SQLException JavaDoc {
5605        return true;
5606    }
5607
5608    /**
5609     * JDBC 2.0 Return true if the driver supports batch updates, else return
5610     * false.
5611     *
5612     * @return DOCUMENT ME!
5613     *
5614     * @throws SQLException DOCUMENT ME!
5615     */

5616    public boolean supportsBatchUpdates() throws SQLException JavaDoc {
5617        return true;
5618    }
5619
5620    /**
5621     * Can a catalog name be used in a data manipulation statement?
5622     *
5623     * @return true if so
5624     *
5625     * @throws java.sql.SQLException DOCUMENT ME!
5626     */

5627    public boolean supportsCatalogsInDataManipulation()
5628        throws java.sql.SQLException JavaDoc {
5629        // Servers before 3.22 could not do this
5630
return this.conn.getIO().versionMeetsMinimum(3, 3, 22);
5631    }
5632
5633    /**
5634     * Can a catalog name be used in a index definition statement?
5635     *
5636     * @return true if so
5637     *
5638     * @throws java.sql.SQLException DOCUMENT ME!
5639     */

5640    public boolean supportsCatalogsInIndexDefinitions()
5641        throws java.sql.SQLException JavaDoc {
5642        return false;
5643    }
5644
5645    /**
5646     * Can a catalog name be used in a privilege definition statement?
5647     *
5648     * @return true if so
5649     *
5650     * @throws java.sql.SQLException DOCUMENT ME!
5651     */

5652    public boolean supportsCatalogsInPrivilegeDefinitions()
5653        throws java.sql.SQLException JavaDoc {
5654        return false;
5655    }
5656
5657    /**
5658     * Can a catalog name be used in a procedure call statement?
5659     *
5660     * @return true if so
5661     *
5662     * @throws java.sql.SQLException DOCUMENT ME!
5663     */

5664    public boolean supportsCatalogsInProcedureCalls()
5665        throws java.sql.SQLException JavaDoc {
5666        return false;
5667    }
5668
5669    /**
5670     * Can a catalog name be used in a table definition statement?
5671     *
5672     * @return true if so
5673     *
5674     * @throws java.sql.SQLException DOCUMENT ME!
5675     */

5676    public boolean supportsCatalogsInTableDefinitions()
5677        throws java.sql.SQLException JavaDoc {
5678        return false;
5679    }
5680
5681    /**
5682     * Is column aliasing supported?
5683     *
5684     * <P>
5685     * If so, the SQL AS clause can be used to provide names for computed
5686     * columns or to provide alias names for columns as required. A JDBC
5687     * compliant driver always returns true.
5688     * </p>
5689     *
5690     * @return true if so
5691     *
5692     * @throws java.sql.SQLException DOCUMENT ME!
5693     */

5694    public boolean supportsColumnAliasing() throws java.sql.SQLException JavaDoc {
5695        return true;
5696    }
5697
5698    /**
5699     * Is the CONVERT function between SQL types supported?
5700     *
5701     * @return true if so
5702     *
5703     * @throws java.sql.SQLException DOCUMENT ME!
5704     */

5705    public boolean supportsConvert() throws java.sql.SQLException JavaDoc {
5706        return true;
5707    }
5708
5709    /**
5710     * Is CONVERT between the given SQL types supported?
5711     *
5712     * @param fromType the type to convert from
5713     * @param toType the type to convert to
5714     *
5715     * @return true if so
5716     *
5717     * @throws java.sql.SQLException if an error occurs
5718     *
5719     * @see Types
5720     */

5721    public boolean supportsConvert(int fromType, int toType)
5722        throws java.sql.SQLException JavaDoc {
5723        switch (fromType) {
5724        /* The char/binary types can be converted
5725         * to pretty much anything.
5726         */

5727        case java.sql.Types.CHAR:
5728        case java.sql.Types.VARCHAR:
5729        case java.sql.Types.LONGVARCHAR:
5730        case java.sql.Types.BINARY:
5731        case java.sql.Types.VARBINARY:
5732        case java.sql.Types.LONGVARBINARY:
5733    
5734            switch (toType) {
5735            case java.sql.Types.DECIMAL:
5736            case java.sql.Types.NUMERIC:
5737            case java.sql.Types.REAL:
5738            case java.sql.Types.TINYINT:
5739            case java.sql.Types.SMALLINT:
5740            case java.sql.Types.INTEGER:
5741            case java.sql.Types.BIGINT:
5742            case java.sql.Types.FLOAT:
5743            case java.sql.Types.DOUBLE:
5744            case java.sql.Types.CHAR:
5745            case java.sql.Types.VARCHAR:
5746            case java.sql.Types.LONGVARCHAR:
5747            case java.sql.Types.BINARY:
5748            case java.sql.Types.VARBINARY:
5749            case java.sql.Types.LONGVARBINARY:
5750            case java.sql.Types.OTHER:
5751            case java.sql.Types.DATE:
5752            case java.sql.Types.TIME:
5753            case java.sql.Types.TIMESTAMP:
5754                return true;
5755    
5756            default:
5757                return false;
5758            }
5759    
5760        /* We don't handle the BIT type
5761         * yet.
5762         */

5763        case java.sql.Types.BIT:
5764            return false;
5765    
5766        /* The numeric types. Basically they can convert
5767         * among themselves, and with char/binary types.
5768         */

5769        case java.sql.Types.DECIMAL:
5770        case java.sql.Types.NUMERIC:
5771        case java.sql.Types.REAL:
5772        case java.sql.Types.TINYINT:
5773        case java.sql.Types.SMALLINT:
5774        case java.sql.Types.INTEGER:
5775        case java.sql.Types.BIGINT:
5776        case java.sql.Types.FLOAT:
5777        case java.sql.Types.DOUBLE:
5778    
5779            switch (toType) {
5780            case java.sql.Types.DECIMAL:
5781            case java.sql.Types.NUMERIC:
5782            case java.sql.Types.REAL:
5783            case java.sql.Types.TINYINT:
5784            case java.sql.Types.SMALLINT:
5785            case java.sql.Types.INTEGER:
5786            case java.sql.Types.BIGINT:
5787            case java.sql.Types.FLOAT:
5788            case java.sql.Types.DOUBLE:
5789            case java.sql.Types.CHAR:
5790            case java.sql.Types.VARCHAR:
5791            case java.sql.Types.LONGVARCHAR:
5792            case java.sql.Types.BINARY:
5793            case java.sql.Types.VARBINARY:
5794            case java.sql.Types.LONGVARBINARY:
5795                return true;
5796    
5797            default:
5798                return false;
5799            }
5800    
5801        /* MySQL doesn't support a NULL type. */
5802        case java.sql.Types.NULL:
5803            return false;
5804    
5805        /* With this driver, this will always be a serialized
5806         * object, so the char/binary types will work.
5807         */

5808        case java.sql.Types.OTHER:
5809    
5810            switch (toType) {
5811            case java.sql.Types.CHAR:
5812            case java.sql.Types.VARCHAR:
5813            case java.sql.Types.LONGVARCHAR:
5814            case java.sql.Types.BINARY:
5815            case java.sql.Types.VARBINARY:
5816            case java.sql.Types.LONGVARBINARY:
5817                return true;
5818    
5819            default:
5820                return false;
5821            }
5822    
5823        /* Dates can be converted to char/binary types. */
5824        case java.sql.Types.DATE:
5825    
5826            switch (toType) {
5827            case java.sql.Types.CHAR:
5828            case java.sql.Types.VARCHAR:
5829            case java.sql.Types.LONGVARCHAR:
5830            case java.sql.Types.BINARY:
5831            case java.sql.Types.VARBINARY:
5832            case java.sql.Types.LONGVARBINARY:
5833                return true;
5834    
5835            default:
5836                return false;
5837            }
5838    
5839        /* Time can be converted to char/binary types */
5840        case java.sql.Types.TIME:
5841    
5842            switch (toType) {
5843            case java.sql.Types.CHAR:
5844            case java.sql.Types.VARCHAR:
5845            case java.sql.Types.LONGVARCHAR:
5846            case java.sql.Types.BINARY:
5847            case java.sql.Types.VARBINARY:
5848            case java.sql.Types.LONGVARBINARY:
5849                return true;
5850    
5851            default:
5852                return false;
5853            }
5854    
5855        /* Timestamp can be converted to char/binary types
5856         * and date/time types (with loss of precision).
5857         */

5858        case java.sql.Types.TIMESTAMP:
5859    
5860            switch (toType) {
5861            case java.sql.Types.CHAR:
5862            case java.sql.Types.VARCHAR:
5863            case java.sql.Types.LONGVARCHAR:
5864            case java.sql.Types.BINARY:
5865            case java.sql.Types.VARBINARY:
5866            case java.sql.Types.LONGVARBINARY:
5867            case java.sql.Types.TIME:
5868            case java.sql.Types.DATE:
5869                return true;
5870    
5871            default:
5872                return false;
5873            }
5874    
5875        /* We shouldn't get here! */
5876        default:
5877            return false; // not sure
5878
}
5879    }
5880
5881    /**
5882     * Is the ODBC Core SQL grammar supported?
5883     *
5884     * @return true if so
5885     *
5886     * @throws java.sql.SQLException DOCUMENT ME!
5887     */

5888    public boolean supportsCoreSQLGrammar() throws java.sql.SQLException JavaDoc {
5889        return true;
5890    }
5891
5892    /**
5893     * Are correlated subqueries supported? A JDBC compliant driver always
5894     * returns true.
5895     *
5896     * @return true if so
5897     *
5898     * @throws java.sql.SQLException DOCUMENT ME!
5899     */

5900    public boolean supportsCorrelatedSubqueries() throws java.sql.SQLException JavaDoc {
5901        return false;
5902    }
5903
5904    /**
5905     * Are both data definition and data manipulation statements within a
5906     * transaction supported?
5907     *
5908     * @return true if so
5909     *
5910     * @throws java.sql.SQLException DOCUMENT ME!
5911     */

5912    public boolean supportsDataDefinitionAndDataManipulationTransactions()
5913        throws java.sql.SQLException JavaDoc {
5914        return false;
5915    }
5916
5917    /**
5918     * Are only data manipulation statements within a transaction supported?
5919     *
5920     * @return true if so
5921     *
5922     * @throws java.sql.SQLException DOCUMENT ME!
5923     */

5924    public boolean supportsDataManipulationTransactionsOnly()
5925        throws java.sql.SQLException JavaDoc {
5926        return false;
5927    }
5928
5929    /**
5930     * If table correlation names are supported, are they restricted to be
5931     * different from the names of the tables? A JDBC compliant driver always
5932     * returns true.
5933     *
5934     * @return true if so
5935     *
5936     * @throws java.sql.SQLException DOCUMENT ME!
5937     */

5938    public boolean supportsDifferentTableCorrelationNames()
5939        throws java.sql.SQLException JavaDoc {
5940        return true;
5941    }
5942
5943    /**
5944     * Are expressions in "ORDER BY" lists supported?
5945     *
5946     * @return true if so
5947     *
5948     * @throws java.sql.SQLException DOCUMENT ME!
5949     */

5950    public boolean supportsExpressionsInOrderBy() throws java.sql.SQLException JavaDoc {
5951        return true;
5952    }
5953
5954    /**
5955     * Is the ODBC Extended SQL grammar supported?
5956     *
5957     * @return true if so
5958     *
5959     * @throws java.sql.SQLException DOCUMENT ME!
5960     */

5961    public boolean supportsExtendedSQLGrammar() throws java.sql.SQLException JavaDoc {
5962        return false;
5963    }
5964
5965    /**
5966     * Are full nested outer joins supported?
5967     *
5968     * @return true if so
5969     *
5970     * @throws java.sql.SQLException DOCUMENT ME!
5971     */

5972    public boolean supportsFullOuterJoins() throws java.sql.SQLException JavaDoc {
5973        return false;
5974    }
5975
5976    /**
5977     * JDBC 3.0
5978     *
5979     * @return DOCUMENT ME!
5980     */

5981    public boolean supportsGetGeneratedKeys() {
5982        return true;
5983    }
5984
5985    /**
5986     * Is some form of "GROUP BY" clause supported?
5987     *
5988     * @return true if so
5989     *
5990     * @throws java.sql.SQLException DOCUMENT ME!
5991     */

5992    public boolean supportsGroupBy() throws java.sql.SQLException JavaDoc {
5993        return true;
5994    }
5995
5996    /**
5997     * Can a "GROUP BY" clause add columns not in the SELECT provided it
5998     * specifies all the columns in the SELECT?
5999     *
6000     * @return true if so
6001     *
6002     * @throws java.sql.SQLException DOCUMENT ME!
6003     */

6004    public boolean supportsGroupByBeyondSelect() throws java.sql.SQLException JavaDoc {
6005        return true;
6006    }
6007
6008    /**
6009     * Can a "GROUP BY" clause use columns not in the SELECT?
6010     *
6011     * @return true if so
6012     *
6013     * @throws java.sql.SQLException DOCUMENT ME!
6014     */

6015    public boolean supportsGroupByUnrelated() throws java.sql.SQLException JavaDoc {
6016        return false;
6017    }
6018
6019    /**
6020     * Is the SQL Integrity Enhancement Facility supported?
6021     *
6022     * @return true if so
6023     *
6024     * @throws java.sql.SQLException DOCUMENT ME!
6025     */

6026    public boolean supportsIntegrityEnhancementFacility()
6027        throws java.sql.SQLException JavaDoc {
6028        return false;
6029    }
6030
6031    /**
6032     * Is the escape character in "LIKE" clauses supported? A JDBC compliant
6033     * driver always returns true.
6034     *
6035     * @return true if so
6036     *
6037     * @throws java.sql.SQLException DOCUMENT ME!
6038     */

6039    public boolean supportsLikeEscapeClause() throws java.sql.SQLException JavaDoc {
6040        return true;
6041    }
6042
6043    /**
6044     * Is there limited support for outer joins? (This will be true if
6045     * supportFullOuterJoins is true.)
6046     *
6047     * @return true if so
6048     *
6049     * @throws java.sql.SQLException DOCUMENT ME!
6050     */

6051    public boolean supportsLimitedOuterJoins() throws java.sql.SQLException JavaDoc {
6052        return true;
6053    }
6054
6055    /**
6056     * Is the ODBC Minimum SQL grammar supported? All JDBC compliant drivers
6057     * must return true.
6058     *
6059     * @return true if so
6060     *
6061     * @throws java.sql.SQLException DOCUMENT ME!
6062     */

6063    public boolean supportsMinimumSQLGrammar() throws java.sql.SQLException JavaDoc {
6064        return true;
6065    }
6066
6067    /**
6068     * Does the database support mixed case unquoted SQL identifiers?
6069     *
6070     * @return true if so
6071     *
6072     * @throws java.sql.SQLException DOCUMENT ME!
6073     */

6074    public boolean supportsMixedCaseIdentifiers() throws java.sql.SQLException JavaDoc {
6075        return false;
6076    }
6077
6078    /**
6079     * Does the database support mixed case quoted SQL identifiers? A JDBC
6080     * compliant driver will always return true.
6081     *
6082     * @return true if so
6083     *
6084     * @throws java.sql.SQLException DOCUMENT ME!
6085     */

6086    public boolean supportsMixedCaseQuotedIdentifiers()
6087        throws java.sql.SQLException JavaDoc {
6088        return false;
6089    }
6090
6091    /**
6092     * @see DatabaseMetaData#supportsMultipleOpenResults()
6093     */

6094    public boolean supportsMultipleOpenResults() throws SQLException JavaDoc {
6095        return false;
6096    }
6097
6098    /**
6099     * Are multiple ResultSets from a single execute supported?
6100     *
6101     * @return true if so
6102     *
6103     * @throws java.sql.SQLException DOCUMENT ME!
6104     */

6105    public boolean supportsMultipleResultSets() throws java.sql.SQLException JavaDoc {
6106        return false;
6107    }
6108
6109    /**
6110     * Can we have multiple transactions open at once (on different
6111     * connections)?
6112     *
6113     * @return true if so
6114     *
6115     * @throws java.sql.SQLException DOCUMENT ME!
6116     */

6117    public boolean supportsMultipleTransactions() throws java.sql.SQLException JavaDoc {
6118        return true;
6119    }
6120
6121    /**
6122     * @see DatabaseMetaData#supportsNamedParameters()
6123     */

6124    public boolean supportsNamedParameters() throws SQLException JavaDoc {
6125        return false;
6126    }
6127
6128    /**
6129     * Can columns be defined as non-nullable? A JDBC compliant driver always
6130     * returns true.
6131     *
6132     * @return true if so
6133     *
6134     * @throws java.sql.SQLException DOCUMENT ME!
6135     */

6136    public boolean supportsNonNullableColumns() throws java.sql.SQLException JavaDoc {
6137        return true;
6138    }
6139
6140    /**
6141     * Can cursors remain open across commits?
6142     *
6143     * @return true if so
6144     *
6145     * @throws java.sql.SQLException if a database access error occurs
6146     *
6147     * @see Connection#disableAutoClose
6148     */

6149    public boolean supportsOpenCursorsAcrossCommit()
6150        throws java.sql.SQLException JavaDoc {
6151        return false;
6152    }
6153
6154    /**
6155     * Can cursors remain open across rollbacks?
6156     *
6157     * @return true if so
6158     *
6159     * @throws java.sql.SQLException if an error occurs
6160     *
6161     * @see Connection#disableAutoClose
6162     */

6163    public boolean supportsOpenCursorsAcrossRollback()
6164        throws java.sql.SQLException JavaDoc {
6165        return false;
6166    }
6167
6168    /**
6169     * Can statements remain open across commits?
6170     *
6171     * @return true if so
6172     *
6173     * @throws java.sql.SQLException if an error occurs
6174     *
6175     * @see Connection#disableAutoClose
6176     */

6177    public boolean supportsOpenStatementsAcrossCommit()
6178        throws java.sql.SQLException JavaDoc {
6179        return false;
6180    }
6181
6182    /**
6183     * Can statements remain open across rollbacks?
6184     *
6185     * @return true if so
6186     *
6187     * @throws java.sql.SQLException if an error occurs
6188     *
6189     * @see Connection#disableAutoClose
6190     */

6191    public boolean supportsOpenStatementsAcrossRollback()
6192        throws java.sql.SQLException JavaDoc {
6193        return false;
6194    }
6195
6196    /**
6197     * Can an "ORDER BY" clause use columns not in the SELECT?
6198     *
6199     * @return true if so
6200     *
6201     * @throws java.sql.SQLException DOCUMENT ME!
6202     */

6203    public boolean supportsOrderByUnrelated() throws java.sql.SQLException JavaDoc {
6204        return false;
6205    }
6206
6207    /**
6208     * Is some form of outer join supported?
6209     *
6210     * @return true if so
6211     *
6212     * @throws java.sql.SQLException DOCUMENT ME!
6213     */

6214    public boolean supportsOuterJoins() throws java.sql.SQLException JavaDoc {
6215        return true;
6216    }
6217
6218    /**
6219     * Is positioned DELETE supported?
6220     *
6221     * @return true if so
6222     *
6223     * @throws java.sql.SQLException DOCUMENT ME!
6224     */

6225    public boolean supportsPositionedDelete() throws java.sql.SQLException JavaDoc {
6226        return false;
6227    }
6228
6229    /**
6230     * Is positioned UPDATE supported?
6231     *
6232     * @return true if so
6233     *
6234     * @throws java.sql.SQLException DOCUMENT ME!
6235     */

6236    public boolean supportsPositionedUpdate() throws java.sql.SQLException JavaDoc {
6237        return false;
6238    }
6239
6240    /**
6241     * JDBC 2.0 Does the database support the concurrency type in combination
6242     * with the given result set type?
6243     *
6244     * @param type defined in java.sql.ResultSet
6245     * @param concurrency type defined in java.sql.ResultSet
6246     *
6247     * @return true if so
6248     *
6249     * @exception SQLException if a database-access error occurs.
6250     *
6251     * @see Connection
6252     */

6253    public boolean supportsResultSetConcurrency(int type, int concurrency)
6254        throws SQLException JavaDoc {
6255        return ((type == ResultSet.TYPE_SCROLL_INSENSITIVE)
6256        && ((concurrency == ResultSet.CONCUR_READ_ONLY)
6257        || (concurrency == ResultSet.CONCUR_UPDATABLE)));
6258    }
6259
6260    /**
6261     * @see DatabaseMetaData#supportsResultSetHoldability(int)
6262     */

6263    public boolean supportsResultSetHoldability(int holdability)
6264        throws SQLException JavaDoc {
6265        return (holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT);
6266    }
6267
6268    /**
6269     * JDBC 2.0 Does the database support the given result set type?
6270     *
6271     * @param type defined in java.sql.ResultSet
6272     *
6273     * @return true if so
6274     *
6275     * @exception SQLException if a database-access error occurs.
6276     *
6277     * @see Connection
6278     */

6279    public boolean supportsResultSetType(int type) throws SQLException JavaDoc {
6280        return (type == ResultSet.TYPE_SCROLL_INSENSITIVE);
6281    }
6282
6283    /**
6284     * @see DatabaseMetaData#supportsSavepoints()
6285     */

6286    public boolean supportsSavepoints() throws SQLException JavaDoc {
6287        return false;
6288    }
6289
6290    /**
6291     * Can a schema name be used in a data manipulation statement?
6292     *
6293     * @return true if so
6294     *
6295     * @throws java.sql.SQLException DOCUMENT ME!
6296     */

6297    public boolean supportsSchemasInDataManipulation()
6298        throws java.sql.SQLException JavaDoc {
6299        return false;
6300    }
6301
6302    /**
6303     * Can a schema name be used in an index definition statement?
6304     *
6305     * @return true if so
6306     *
6307     * @throws java.sql.SQLException DOCUMENT ME!
6308     */

6309    public boolean supportsSchemasInIndexDefinitions()
6310        throws java.sql.SQLException JavaDoc {
6311        return false;
6312    }
6313
6314    /**
6315     * Can a schema name be used in a privilege definition statement?
6316     *
6317     * @return true if so
6318     *
6319     * @throws java.sql.SQLException DOCUMENT ME!
6320     */

6321    public boolean supportsSchemasInPrivilegeDefinitions()
6322        throws java.sql.SQLException JavaDoc {
6323        return false;
6324    }
6325
6326    /**
6327     * Can a schema name be used in a procedure call statement?
6328     *
6329     * @return true if so
6330     *
6331     * @throws java.sql.SQLException DOCUMENT ME!
6332     */

6333    public boolean supportsSchemasInProcedureCalls()
6334        throws java.sql.SQLException JavaDoc {
6335        return false;
6336    }
6337
6338    /**
6339     * Can a schema name be used in a table definition statement?
6340     *
6341     * @return true if so
6342     *
6343     * @throws java.sql.SQLException DOCUMENT ME!
6344     */

6345    public boolean supportsSchemasInTableDefinitions()
6346        throws java.sql.SQLException JavaDoc {
6347        return false;
6348    }
6349
6350    /**
6351     * Is SELECT for UPDATE supported?
6352     *
6353     * @return true if so
6354     *
6355     * @throws java.sql.SQLException DOCUMENT ME!
6356     */

6357    public boolean supportsSelectForUpdate() throws java.sql.SQLException JavaDoc {
6358        return false;
6359    }
6360
6361    /**
6362     * @see DatabaseMetaData#supportsStatementPooling()
6363     */

6364    public boolean supportsStatementPooling() throws SQLException JavaDoc {
6365        return false;
6366    }
6367
6368    /**
6369     * Are stored procedure calls using the stored procedure escape syntax
6370     * supported?
6371     *
6372     * @return true if so
6373     *
6374     * @throws java.sql.SQLException DOCUMENT ME!
6375     */

6376    public boolean supportsStoredProcedures() throws java.sql.SQLException JavaDoc {
6377        return false;
6378    }
6379
6380    /**
6381     * Are subqueries in comparison expressions supported? A JDBC compliant
6382     * driver always returns true.
6383     *
6384     * @return true if so
6385     *
6386     * @throws java.sql.SQLException DOCUMENT ME!
6387     */

6388    public boolean supportsSubqueriesInComparisons()
6389        throws java.sql.SQLException JavaDoc {
6390        return this.conn.getIO().versionMeetsMinimum(4, 1, 0);
6391    }
6392
6393    /**
6394     * Are subqueries in exists expressions supported? A JDBC compliant driver
6395     * always returns true.
6396     *
6397     * @return true if so
6398     *
6399     * @throws java.sql.SQLException DOCUMENT ME!
6400     */

6401    public boolean supportsSubqueriesInExists() throws java.sql.SQLException JavaDoc {
6402        return this.conn.getIO().versionMeetsMinimum(4, 1, 0);
6403    }
6404
6405    /**
6406     * Are subqueries in "in" statements supported? A JDBC compliant driver
6407     * always returns true.
6408     *
6409     * @return true if so
6410     *
6411     * @throws java.sql.SQLException DOCUMENT ME!
6412     */

6413    public boolean supportsSubqueriesInIns() throws java.sql.SQLException JavaDoc {
6414        return this.conn.getIO().versionMeetsMinimum(4, 1, 0);
6415    }
6416
6417    /**
6418     * Are subqueries in quantified expressions supported? A JDBC compliant
6419     * driver always returns true.
6420     *
6421     * @return true if so
6422     *
6423     * @throws java.sql.SQLException DOCUMENT ME!
6424     */

6425    public boolean supportsSubqueriesInQuantifieds()
6426        throws java.sql.SQLException JavaDoc {
6427        return this.conn.getIO().versionMeetsMinimum(4, 1, 0);
6428    }
6429
6430    /**
6431     * Are table correlation names supported? A JDBC compliant driver always
6432     * returns true.
6433     *
6434     * @return true if so
6435     *
6436     * @throws java.sql.SQLException DOCUMENT ME!
6437     */

6438    public boolean supportsTableCorrelationNames() throws java.sql.SQLException JavaDoc {
6439        return true;
6440    }
6441
6442    /**
6443     * Does the database support the given transaction isolation level?
6444     *
6445     * @param level the values are defined in java.sql.Connection
6446     *
6447     * @return true if so
6448     *
6449     * @throws java.sql.SQLException if a database access error occurs
6450     *
6451     * @see Connection
6452     */

6453    public boolean supportsTransactionIsolationLevel(int level)
6454        throws java.sql.SQLException JavaDoc {
6455        if (this.conn.supportsIsolationLevel()) {
6456            switch (level) {
6457            case java.sql.Connection.TRANSACTION_READ_COMMITTED:
6458            case java.sql.Connection.TRANSACTION_READ_UNCOMMITTED:
6459            case java.sql.Connection.TRANSACTION_REPEATABLE_READ:
6460            case java.sql.Connection.TRANSACTION_SERIALIZABLE:
6461                return true;
6462
6463            default:
6464                return false;
6465            }
6466        } else {
6467            return false;
6468        }
6469    }
6470
6471    /**
6472     * Are transactions supported? If not, commit is a noop and the isolation
6473     * level is TRANSACTION_NONE.
6474     *
6475     * @return true if transactions are supported
6476     *
6477     * @throws java.sql.SQLException DOCUMENT ME!
6478     */

6479    public boolean supportsTransactions() throws java.sql.SQLException JavaDoc {
6480        return this.conn.supportsTransactions();
6481    }
6482
6483    /**
6484     * Is SQL UNION supported? A JDBC compliant driver always returns true.
6485     *
6486     * @return true if so
6487     *
6488     * @throws java.sql.SQLException DOCUMENT ME!
6489     */

6490    public boolean supportsUnion() throws java.sql.SQLException JavaDoc {
6491        return this.conn.getIO().versionMeetsMinimum(4, 0, 0);
6492    }
6493
6494    /**
6495     * Is SQL UNION ALL supported? A JDBC compliant driver always returns true.
6496     *
6497     * @return true if so
6498     *
6499     * @throws java.sql.SQLException DOCUMENT ME!
6500     */

6501    public boolean supportsUnionAll() throws java.sql.SQLException JavaDoc {
6502        return this.conn.getIO().versionMeetsMinimum(4, 0, 0);
6503    }
6504
6505    /**
6506     * JDBC 2.0 Determine whether or not a visible row update can be detected
6507     * by calling ResultSet.rowUpdated().
6508     *
6509     * @param type set type, i.e. ResultSet.TYPE_XXX
6510     *
6511     * @return true if changes are detected by the resultset type
6512     *
6513     * @exception SQLException if a database-access error occurs.
6514     */

6515    public boolean updatesAreDetected(int type) throws SQLException JavaDoc {
6516        return false;
6517    }
6518
6519    /**
6520     * Does the database use a file for each table?
6521     *
6522     * @return true if the database uses a local file for each table
6523     *
6524     * @throws java.sql.SQLException DOCUMENT ME!
6525     */

6526    public boolean usesLocalFilePerTable() throws java.sql.SQLException JavaDoc {
6527        return false;
6528    }
6529
6530    /**
6531     * Does the database store tables in a local file?
6532     *
6533     * @return true if so
6534     *
6535     * @throws java.sql.SQLException DOCUMENT ME!
6536     */

6537    public boolean usesLocalFiles() throws java.sql.SQLException JavaDoc {
6538        return false;
6539    }
6540
6541    /**
6542     * Parses the cascade option string and returns the DBMD constant that
6543     * represents it (for deletes)
6544     *
6545     * @param cascadeOptions the comment from 'SHOW TABLE STATUS'
6546     *
6547     * @return the DBMD constant that represents the cascade option
6548     */

6549    private int getCascadeDeleteOption(String JavaDoc cascadeOptions) {
6550        int onDeletePos = cascadeOptions.indexOf("ON DELETE");
6551
6552        if (onDeletePos != -1) {
6553            String JavaDoc deleteOptions = cascadeOptions.substring(onDeletePos,
6554                    cascadeOptions.length());
6555
6556            if (deleteOptions.startsWith("ON DELETE CASCADE")) {
6557                return DatabaseMetaData.importedKeyCascade;
6558            } else if (deleteOptions.startsWith("ON DELETE SET NULL")) {
6559                return DatabaseMetaData.importedKeySetNull;
6560            } else if (deleteOptions.startsWith("ON DELETE RESTRICT")) {
6561                return DatabaseMetaData.importedKeyRestrict;
6562            } else if (deleteOptions.startsWith("ON DELETE NO ACTION")) {
6563                return DatabaseMetaData.importedKeyNoAction;
6564            }
6565        }
6566
6567        return DatabaseMetaData.importedKeyNoAction;
6568    }
6569
6570    /**
6571     * Parses the cascade option string and returns the DBMD constant that
6572     * represents it (for Updates)
6573     *
6574     * @param cascadeOptions the comment from 'SHOW TABLE STATUS'
6575     *
6576     * @return the DBMD constant that represents the cascade option
6577     */

6578    private int getCascadeUpdateOption(String JavaDoc cascadeOptions) {
6579        int onUpdatePos = cascadeOptions.indexOf("ON UPDATE");
6580
6581        if (onUpdatePos != -1) {
6582            String JavaDoc updateOptions = cascadeOptions.substring(onUpdatePos,
6583                    cascadeOptions.length());
6584
6585            if (updateOptions.startsWith("ON UPDATE CASCADE")) {
6586                return DatabaseMetaData.importedKeyCascade;
6587            } else if (updateOptions.startsWith("ON UPDATE SET NULL")) {
6588                return DatabaseMetaData.importedKeySetNull;
6589            } else if (updateOptions.startsWith("ON UPDATE RESTRICT")) {
6590                return DatabaseMetaData.importedKeyRestrict;
6591            } else if (updateOptions.startsWith("ON UPDATE NO ACTION")) {
6592                return DatabaseMetaData.importedKeyNoAction;
6593            }
6594        }
6595
6596        return DatabaseMetaData.importedKeyNoAction;
6597    }
6598
6599    /**
6600     * Adds to the tuples list the exported keys of exportingTable based on the
6601     * keysComment from the 'show table status' sql command. KeysComment is
6602     * that part of the comment field that follows the "InnoDB free ...;"
6603     * prefix.
6604     *
6605     * @param catalog the database to use
6606     * @param exportingTable the table keys are being exported from
6607     * @param keysComment the comment from 'show table status'
6608     * @param tuples the rows to add results to
6609     * @param fkTableName the foreign key table name
6610     *
6611     * @throws SQLException if a database access error occurs
6612     */

6613    private void getExportKeyResults(String JavaDoc catalog, String JavaDoc exportingTable,
6614        String JavaDoc keysComment, List JavaDoc tuples, String JavaDoc fkTableName)
6615        throws SQLException JavaDoc {
6616        getResultsImpl(catalog, exportingTable, keysComment, tuples,
6617            fkTableName, true);
6618    }
6619
6620    /**
6621     * Returns the DELETE and UPDATE foreign key actions from the given 'SHOW
6622     * TABLE STATUS' string, with the DELETE action being the first item in
6623     * the array, and the UPDATE action being the second.
6624     *
6625     * @param commentString the comment from 'SHOW TABLE STATUS'
6626     *
6627     * @return int[] [0] = delete action, [1] = update action
6628     */

6629    private int[] getForeignKeyActions(String JavaDoc commentString) {
6630        int[] actions = new int[] {
6631                DatabaseMetaData.importedKeyNoAction,
6632                DatabaseMetaData.importedKeyNoAction
6633            };
6634
6635        int lastParenIndex = commentString.lastIndexOf(")");
6636
6637        if (lastParenIndex != (commentString.length() - 1)) {
6638            String JavaDoc cascadeOptions = commentString.substring(lastParenIndex + 1)
6639                                                 .trim().toUpperCase();
6640
6641            actions[0] = getCascadeDeleteOption(cascadeOptions);
6642            actions[1] = getCascadeUpdateOption(cascadeOptions);
6643        }
6644
6645        return actions;
6646    }
6647
6648    /**
6649     * Populates the tuples list with the imported keys of importingTable based
6650     * on the keysComment from the 'show table status' sql command.
6651     * KeysComment is that part of the comment field that follows the "InnoDB
6652     * free ...;" prefix.
6653     *
6654     * @param catalog the database to use
6655     * @param importingTable the table keys are being imported to
6656     * @param keysComment the comment from 'show table status'
6657     * @param tuples the rows to add results to
6658     *
6659     * @throws SQLException if a database access error occurs
6660     */

6661    private void getImportKeyResults(String JavaDoc catalog, String JavaDoc importingTable,
6662        String JavaDoc keysComment, List JavaDoc tuples) throws SQLException JavaDoc {
6663        getResultsImpl(catalog, importingTable, keysComment, tuples, null, false);
6664    }
6665
6666    private void getResultsImpl(String JavaDoc catalog, String JavaDoc table,
6667        String JavaDoc keysComment, List JavaDoc tuples, String JavaDoc fkTableName, boolean isExport)
6668        throws SQLException JavaDoc {
6669        // keys will equal something like this:
6670
// (parent_service_id child_service_id) REFER ds/subservices(parent_service_id child_service_id)
6671
// parse of the string into three phases:
6672
// 1: parse the opening parentheses to determine how many results there will be
6673
// 2: read in the schema name/table name
6674
// 3: parse the closing parentheses
6675
int firstLeftParenIndex = keysComment.indexOf('(');
6676        String JavaDoc constraintName = keysComment.substring(0, firstLeftParenIndex)
6677                                           .trim();
6678        keysComment = keysComment.substring(firstLeftParenIndex,
6679                keysComment.length());
6680
6681        StringTokenizer JavaDoc keyTokens = new StringTokenizer JavaDoc(keysComment.trim(),
6682                "()", false);
6683        String JavaDoc localColumnNamesString = keyTokens.nextToken();
6684        StringTokenizer JavaDoc localColumnNames = new StringTokenizer JavaDoc(localColumnNamesString,
6685                " ,");
6686        String JavaDoc referCatalogTableString = keyTokens.nextToken();
6687        StringTokenizer JavaDoc referSchemaTable = new StringTokenizer JavaDoc(referCatalogTableString,
6688                " /");
6689        String JavaDoc referColumnNamesString = keyTokens.nextToken();
6690        StringTokenizer JavaDoc referColumnNames = new StringTokenizer JavaDoc(referColumnNamesString,
6691                " ,");
6692        referSchemaTable.nextToken(); //discard the REFER token
6693

6694        String JavaDoc referCatalog = referSchemaTable.nextToken();
6695        String JavaDoc referTable = referSchemaTable.nextToken();
6696
6697        if (isExport && !referTable.equals(table)) {
6698            return;
6699        }
6700
6701        if (localColumnNames.countTokens() != referColumnNames.countTokens()) {
6702            throw new SQLException JavaDoc("Error parsing foriegn keys definition",
6703                SQLError.SQL_STATE_GENERAL_ERROR);
6704        }
6705
6706        int keySeqIndex = 1;
6707
6708        byte[] connectionCatalogAsBytes = null;
6709
6710        if (catalog == null) {
6711            connectionCatalogAsBytes = s2b(this.conn.getCatalog());
6712        } else {
6713            connectionCatalogAsBytes = s2b(catalog);
6714        }
6715
6716        while (localColumnNames.hasMoreTokens()) {
6717            byte[][] tuple = new byte[14][];
6718            String JavaDoc localColumnName = localColumnNames.nextToken();
6719            String JavaDoc referColumnName = referColumnNames.nextToken();
6720            tuple[FKTABLE_CAT] = connectionCatalogAsBytes;
6721            tuple[FKTABLE_SCHEM] = null;
6722            tuple[FKTABLE_NAME] = s2b((isExport) ? fkTableName : table);
6723            tuple[FKCOLUMN_NAME] = s2b(localColumnName);
6724            tuple[PKTABLE_CAT] = s2b(referCatalog);
6725            tuple[PKTABLE_SCHEM] = null;
6726            tuple[PKTABLE_NAME] = s2b((isExport) ? table : referTable);
6727            tuple[PKCOLUMN_NAME] = s2b(referColumnName);
6728            tuple[KEY_SEQ] = s2b(Integer.toString(keySeqIndex++));
6729
6730            int[] actions = getForeignKeyActions(keysComment);
6731
6732            tuple[UPDATE_RULE] = s2b(Integer.toString(actions[1]));
6733            tuple[DELETE_RULE] = s2b(Integer.toString(actions[0]));
6734            tuple[FK_NAME] = s2b(constraintName);
6735            tuple[PK_NAME] = null; //not available from show table status
6736
tuple[DEFERRABILITY] = s2b(Integer.toString(
6737                        java.sql.DatabaseMetaData.importedKeyNotDeferrable));
6738            tuples.add(tuple);
6739        }
6740    }
6741
6742    private String JavaDoc getTableNameWithCase(String JavaDoc table) {
6743        String JavaDoc tableNameWithCase = (this.conn.lowerCaseTableNames()
6744            ? table.toLowerCase() : table);
6745
6746        return tableNameWithCase;
6747    }
6748
6749    private java.sql.ResultSet JavaDoc buildResultSet(com.mysql.jdbc.Field[] fields,
6750        java.util.ArrayList JavaDoc rows) throws SQLException JavaDoc {
6751        int fieldsLength = fields.length;
6752
6753        for (int i = 0; i < fieldsLength; i++) {
6754            fields[i].setConnection(this.conn);
6755        }
6756
6757        return new com.mysql.jdbc.ResultSet(this.conn.getCatalog(), fields,
6758            new RowDataStatic(rows), this.conn);
6759    }
6760
6761    /**
6762     * Converts the given string to bytes, using the connection's character
6763     * encoding, or if not available, the JVM default encoding.
6764     *
6765     * @param s DOCUMENT ME!
6766     *
6767     * @return DOCUMENT ME!
6768     */

6769    private byte[] s2b(String JavaDoc s) {
6770        if ((this.conn != null) && this.conn.useUnicode()) {
6771            try {
6772                String JavaDoc encoding = this.conn.getEncoding();
6773
6774                if (encoding == null) {
6775                    return s.getBytes();
6776                } else {
6777                    SingleByteCharsetConverter converter = this.conn.getCharsetConverter(encoding);
6778
6779                    if (converter != null) {
6780                        return converter.toBytes(s);
6781                    } else {
6782                        return s.getBytes(encoding);
6783                    }
6784                }
6785            } catch (java.io.UnsupportedEncodingException JavaDoc E) {
6786                return s.getBytes();
6787            }
6788        } else {
6789            return s.getBytes();
6790        }
6791    }
6792}
6793
Popular Tags