EMMA Coverage Report (generated Mon Jul 24 20:33:06 CDT 2006)
[all classes][com.mysql.jdbc]

COVERAGE SUMMARY FOR SOURCE FILE [DatabaseMetaDataUsingInfoSchema.java]

nameclass, %method, %block, %line, %
DatabaseMetaDataUsingInfoSchema.java100% (1/1)100% (12/12)88%  (1655/1881)79%  (164.1/208)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class DatabaseMetaDataUsingInfoSchema100% (1/1)100% (12/12)88%  (1655/1881)79%  (164.1/208)
getTables (String, String, String, String []): ResultSet 100% (1/1)59%  (112/189)54%  (17.3/32)
getProcedures (String, String, String): ResultSet 100% (1/1)78%  (126/162)59%  (13.5/23)
prepareMetaDataSafeStatement (String): PreparedStatement 100% (1/1)81%  (13/16)80%  (4/5)
getPrimaryKeys (String, String, String): ResultSet 100% (1/1)87%  (104/119)84%  (13.5/16)
getColumnPrivileges (String, String, String, String): ResultSet 100% (1/1)90%  (135/150)87%  (16.5/19)
getExportedKeys (String, String, String): ResultSet 100% (1/1)92%  (184/199)84%  (13.5/16)
getImportedKeys (String, String, String): ResultSet 100% (1/1)93%  (188/203)85%  (14.5/17)
getColumns (String, String, String, String): ResultSet 100% (1/1)93%  (262/282)86%  (21.5/25)
getIndexInfo (String, String, String, boolean, boolean): ResultSet 100% (1/1)94%  (173/184)88%  (11.5/13)
getCrossReference (String, String, String, String, String, String): ResultSet 100% (1/1)95%  (344/363)91%  (33.5/37)
DatabaseMetaDataUsingInfoSchema (Connection, String): void 100% (1/1)100% (5/5)100% (2/2)
executeMetadataQuery (PreparedStatement): ResultSet 100% (1/1)100% (9/9)100% (3/3)

1/*
2 Copyright (C) 2005 MySQL AB
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of version 2 of the GNU General Public License as 
6 published by the Free Software Foundation.
7 
8 There are special exceptions to the terms and conditions of the GPL 
9 as it is applied to this software. View the full text of the 
10 exception in file EXCEPTIONS-CONNECTOR-J in the directory of this 
11 software distribution.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 
22 */
23package com.mysql.jdbc;
24 
25import java.sql.ResultSet;
26import java.sql.SQLException;
27import java.sql.Types;
28 
29/**
30 * DatabaseMetaData implementation that uses INFORMATION_SCHEMA available in
31 * MySQL-5.0 and newer.
32 * 
33 * The majority of the queries in this code were built for Connector/OO.org by
34 * Georg Richter (georg_at_mysql.com).
35 */
36public class DatabaseMetaDataUsingInfoSchema extends DatabaseMetaData {
37 
38        public DatabaseMetaDataUsingInfoSchema(Connection connToSet,
39                        String databaseToSet) {
40                super(connToSet, databaseToSet);
41        }
42 
43        private ResultSet executeMetadataQuery(PreparedStatement pStmt)
44                        throws SQLException {
45                ResultSet rs = pStmt.executeQuery();
46                ((com.mysql.jdbc.ResultSet) rs).setOwningStatement(null);
47 
48                return rs;
49        }
50 
51        /**
52         * Get a description of the access rights for a table's columns.
53         * <P>
54         * Only privileges matching the column name criteria are returned. They are
55         * ordered by COLUMN_NAME and PRIVILEGE.
56         * </p>
57         * <P>
58         * Each privilige description has the following columns:
59         * <OL>
60         * <li> <B>TABLE_CAT</B> String => table catalog (may be null) </li>
61         * <li> <B>TABLE_SCHEM</B> String => table schema (may be null) </li>
62         * <li> <B>TABLE_NAME</B> String => table name </li>
63         * <li> <B>COLUMN_NAME</B> String => column name </li>
64         * <li> <B>GRANTOR</B> => grantor of access (may be null) </li>
65         * <li> <B>GRANTEE</B> String => grantee of access </li>
66         * <li> <B>PRIVILEGE</B> String => name of access (SELECT, INSERT, UPDATE,
67         * REFRENCES, ...) </li>
68         * <li> <B>IS_GRANTABLE</B> String => "YES" if grantee is permitted to
69         * grant to others; "NO" if not; null if unknown </li>
70         * </ol>
71         * </p>
72         * 
73         * @param catalog
74         *            a catalog name; "" retrieves those without a catalog
75         * @param schema
76         *            a schema name; "" retrieves those without a schema
77         * @param table
78         *            a table name
79         * @param columnNamePattern
80         *            a column name pattern
81         * @return ResultSet each row is a column privilege description
82         * @throws SQLException
83         *             if a database access error occurs
84         * @see #getSearchStringEscape
85         */
86        public java.sql.ResultSet getColumnPrivileges(String catalog,
87                        String schema, String table, String columnNamePattern)
88                        throws SQLException {
89                if (columnNamePattern == null) {
90                        if (this.conn.getNullNamePatternMatchesAll()) {
91                                columnNamePattern = "%";
92                        } else {
93                                throw SQLError.createSQLException(
94                                                "Column name pattern can not be NULL or empty.",
95                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
96                        }
97                }
98 
99                if (catalog == null) {
100                        if (!this.conn.getNullCatalogMeansCurrent()) {
101                                throw SQLError.createSQLException("'catalog' parameter can not be null",
102                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
103                        }
104 
105                        catalog = this.database;
106                }
107                
108                String sql = "SELECT TABLE_SCHEMA AS TABLE_CAT, NULL AS TABLE_SCHEM, TABLE_NAME,"
109                         +"COLUMN_NAME, NULL AS GRANTOR, GRANTEE, PRIVILEGE_TYPE AS PRIVILEGE, IS_GRANTABLE FROM "
110                         + "INFORMATION_SCHEMA.COLUMN_PRIVILEGES WHERE "
111                         + "TABLE_SCHEMA = ? AND "
112                         + "TABLE_NAME =? AND COLUMN_NAME LIKE ? ORDER BY " 
113                         + "COLUMN_NAME, PRIVILEGE_TYPE";
114                
115                PreparedStatement pStmt = null;
116                
117                try {
118                        pStmt = prepareMetaDataSafeStatement(sql);
119                        pStmt.setString(1, catalog);
120                        pStmt.setString(2, table);
121                        pStmt.setString(3, columnNamePattern);
122                        
123                        ResultSet rs = executeMetadataQuery(pStmt);
124                        ((com.mysql.jdbc.ResultSet) rs).redefineFieldsForDBMD(new Field[] {
125                                        new Field("", "TABLE_CAT", Types.CHAR, 64),
126                                        new Field("", "TABLE_SCHEM", Types.CHAR, 1),
127                                        new Field("", "TABLE_NAME", Types.CHAR, 64),
128                                        new Field("", "COLUMN_NAME", Types.CHAR, 64),
129                                        new Field("", "GRANTOR", Types.CHAR, 77),
130                                        new Field("", "GRANTEE", Types.CHAR, 77),
131                                        new Field("", "PRIVILEGE", Types.CHAR, 64),
132                                        new Field("", "IS_GRANTABLE", Types.CHAR, 3)});
133                        
134                        return rs;
135                } finally {
136                        if (pStmt != null) {
137                                pStmt.close();
138                        }
139                }
140        }
141 
142        /**
143         * Get a description of table columns available in a catalog.
144         * <P>
145         * Only column descriptions matching the catalog, schema, table and column
146         * name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME
147         * and ORDINAL_POSITION.
148         * </p>
149         * <P>
150         * Each column description has the following columns:
151         * <OL>
152         * <li> <B>TABLE_CAT</B> String => table catalog (may be null) </li>
153         * <li> <B>TABLE_SCHEM</B> String => table schema (may be null) </li>
154         * <li> <B>TABLE_NAME</B> String => table name </li>
155         * <li> <B>COLUMN_NAME</B> String => column name </li>
156         * <li> <B>DATA_TYPE</B> short => SQL type from java.sql.Types </li>
157         * <li> <B>TYPE_NAME</B> String => Data source dependent type name </li>
158         * <li> <B>COLUMN_SIZE</B> int => column size. For char or date types this
159         * is the maximum number of characters, for numeric or decimal types this is
160         * precision. </li>
161         * <li> <B>BUFFER_LENGTH</B> is not used. </li>
162         * <li> <B>DECIMAL_DIGITS</B> int => the number of fractional digits </li>
163         * <li> <B>NUM_PREC_RADIX</B> int => Radix (typically either 10 or 2) </li>
164         * <li> <B>NULLABLE</B> int => is NULL allowed?
165         * <UL>
166         * <li> columnNoNulls - might not allow NULL values </li>
167         * <li> columnNullable - definitely allows NULL values </li>
168         * <li> columnNullableUnknown - nullability unknown </li>
169         * </ul>
170         * </li>
171         * <li> <B>REMARKS</B> String => comment describing column (may be null)
172         * </li>
173         * <li> <B>COLUMN_DEF</B> String => default value (may be null) </li>
174         * <li> <B>SQL_DATA_TYPE</B> int => unused </li>
175         * <li> <B>SQL_DATETIME_SUB</B> int => unused </li>
176         * <li> <B>CHAR_OCTET_LENGTH</B> int => for char types the maximum number
177         * of bytes in the column </li>
178         * <li> <B>ORDINAL_POSITION</B> int => index of column in table (starting
179         * at 1) </li>
180         * <li> <B>IS_NULLABLE</B> String => "NO" means column definitely does not
181         * allow NULL values; "YES" means the column might allow NULL values. An
182         * empty string means nobody knows. </li>
183         * </ol>
184         * </p>
185         */
186        public ResultSet getColumns(String catalog, String schemaPattern,
187                        String tableName, String columnNamePattern) throws SQLException {
188                if (columnNamePattern == null) {
189                        if (this.conn.getNullNamePatternMatchesAll()) {
190                                columnNamePattern = "%";
191                        } else {
192                                throw SQLError.createSQLException(
193                                                "Column name pattern can not be NULL or empty.",
194                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
195                        }
196                }
197 
198                if (catalog == null) {
199                        if (!this.conn.getNullCatalogMeansCurrent()) {
200                                throw SQLError.createSQLException("'catalog' parameter can not be null",
201                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
202                        }
203 
204                        catalog = this.database;
205                }
206 
207                StringBuffer sqlBuf = new StringBuffer("SELECT "
208                                + "TABLE_SCHEMA AS TABLE_CAT, " + "NULL AS TABLE_SCHEM,"
209                                + "TABLE_NAME," + "COLUMN_NAME,");
210                MysqlDefs.appendJdbcTypeMappingQuery(sqlBuf, "DATA_TYPE");
211 
212                sqlBuf.append(" AS DATA_TYPE, ");
213 
214                if (conn.getCapitalizeTypeNames()) {
215                        sqlBuf.append("UPPER(CASE WHEN LOCATE('unsigned', COLUMN_TYPE) != 0 AND LOCATE('unsigned', DATA_TYPE) = 0 THEN CONCAT(DATA_TYPE, ' unsigned') ELSE DATA_TYPE END) AS TYPE_NAME,");
216                } else {
217                        sqlBuf.append("CASE WHEN LOCATE('unsigned', COLUMN_TYPE) != 0 AND LOCATE('unsigned', DATA_TYPE) = 0 THEN CONCAT(DATA_TYPE, ' unsigned') ELSE DATA_TYPE END AS TYPE_NAME,");
218                }
219 
220                sqlBuf
221                                .append("CASE WHEN CHARACTER_MAXIMUM_LENGTH IS NULL THEN NUMERIC_PRECISION ELSE CHARACTER_MAXIMUM_LENGTH END AS COLUMN_SIZE, "
222                                                + " NULL AS BUFFER_LENGTH,"
223                                                + "NUMERIC_SCALE AS DECIMAL_DIGITS,"
224                                                + "10 AS NUM_PREC_RADIX,"
225                                                + "NULL AS NULLABLE,"
226                                                + "COLUMN_COMMENT AS REMARKS,"
227                                                + "COLUMN_DEFAULT AS COLUMN_DEF,"
228                                                + "NULL AS SQL_DATA_TYPE,"
229                                                + "NULL AS SQL_DATETIME_SUB,"
230                                                + "CHARACTER_OCTET_LENGTH AS CHAR_OCTET_LENGTH,"
231                                                + "ORDINAL_POSITION,"
232                                                + "IS_NULLABLE "
233                                                + "FROM INFORMATION_SCHEMA.COLUMNS WHERE "
234                                                + "TABLE_SCHEMA LIKE ? AND TABLE_NAME LIKE ? AND COLUMN_NAME LIKE ? "
235                                                + "ORDER BY TABLE_SCHEMA, TABLE_NAME, ORDINAL_POSITION");
236 
237                PreparedStatement pStmt = null;
238 
239                try {
240                        pStmt = prepareMetaDataSafeStatement(sqlBuf.toString());
241                        pStmt.setString(1, catalog);
242                        pStmt.setString(2, tableName);
243                        pStmt.setString(3, columnNamePattern);
244 
245                        ResultSet rs = executeMetadataQuery(pStmt);
246 
247                        ((com.mysql.jdbc.ResultSet) rs).redefineFieldsForDBMD(new Field[] {
248                                        new Field("", "TABLE_CAT", Types.CHAR, 255),
249                                        new Field("", "TABLE_SCHEM", Types.CHAR, 0),
250                                        new Field("", "TABLE_NAME", Types.CHAR, 255),
251                                        new Field("", "COLUMN_NAME", Types.CHAR, 32),
252                                        new Field("", "DATA_TYPE", Types.SMALLINT, 5),
253                                        new Field("", "TYPE_NAME", Types.CHAR, 16),
254                                        new Field("", "COLUMN_SIZE", Types.INTEGER, Integer
255                                                        .toString(Integer.MAX_VALUE).length()),
256                                        new Field("", "BUFFER_LENGTH", Types.INTEGER, 10),
257                                        new Field("", "DECIMAL_DIGITS", Types.INTEGER, 10),
258                                        new Field("", "NUM_PREC_RADIX", Types.INTEGER, 10),
259                                        new Field("", "NULLABLE", Types.INTEGER, 10),
260                                        new Field("", "REMARKS", Types.CHAR, 0),
261                                        new Field("", "COLUMN_DEF", Types.CHAR, 0),
262                                        new Field("", "SQL_DATA_TYPE", Types.INTEGER, 10),
263                                        new Field("", "SQL_DATETIME_SUB", Types.INTEGER, 10),
264                                        new Field("", "CHAR_OCTET_LENGTH", Types.INTEGER, Integer
265                                                        .toString(Integer.MAX_VALUE).length()),
266                                        new Field("", "ORDINAL_POSITION", Types.INTEGER, 10),
267                                        new Field("", "IS_NULLABLE", Types.CHAR, 3) });
268 
269                        return rs;
270                } finally {
271                        if (pStmt != null) {
272                                pStmt.close();
273                        }
274                }
275        }
276 
277        /**
278         * Get a description of the foreign key columns in the foreign key table
279         * that reference the primary key columns of the primary key table (describe
280         * how one table imports another's key.) This should normally return a
281         * single foreign key/primary key pair (most tables only import a foreign
282         * key from a table once.) They are ordered by FKTABLE_CAT, FKTABLE_SCHEM,
283         * FKTABLE_NAME, and KEY_SEQ.
284         * <P>
285         * Each foreign key column description has the following columns:
286         * <OL>
287         * <li> <B>PKTABLE_CAT</B> String => primary key table catalog (may be
288         * null) </li>
289         * <li> <B>PKTABLE_SCHEM</B> String => primary key table schema (may be
290         * null) </li>
291         * <li> <B>PKTABLE_NAME</B> String => primary key table name </li>
292         * <li> <B>PKCOLUMN_NAME</B> String => primary key column name </li>
293         * <li> <B>FKTABLE_CAT</B> String => foreign key table catalog (may be
294         * null) being exported (may be null) </li>
295         * <li> <B>FKTABLE_SCHEM</B> String => foreign key table schema (may be
296         * null) being exported (may be null) </li>
297         * <li> <B>FKTABLE_NAME</B> String => foreign key table name being exported
298         * </li>
299         * <li> <B>FKCOLUMN_NAME</B> String => foreign key column name being
300         * exported </li>
301         * <li> <B>KEY_SEQ</B> short => sequence number within foreign key </li>
302         * <li> <B>UPDATE_RULE</B> short => What happens to foreign key when
303         * primary is updated:
304         * <UL>
305         * <li> importedKeyCascade - change imported key to agree with primary key
306         * update </li>
307         * <li> importedKeyRestrict - do not allow update of primary key if it has
308         * been imported </li>
309         * <li> importedKeySetNull - change imported key to NULL if its primary key
310         * has been updated </li>
311         * </ul>
312         * </li>
313         * <li> <B>DELETE_RULE</B> short => What happens to the foreign key when
314         * primary is deleted.
315         * <UL>
316         * <li> importedKeyCascade - delete rows that import a deleted key </li>
317         * <li> importedKeyRestrict - do not allow delete of primary key if it has
318         * been imported </li>
319         * <li> importedKeySetNull - change imported key to NULL if its primary key
320         * has been deleted </li>
321         * </ul>
322         * </li>
323         * <li> <B>FK_NAME</B> String => foreign key identifier (may be null) </li>
324         * <li> <B>PK_NAME</B> String => primary key identifier (may be null) </li>
325         * </ol>
326         * </p>
327         * 
328         * @param primaryCatalog
329         *            a catalog name; "" retrieves those without a catalog
330         * @param primarySchema
331         *            a schema name pattern; "" retrieves those without a schema
332         * @param primaryTable
333         *            a table name
334         * @param foreignCatalog
335         *            a catalog name; "" retrieves those without a catalog
336         * @param foreignSchema
337         *            a schema name pattern; "" retrieves those without a schema
338         * @param foreignTable
339         *            a table name
340         * @return ResultSet each row is a foreign key column description
341         * @throws SQLException
342         *             if a database access error occurs
343         */
344        public java.sql.ResultSet getCrossReference(String primaryCatalog,
345                        String primarySchema, String primaryTable, String foreignCatalog,
346                        String foreignSchema, String foreignTable) throws SQLException {
347                if (primaryTable == null) {
348                        throw SQLError.createSQLException("Table not specified.",
349                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
350                }
351 
352                if (primaryCatalog == null) {
353                        if (!this.conn.getNullCatalogMeansCurrent()) {
354                                throw SQLError.createSQLException("'catalog' parameter can not be null",
355                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
356                        }
357 
358                        primaryCatalog = this.database;
359                }
360 
361                if (foreignCatalog == null) {
362                        if (!this.conn.getNullCatalogMeansCurrent()) {
363                                throw SQLError.createSQLException("'catalog' parameter can not be null",
364                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
365                        }
366 
367                        foreignCatalog = this.database;
368                }
369 
370                Field[] fields = new Field[14];
371                fields[0] = new Field("", "PKTABLE_CAT", Types.CHAR, 255);
372                fields[1] = new Field("", "PKTABLE_SCHEM", Types.CHAR, 0);
373                fields[2] = new Field("", "PKTABLE_NAME", Types.CHAR, 255);
374                fields[3] = new Field("", "PKCOLUMN_NAME", Types.CHAR, 32);
375                fields[4] = new Field("", "FKTABLE_CAT", Types.CHAR, 255);
376                fields[5] = new Field("", "FKTABLE_SCHEM", Types.CHAR, 0);
377                fields[6] = new Field("", "FKTABLE_NAME", Types.CHAR, 255);
378                fields[7] = new Field("", "FKCOLUMN_NAME", Types.CHAR, 32);
379                fields[8] = new Field("", "KEY_SEQ", Types.SMALLINT, 2);
380                fields[9] = new Field("", "UPDATE_RULE", Types.SMALLINT, 2);
381                fields[10] = new Field("", "DELETE_RULE", Types.SMALLINT, 2);
382                fields[11] = new Field("", "FK_NAME", Types.CHAR, 0);
383                fields[12] = new Field("", "PK_NAME", Types.CHAR, 0);
384                fields[13] = new Field("", "DEFERRABILITY", Types.INTEGER, 2);
385 
386                String sql = "SELECT "
387                                + "A.REFERENCED_TABLE_SCHEMA AS PKTABLE_CAT,"
388                                + "NULL AS PKTABLE_SCHEM,"
389                                + "A.REFERENCED_TABLE_NAME AS PKTABLE_NAME,"
390                                + "A.REFERENCED_COLUMN_NAME AS PKCOLUMN_NAME,"
391                                + "A.TABLE_SCHEMA AS FKTABLE_CAT,"
392                                + "NULL AS FKTABLE_SCHEM,"
393                                + "A.TABLE_NAME AS FKTABLE_NAME, "
394                                + "A.COLUMN_NAME AS FKCOLUMN_NAME, "
395                                + "A.ORDINAL_POSITION AS KEY_SEQ,"
396                                + importedKeyRestrict
397                                + " AS UPDATE_RULE,"
398                                + importedKeyRestrict
399                                + " AS DELETE_RULE,"
400                                + "A.CONSTRAINT_NAME AS FK_NAME,"
401                                + "NULL AS PK_NAME,"
402                                + importedKeyNotDeferrable
403                                + " AS DEFERRABILITY "
404                                + "FROM "
405                                + "INFORMATION_SCHEMA.KEY_COLUMN_USAGE A,"
406                                + "INFORMATION_SCHEMA.TABLE_CONSTRAINTS B "
407                                + "WHERE "
408                                + "A.TABLE_SCHEMA=B.TABLE_SCHEMA AND A.TABLE_NAME=B.TABLE_NAME "
409                                + "AND "
410                                + "A.CONSTRAINT_NAME=B.CONSTRAINT_NAME AND B.CONSTRAINT_TYPE IS NOT NULL "
411                                + "AND A.REFERENCED_TABLE_SCHEMA=? AND A.REFERENCED_TABLE_NAME=? "
412                                + "AND A.TABLE_SCHEMA=? AND A.TABLE_NAME=? " + "ORDER BY "
413                                + "A.TABLE_SCHEMA, A.TABLE_NAME, A.ORDINAL_POSITION";
414 
415                PreparedStatement pStmt = null;
416 
417                try {
418                        pStmt = prepareMetaDataSafeStatement(sql);
419                        pStmt.setString(1, primaryCatalog);
420                        pStmt.setString(2, primaryTable);
421                        pStmt.setString(3, foreignCatalog);
422                        pStmt.setString(4, foreignTable);
423 
424                        ResultSet rs = executeMetadataQuery(pStmt);
425                        ((com.mysql.jdbc.ResultSet) rs).redefineFieldsForDBMD(new Field[] {
426                                        new Field("", "PKTABLE_CAT", Types.CHAR, 255),
427                                        new Field("", "PKTABLE_SCHEM", Types.CHAR, 0),
428                                        new Field("", "PKTABLE_NAME", Types.CHAR, 255),
429                                        new Field("", "PKCOLUMN_NAME", Types.CHAR, 32),
430                                        new Field("", "FKTABLE_CAT", Types.CHAR, 255),
431                                        new Field("", "FKTABLE_SCHEM", Types.CHAR, 0),
432                                        new Field("", "FKTABLE_NAME", Types.CHAR, 255),
433                                        new Field("", "FKCOLUMN_NAME", Types.CHAR, 32),
434                                        new Field("", "KEY_SEQ", Types.SMALLINT, 2),
435                                        new Field("", "UPDATE_RULE", Types.SMALLINT, 2),
436                                        new Field("", "DELETE_RULE", Types.SMALLINT, 2),
437                                        new Field("", "FK_NAME", Types.CHAR, 0),
438                                        new Field("", "PK_NAME", Types.CHAR, 0),
439                                        new Field("", "DEFERRABILITY", Types.INTEGER, 2) });
440 
441                        return rs;
442                } finally {
443                        if (pStmt != null) {
444                                pStmt.close();
445                        }
446                }
447        }
448 
449        /**
450         * Get a description of a foreign key columns that reference a table's
451         * primary key columns (the foreign keys exported by a table). They are
452         * ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.
453         * <P>
454         * Each foreign key column description has the following columns:
455         * <OL>
456         * <li> <B>PKTABLE_CAT</B> String => primary key table catalog (may be
457         * null) </li>
458         * <li> <B>PKTABLE_SCHEM</B> String => primary key table schema (may be
459         * null) </li>
460         * <li> <B>PKTABLE_NAME</B> String => primary key table name </li>
461         * <li> <B>PKCOLUMN_NAME</B> String => primary key column name </li>
462         * <li> <B>FKTABLE_CAT</B> String => foreign key table catalog (may be
463         * null) being exported (may be null) </li>
464         * <li> <B>FKTABLE_SCHEM</B> String => foreign key table schema (may be
465         * null) being exported (may be null) </li>
466         * <li> <B>FKTABLE_NAME</B> String => foreign key table name being exported
467         * </li>
468         * <li> <B>FKCOLUMN_NAME</B> String => foreign key column name being
469         * exported </li>
470         * <li> <B>KEY_SEQ</B> short => sequence number within foreign key </li>
471         * <li> <B>UPDATE_RULE</B> short => What happens to foreign key when
472         * primary is updated:
473         * <UL>
474         * <li> importedKeyCascade - change imported key to agree with primary key
475         * update </li>
476         * <li> importedKeyRestrict - do not allow update of primary key if it has
477         * been imported </li>
478         * <li> importedKeySetNull - change imported key to NULL if its primary key
479         * has been updated </li>
480         * </ul>
481         * </li>
482         * <li> <B>DELETE_RULE</B> short => What happens to the foreign key when
483         * primary is deleted.
484         * <UL>
485         * <li> importedKeyCascade - delete rows that import a deleted key </li>
486         * <li> importedKeyRestrict - do not allow delete of primary key if it has
487         * been imported </li>
488         * <li> importedKeySetNull - change imported key to NULL if its primary key
489         * has been deleted </li>
490         * </ul>
491         * </li>
492         * <li> <B>FK_NAME</B> String => foreign key identifier (may be null) </li>
493         * <li> <B>PK_NAME</B> String => primary key identifier (may be null) </li>
494         * </ol>
495         * </p>
496         * 
497         * @param catalog
498         *            a catalog name; "" retrieves those without a catalog
499         * @param schema
500         *            a schema name pattern; "" retrieves those without a schema
501         * @param table
502         *            a table name
503         * @return ResultSet each row is a foreign key column description
504         * @throws SQLException
505         *             if a database access error occurs
506         * @see #getImportedKeys
507         */
508        public java.sql.ResultSet getExportedKeys(String catalog, String schema,
509                        String table) throws SQLException {
510                // TODO: Can't determine actions using INFORMATION_SCHEMA yet...
511 
512                if (table == null) {
513                        throw SQLError.createSQLException("Table not specified.",
514                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
515                }
516 
517                if (catalog == null) {
518                        if (!this.conn.getNullCatalogMeansCurrent()) {
519                                throw SQLError.createSQLException("'catalog' parameter can not be null",
520                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
521                        }
522 
523                        catalog = this.database;
524                }
525 
526                String sql = "SELECT "
527                                + "A.REFERENCED_TABLE_SCHEMA AS PKTABLE_CAT,"
528                                + "NULL AS PKTABLE_SCHEM,"
529                                + "A.REFERENCED_TABLE_NAME AS PKTABLE_NAME, "
530                                + "A.REFERENCED_COLUMN_NAME AS PKCOLUMN_NAME, "
531                                + "A.TABLE_SCHEMA AS FKTABLE_CAT,"
532                                + "NULL AS FKTABLE_SCHEM,"
533                                + "A.TABLE_NAME AS FKTABLE_NAME,"
534                                + "A.COLUMN_NAME AS FKCOLUMN_NAME, "
535                                + "A.ORDINAL_POSITION AS KEY_SEQ,"
536                                + importedKeyRestrict
537                                + " AS UPDATE_RULE,"
538                                + importedKeyRestrict
539                                + " AS DELETE_RULE,"
540                                + "A.CONSTRAINT_NAME AS FK_NAME,"
541                                + "NULL AS PK_NAME,"
542                                + importedKeyNotDeferrable
543                                + " AS DEFERRABILITY "
544                                + "FROM "
545                                + "INFORMATION_SCHEMA.KEY_COLUMN_USAGE A,"
546                                + "INFORMATION_SCHEMA.TABLE_CONSTRAINTS B "
547                                + "WHERE "
548                                + "A.TABLE_SCHEMA=B.TABLE_SCHEMA AND A.TABLE_NAME=B.TABLE_NAME "
549                                + "AND "
550                                + "A.CONSTRAINT_NAME=B.CONSTRAINT_NAME AND B.CONSTRAINT_TYPE IS NOT NULL "
551                                + "AND A.REFERENCED_TABLE_SCHEMA=? AND A.REFERENCED_TABLE_NAME=? "
552                                + "ORDER BY A.TABLE_SCHEMA, A.TABLE_NAME, A.ORDINAL_POSITION";
553 
554                PreparedStatement pStmt = null;
555 
556                try {
557                        pStmt = prepareMetaDataSafeStatement(sql);
558                        pStmt.setString(1, catalog);
559                        pStmt.setString(2, table);
560 
561                        ResultSet rs = executeMetadataQuery(pStmt);
562 
563                        ((com.mysql.jdbc.ResultSet) rs).redefineFieldsForDBMD(new Field[] {
564                                        new Field("", "PKTABLE_CAT", Types.CHAR, 255),
565                                        new Field("", "PKTABLE_SCHEM", Types.CHAR, 0),
566                                        new Field("", "PKTABLE_NAME", Types.CHAR, 255),
567                                        new Field("", "PKCOLUMN_NAME", Types.CHAR, 32),
568                                        new Field("", "FKTABLE_CAT", Types.CHAR, 255),
569                                        new Field("", "FKTABLE_SCHEM", Types.CHAR, 0),
570                                        new Field("", "FKTABLE_NAME", Types.CHAR, 255),
571                                        new Field("", "FKCOLUMN_NAME", Types.CHAR, 32),
572                                        new Field("", "KEY_SEQ", Types.SMALLINT, 2),
573                                        new Field("", "UPDATE_RULE", Types.SMALLINT, 2),
574                                        new Field("", "DELETE_RULE", Types.SMALLINT, 2),
575                                        new Field("", "FK_NAME", Types.CHAR, 255),
576                                        new Field("", "PK_NAME", Types.CHAR, 0),
577                                        new Field("", "DEFERRABILITY", Types.INTEGER, 2) });
578 
579                        return rs;
580                } finally {
581                        if (pStmt != null) {
582                                pStmt.close();
583                        }
584                }
585 
586        }
587 
588        /*
589         * 
590         * getTablePrivileges
591         * 
592         * if (getMysqlVersion() > 49999) { if (!strcasecmp("localhost",
593         * m_pSettings->pConnection->host)) { sprintf(user, "A.GRANTEE =
594         * \"'%s'@'localhost'\" OR A.GRANTEE LIKE \"'%'@'localhost'\"",
595         * m_pSettings->pConnection->user, m_pSettings->pConnection->user); } else {
596         * sprintf(user, "\"'%s'@'%s'\" LIKE A.GRANTEE",
597         * m_pSettings->pConnection->user, m_pSettings->pConnection->host); }
598         * 
599         * sprintf(query, "SELECT DISTINCT A.TABLE_CATALOG, B.TABLE_SCHEMA,
600         * B.TABLE_NAME, CURRENT_USER(), " \ "A.PRIVILEGE_TYPE FROM
601         * INFORMATION_SCHEMA.USER_PRIVILEGES A, INFORMATION_SCHEMA.TABLES B " \
602         * "WHERE B.TABLE_SCHEMA LIKE '%s' AND B.TABLE_NAME LIKE '%s' AND (%s) " \
603         * "UNION " \ "SELECT DISTINCT A.TABLE_CATALOG, B.TABLE_SCHEMA,
604         * B.TABLE_NAME, CURRENT_USER(), A.PRIVILEGE_TYPE " \ "FROM
605         * INFORMATION_SCHEMA.SCHEMA_PRIVILEGES A, INFORMATION_SCHEMA.TABLES B WHERE " \
606         * "B.TABLE_SCHEMA LIKE '%s' AND B.TABLE_NAME LIKE '%s' AND (%s) " \ "UNION "\
607         * "SELECT DISTINCT A.TABLE_CATALOG, A.TABLE_SCHEMA, A.TABLE_NAME,
608         * CURRENT_USER, A.PRIVILEGE_TYPE FROM " \
609         * "INFORMATION_SCHEMA.TABLE_PRIVILEGES A WHERE A.TABLE_SCHEMA LIKE '%s' AND
610         * A.TABLE_NAME LIKE '%s' " \ "AND (%s)", schemaName, tableName, user,
611         * schemaName, tableName, user, schemaName, tableName, user );
612         */
613 
614        /**
615         * Get a description of the primary key columns that are referenced by a
616         * table's foreign key columns (the primary keys imported by a table). They
617         * are ordered by PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.
618         * <P>
619         * Each primary key column description has the following columns:
620         * <OL>
621         * <li> <B>PKTABLE_CAT</B> String => primary key table catalog being
622         * imported (may be null) </li>
623         * <li> <B>PKTABLE_SCHEM</B> String => primary key table schema being
624         * imported (may be null) </li>
625         * <li> <B>PKTABLE_NAME</B> String => primary key table name being imported
626         * </li>
627         * <li> <B>PKCOLUMN_NAME</B> String => primary key column name being
628         * imported </li>
629         * <li> <B>FKTABLE_CAT</B> String => foreign key table catalog (may be
630         * null) </li>
631         * <li> <B>FKTABLE_SCHEM</B> String => foreign key table schema (may be
632         * null) </li>
633         * <li> <B>FKTABLE_NAME</B> String => foreign key table name </li>
634         * <li> <B>FKCOLUMN_NAME</B> String => foreign key column name </li>
635         * <li> <B>KEY_SEQ</B> short => sequence number within foreign key </li>
636         * <li> <B>UPDATE_RULE</B> short => What happens to foreign key when
637         * primary is updated:
638         * <UL>
639         * <li> importedKeyCascade - change imported key to agree with primary key
640         * update </li>
641         * <li> importedKeyRestrict - do not allow update of primary key if it has
642         * been imported </li>
643         * <li> importedKeySetNull - change imported key to NULL if its primary key
644         * has been updated </li>
645         * </ul>
646         * </li>
647         * <li> <B>DELETE_RULE</B> short => What happens to the foreign key when
648         * primary is deleted.
649         * <UL>
650         * <li> importedKeyCascade - delete rows that import a deleted key </li>
651         * <li> importedKeyRestrict - do not allow delete of primary key if it has
652         * been imported </li>
653         * <li> importedKeySetNull - change imported key to NULL if its primary key
654         * has been deleted </li>
655         * </ul>
656         * </li>
657         * <li> <B>FK_NAME</B> String => foreign key name (may be null) </li>
658         * <li> <B>PK_NAME</B> String => primary key name (may be null) </li>
659         * </ol>
660         * </p>
661         * 
662         * @param catalog
663         *            a catalog name; "" retrieves those without a catalog
664         * @param schema
665         *            a schema name pattern; "" retrieves those without a schema
666         * @param table
667         *            a table name
668         * @return ResultSet each row is a primary key column description
669         * @throws SQLException
670         *             if a database access error occurs
671         * @see #getExportedKeys
672         */
673        public java.sql.ResultSet getImportedKeys(String catalog, String schema,
674                        String table) throws SQLException {
675                if (table == null) {
676                        throw SQLError.createSQLException("Table not specified.",
677                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
678                }
679 
680                if (catalog == null) {
681                        if (!this.conn.getNullCatalogMeansCurrent()) {
682                                throw SQLError.createSQLException("'catalog' parameter can not be null",
683                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
684                        }
685 
686                        catalog = this.database;
687                }
688 
689                String sql = "SELECT "
690                                + "A.REFERENCED_TABLE_SCHEMA AS PKTABLE_CAT,"
691                                + "NULL AS PKTABLE_SCHEM,"
692                                + "A.REFERENCED_TABLE_NAME AS PKTABLE_NAME,"
693                                + "A.REFERENCED_COLUMN_NAME AS PKCOLUMN_NAME,"
694                                + "A.TABLE_SCHEMA AS FKTABLE_CAT,"
695                                + "NULL AS FKTABLE_SCHEM,"
696                                + "A.TABLE_NAME AS FKTABLE_NAME, "
697                                + "A.COLUMN_NAME AS FKCOLUMN_NAME, "
698                                + "A.ORDINAL_POSITION AS KEY_SEQ,"
699                                + importedKeyRestrict
700                                + " AS UPDATE_RULE,"
701                                + importedKeyRestrict
702                                + " AS DELETE_RULE,"
703                                + "A.CONSTRAINT_NAME AS FK_NAME,"
704                                + "NULL AS PK_NAME, "
705                                + importedKeyNotDeferrable
706                                + " AS DEFERRABILITY "
707                                + "FROM "
708                                + "INFORMATION_SCHEMA.KEY_COLUMN_USAGE A, "
709                                + "INFORMATION_SCHEMA.TABLE_CONSTRAINTS B WHERE A.TABLE_SCHEMA=? "
710                                + "AND A.CONSTRAINT_NAME=B.CONSTRAINT_NAME AND A.TABLE_NAME=? "
711                                + "AND "
712                                + "B.TABLE_NAME=? AND A.REFERENCED_TABLE_SCHEMA IS NOT NULL "
713                                + " ORDER BY "
714                                + "A.REFERENCED_TABLE_SCHEMA, A.REFERENCED_TABLE_NAME, "
715                                + "A.ORDINAL_POSITION";
716 
717                PreparedStatement pStmt = null;
718 
719                try {
720                        pStmt = prepareMetaDataSafeStatement(sql);
721                        pStmt.setString(1, catalog);
722                        pStmt.setString(2, table);
723                        pStmt.setString(3, table);
724 
725                        ResultSet rs = executeMetadataQuery(pStmt);
726 
727                        ((com.mysql.jdbc.ResultSet) rs).redefineFieldsForDBMD(new Field[] {
728                                        new Field("", "PKTABLE_CAT", Types.CHAR, 255),
729                                        new Field("", "PKTABLE_SCHEM", Types.CHAR, 0),
730                                        new Field("", "PKTABLE_NAME", Types.CHAR, 255),
731                                        new Field("", "PKCOLUMN_NAME", Types.CHAR, 32),
732                                        new Field("", "FKTABLE_CAT", Types.CHAR, 255),
733                                        new Field("", "FKTABLE_SCHEM", Types.CHAR, 0),
734                                        new Field("", "FKTABLE_NAME", Types.CHAR, 255),
735                                        new Field("", "FKCOLUMN_NAME", Types.CHAR, 32),
736                                        new Field("", "KEY_SEQ", Types.SMALLINT, 2),
737                                        new Field("", "UPDATE_RULE", Types.SMALLINT, 2),
738                                        new Field("", "DELETE_RULE", Types.SMALLINT, 2),
739                                        new Field("", "FK_NAME", Types.CHAR, 255),
740                                        new Field("", "PK_NAME", Types.CHAR, 0),
741                                        new Field("", "DEFERRABILITY", Types.INTEGER, 2) });
742 
743                        return rs;
744                } finally {
745                        if (pStmt != null) {
746                                pStmt.close();
747                        }
748                }
749        }
750 
751        /**
752         * Get a description of a table's indices and statistics. They are ordered
753         * by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.
754         * <P>
755         * Each index column description has the following columns:
756         * <OL>
757         * <li> <B>TABLE_CAT</B> String => table catalog (may be null) </li>
758         * <li> <B>TABLE_SCHEM</B> String => table schema (may be null) </li>
759         * <li> <B>TABLE_NAME</B> String => table name </li>
760         * <li> <B>NON_UNIQUE</B> boolean => Can index values be non-unique? false
761         * when TYPE is tableIndexStatistic </li>
762         * <li> <B>INDEX_QUALIFIER</B> String => index catalog (may be null); null
763         * when TYPE is tableIndexStatistic </li>
764         * <li> <B>INDEX_NAME</B> String => index name; null when TYPE is
765         * tableIndexStatistic </li>
766         * <li> <B>TYPE</B> short => index type:
767         * <UL>
768         * <li> tableIndexStatistic - this identifies table statistics that are
769         * returned in conjuction with a table's index descriptions </li>
770         * <li> tableIndexClustered - this is a clustered index </li>
771         * <li> tableIndexHashed - this is a hashed index </li>
772         * <li> tableIndexOther - this is some other style of index </li>
773         * </ul>
774         * </li>
775         * <li> <B>ORDINAL_POSITION</B> short => column sequence number within
776         * index; zero when TYPE is tableIndexStatistic </li>
777         * <li> <B>COLUMN_NAME</B> String => column name; null when TYPE is
778         * tableIndexStatistic </li>
779         * <li> <B>ASC_OR_DESC</B> String => column sort sequence, "A" =>
780         * ascending, "D" => descending, may be null if sort sequence is not
781         * supported; null when TYPE is tableIndexStatistic </li>
782         * <li> <B>CARDINALITY</B> int => When TYPE is tableIndexStatisic then this
783         * is the number of rows in the table; otherwise it is the number of unique
784         * values in the index. </li>
785         * <li> <B>PAGES</B> int => When TYPE is tableIndexStatisic then this is
786         * the number of pages used for the table, otherwise it is the number of
787         * pages used for the current index. </li>
788         * <li> <B>FILTER_CONDITION</B> String => Filter condition, if any. (may be
789         * null) </li>
790         * </ol>
791         * </p>
792         * 
793         * @param catalog
794         *            a catalog name; "" retrieves those without a catalog
795         * @param schema
796         *            a schema name pattern; "" retrieves those without a schema
797         * @param table
798         *            a table name
799         * @param unique
800         *            when true, return only indices for unique values; when false,
801         *            return indices regardless of whether unique or not
802         * @param approximate
803         *            when true, result is allowed to reflect approximate or out of
804         *            data values; when false, results are requested to be accurate
805         * @return ResultSet each row is an index column description
806         * @throws SQLException
807         *             DOCUMENT ME!
808         */
809        public ResultSet getIndexInfo(String catalog, String schema, String table,
810                        boolean unique, boolean approximate) throws SQLException {
811                StringBuffer sqlBuf = new StringBuffer("SELECT "
812                                + "TABLE_SCHEMA AS TABLE_CAT, " + "NULL AS TABLE_SCHEM,"
813                                + "TABLE_NAME," + "NON_UNIQUE,"
814                                + "TABLE_SCHEMA AS INDEX_QUALIFIER," + "INDEX_NAME,"
815                                + tableIndexOther + " AS TYPE,"
816                                + "SEQ_IN_INDEX AS ORDINAL_POSITION," + "COLUMN_NAME,"
817                                + "COLLATION AS ASC_OR_DESC," + "CARDINALITY,"
818                                + "NULL AS PAGES," + "NULL AS FILTER_CONDITION "
819                                + "FROM INFORMATION_SCHEMA.STATISTICS WHERE "
820                                + "TABLE_SCHEMA LIKE ? AND " + "TABLE_NAME LIKE ?");
821 
822                if (unique) {
823                        sqlBuf.append(" AND NON_UNIQUE=0 ");
824                }
825 
826                sqlBuf.append("ORDER BY NON_UNIQUE, INDEX_NAME, SEQ_IN_INDEX");
827 
828                PreparedStatement pStmt = null;
829 
830                try {
831                        pStmt = prepareMetaDataSafeStatement(sqlBuf.toString());
832 
833                        pStmt.setString(1, catalog);
834                        pStmt.setString(2, table);
835 
836                        ResultSet rs = executeMetadataQuery(pStmt);
837 
838                        ((com.mysql.jdbc.ResultSet) rs).redefineFieldsForDBMD(new Field[] {
839                                        new Field("", "TABLE_CAT", Types.CHAR, 255),
840                                        new Field("", "TABLE_SCHEM", Types.CHAR, 0),
841                                        new Field("", "TABLE_NAME", Types.CHAR, 255),
842                                        new Field("", "NON_UNIQUE", Types.CHAR, 4),
843                                        new Field("", "INDEX_QUALIFIER", Types.CHAR, 1),
844                                        new Field("", "INDEX_NAME", Types.CHAR, 32),
845                                        new Field("", "TYPE", Types.CHAR, 32),
846                                        new Field("", "ORDINAL_POSITION", Types.SMALLINT, 5),
847                                        new Field("", "COLUMN_NAME", Types.CHAR, 32),
848                                        new Field("", "ASC_OR_DESC", Types.CHAR, 1),
849                                        new Field("", "CARDINALITY", Types.INTEGER, 10),
850                                        new Field("", "PAGES", Types.INTEGER, 10),
851                                        new Field("", "FILTER_CONDITION", Types.CHAR, 32) });
852 
853                        return rs;
854                } finally {
855                        if (pStmt != null) {
856                                pStmt.close();
857                        }
858                }
859        }
860 
861        /**
862         * Get a description of a table's primary key columns. They are ordered by
863         * COLUMN_NAME.
864         * <P>
865         * Each column description has the following columns:
866         * <OL>
867         * <li> <B>TABLE_CAT</B> String => table catalog (may be null) </li>
868         * <li> <B>TABLE_SCHEM</B> String => table schema (may be null) </li>
869         * <li> <B>TABLE_NAME</B> String => table name </li>
870         * <li> <B>COLUMN_NAME</B> String => column name </li>
871         * <li> <B>KEY_SEQ</B> short => sequence number within primary key </li>
872         * <li> <B>PK_NAME</B> String => primary key name (may be null) </li>
873         * </ol>
874         * </p>
875         * 
876         * @param catalog
877         *            a catalog name; "" retrieves those without a catalog
878         * @param schema
879         *            a schema name pattern; "" retrieves those without a schema
880         * @param table
881         *            a table name
882         * @return ResultSet each row is a primary key column description
883         * @throws SQLException
884         *             DOCUMENT ME!
885         */
886        public java.sql.ResultSet getPrimaryKeys(String catalog, String schema,
887                        String table) throws SQLException {
888 
889                if (catalog == null) {
890                        if (!this.conn.getNullCatalogMeansCurrent()) {
891                                throw SQLError.createSQLException("'catalog' parameter can not be null",
892                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
893                        }
894 
895                        catalog = this.database;
896                }
897 
898                if (table == null) {
899                        throw SQLError.createSQLException("Table not specified.",
900                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
901                }
902 
903                String sql = "SELECT TABLE_SCHEMA AS TABLE_CAT, NULL AS TABLE_SCHEM, TABLE_NAME, "
904                                + "COLUMN_NAME, SEQ_IN_INDEX AS KEY_SEQ, 'PRIMARY' AS PK_NAME FROM INFORMATION_SCHEMA.STATISTICS "
905                                + "WHERE TABLE_SCHEMA LIKE ? AND TABLE_NAME LIKE ? AND "
906                                + "INDEX_NAME='PRIMARY' ORDER BY TABLE_SCHEMA, TABLE_NAME, INDEX_NAME, SEQ_IN_INDEX";
907 
908                PreparedStatement pStmt = null;
909 
910                try {
911                        pStmt = prepareMetaDataSafeStatement(sql);
912 
913                        pStmt.setString(1, catalog);
914                        pStmt.setString(2, table);
915 
916                        ResultSet rs = executeMetadataQuery(pStmt);
917                        ((com.mysql.jdbc.ResultSet) rs).redefineFieldsForDBMD(new Field[] {
918                                        new Field("", "TABLE_CAT", Types.CHAR, 255),
919                                        new Field("", "TABLE_SCHEM", Types.CHAR, 0),
920                                        new Field("", "TABLE_NAME", Types.CHAR, 255),
921                                        new Field("", "COLUMN_NAME", Types.CHAR, 32),
922                                        new Field("", "KEY_SEQ", Types.SMALLINT, 5),
923                                        new Field("", "PK_NAME", Types.CHAR, 32) });
924 
925                        return rs;
926                } finally {
927                        if (pStmt != null) {
928                                pStmt.close();
929                        }
930                }
931        }
932 
933        /**
934         * Get a description of stored procedures available in a catalog.
935         * <P>
936         * Only procedure descriptions matching the schema and procedure name
937         * criteria are returned. They are ordered by PROCEDURE_SCHEM, and
938         * PROCEDURE_NAME.
939         * </p>
940         * <P>
941         * Each procedure description has the the following columns:
942         * <OL>
943         * <li> <B>PROCEDURE_CAT</B> String => procedure catalog (may be null)
944         * </li>
945         * <li> <B>PROCEDURE_SCHEM</B> String => procedure schema (may be null)
946         * </li>
947         * <li> <B>PROCEDURE_NAME</B> String => procedure name </li>
948         * <li> reserved for future use </li>
949         * <li> reserved for future use </li>
950         * <li> reserved for future use </li>
951         * <li> <B>REMARKS</B> String => explanatory comment on the procedure </li>
952         * <li> <B>PROCEDURE_TYPE</B> short => kind of procedure:
953         * <UL>
954         * <li> procedureResultUnknown - May return a result </li>
955         * <li> procedureNoResult - Does not return a result </li>
956         * <li> procedureReturnsResult - Returns a result </li>
957         * </ul>
958         * </li>
959         * </ol>
960         * </p>
961         * 
962         * @param catalog
963         *            a catalog name; "" retrieves those without a catalog
964         * @param schemaPattern
965         *            a schema name pattern; "" retrieves those without a schema
966         * @param procedureNamePattern
967         *            a procedure name pattern
968         * @return ResultSet each row is a procedure description
969         * @throws SQLException
970         *             if a database access error occurs
971         * @see #getSearchStringEscape
972         */
973        public ResultSet getProcedures(String catalog, String schemaPattern,
974                        String procedureNamePattern) throws SQLException {
975 
976                if ((procedureNamePattern == null)
977                                || (procedureNamePattern.length() == 0)) {
978                        if (this.conn.getNullNamePatternMatchesAll()) {
979                                procedureNamePattern = "%";
980                        } else {
981                                throw SQLError.createSQLException(
982                                                "Procedure name pattern can not be NULL or empty.",
983                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
984                        }
985                }
986 
987                String db = null;
988 
989                if (catalog == null) {
990                        db = this.database;
991                } else if (catalog.length() > 0) {
992                        db = catalog;
993                } else {
994                        if (!this.conn.getNullCatalogMeansCurrent()) {
995                                throw SQLError.createSQLException("'catalog' parameter can not be null",
996                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
997                        }
998 
999                        catalog = null;
1000                        db = null;
1001                }
1002 
1003                String sql = "SELECT ROUTINE_SCHEMA AS PROCEDURE_CAT, "
1004                                + "NULL AS PROCEDURE_SCHEM, "
1005                                + "ROUTINE_NAME AS PROCEDURE_NAME, " + "NULL AS RESERVED_1, "
1006                                + "NULL AS RESERVED_2, " + "NULL AS RESERVED_3, "
1007                                + "ROUTINE_COMMENT AS REMARKS, "
1008                                + "CASE WHEN ROUTINE_TYPE = 'PROCEDURE' THEN "
1009                                + procedureNoResult + " WHEN ROUTINE_TYPE='FUNCTION' THEN "
1010                                + procedureReturnsResult + " ELSE " + procedureResultUnknown
1011                                + " END AS PROCEDURE_TYPE "
1012                                + "FROM INFORMATION_SCHEMA.ROUTINES WHERE "
1013                                + "ROUTINE_SCHEMA LIKE ? AND ROUTINE_NAME LIKE ? "
1014                                + "ORDER BY ROUTINE_SCHEMA, ROUTINE_NAME";
1015 
1016                PreparedStatement pStmt = null;
1017 
1018                try {
1019                        pStmt = prepareMetaDataSafeStatement(sql);
1020                        pStmt.setString(1, db);
1021                        pStmt.setString(2, procedureNamePattern);
1022 
1023                        ResultSet rs = executeMetadataQuery(pStmt);
1024                        ((com.mysql.jdbc.ResultSet) rs).redefineFieldsForDBMD(new Field[] {
1025                                        new Field("", "PROCEDURE_CAT", Types.CHAR, 0),
1026                                        new Field("", "PROCEDURE_SCHEM", Types.CHAR, 0),
1027                                        new Field("", "PROCEDURE_NAME", Types.CHAR, 0),
1028                                        new Field("", "reserved1", Types.CHAR, 0),
1029                                        new Field("", "reserved2", Types.CHAR, 0),
1030                                        new Field("", "reserved3", Types.CHAR, 0),
1031                                        new Field("", "REMARKS", Types.CHAR, 0),
1032                                        new Field("", "PROCEDURE_TYPE", Types.SMALLINT, 0) });
1033 
1034                        return rs;
1035                } finally {
1036                        if (pStmt != null) {
1037                                pStmt.close();
1038                        }
1039                }
1040        }
1041 
1042        /**
1043         * Get a description of tables available in a catalog.
1044         * <P>
1045         * Only table descriptions matching the catalog, schema, table name and type
1046         * criteria are returned. They are ordered by TABLE_TYPE, TABLE_SCHEM and
1047         * TABLE_NAME.
1048         * </p>
1049         * <P>
1050         * Each table description has the following columns:
1051         * <OL>
1052         * <li> <B>TABLE_CAT</B> String => table catalog (may be null) </li>
1053         * <li> <B>TABLE_SCHEM</B> String => table schema (may be null) </li>
1054         * <li> <B>TABLE_NAME</B> String => table name </li>
1055         * <li> <B>TABLE_TYPE</B> String => table type. Typical types are "TABLE",
1056         * "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS",
1057         * "SYNONYM". </li>
1058         * <li> <B>REMARKS</B> String => explanatory comment on the table </li>
1059         * </ol>
1060         * </p>
1061         * <P>
1062         * <B>Note:</B> Some databases may not return information for all tables.
1063         * </p>
1064         * 
1065         * @param catalog
1066         *            a catalog name; "" retrieves those without a catalog
1067         * @param schemaPattern
1068         *            a schema name pattern; "" retrieves those without a schema
1069         * @param tableNamePattern
1070         *            a table name pattern
1071         * @param types
1072         *            a list of table types to include; null returns all types
1073         * @return ResultSet each row is a table description
1074         * @throws SQLException
1075         *             DOCUMENT ME!
1076         * @see #getSearchStringEscape
1077         */
1078        public ResultSet getTables(String catalog, String schemaPattern,
1079                        String tableNamePattern, String[] types) throws SQLException {
1080                if (catalog == null) {
1081                        if (!this.conn.getNullCatalogMeansCurrent()) {
1082                                throw SQLError.createSQLException("'catalog' parameter can not be null",
1083                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
1084                        }
1085 
1086                        catalog = this.database;
1087                }
1088 
1089                if (tableNamePattern == null) {
1090                        if (this.conn.getNullNamePatternMatchesAll()) {
1091                                tableNamePattern = "%";
1092                        } else {
1093                                throw SQLError.createSQLException(
1094                                                "Table name pattern can not be NULL or empty.",
1095                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
1096                        }
1097                }
1098 
1099                PreparedStatement pStmt = null;
1100 
1101                String sql = "SELECT TABLE_SCHEMA AS TABLE_CAT, "
1102                                + "NULL AS TABLE_SCHEM, TABLE_NAME, "
1103                                + "CASE WHEN TABLE_TYPE='BASE TABLE' THEN 'TABLE' WHEN TABLE_TYPE='TEMPORARY' THEN 'LOCAL_TEMPORARY' ELSE TABLE_TYPE END AS TABLE_TYPE, "
1104                                + "TABLE_COMMENT AS REMARKS "
1105                                + "FROM INFORMATION_SCHEMA.TABLES WHERE "
1106                                + "TABLE_SCHEMA LIKE ? AND TABLE_NAME LIKE ? AND TABLE_TYPE IN (?,?,?) "
1107                                + "ORDER BY TABLE_TYPE, TABLE_SCHEMA, TABLE_NAME";
1108                try {
1109                        pStmt = prepareMetaDataSafeStatement(sql);
1110                        pStmt.setString(1, catalog);
1111                        pStmt.setString(2, tableNamePattern);
1112 
1113                        // This overloading of IN (...) allows us to cache this
1114                        // prepared statement
1115                        if (types == null || types.length == 0) {
1116                                pStmt.setString(3, "BASE TABLE");
1117                                pStmt.setString(4, "VIEW");
1118                                pStmt.setString(5, "TEMPORARY");
1119                        } else {
1120                                pStmt.setNull(3, Types.VARCHAR);
1121                                pStmt.setNull(4, Types.VARCHAR);
1122                                pStmt.setNull(5, Types.VARCHAR);
1123 
1124                                for (int i = 0; i < types.length; i++) {
1125                                        if ("TABLE".equalsIgnoreCase(types[i])) {
1126                                                pStmt.setString(3, "BASE TABLE");
1127                                        }
1128 
1129                                        if ("VIEW".equalsIgnoreCase(types[i])) {
1130                                                pStmt.setString(4, "VIEW");
1131                                        }
1132 
1133                                        if ("LOCAL TEMPORARY".equalsIgnoreCase(types[i])) {
1134                                                pStmt.setString(5, "TEMPORARY");
1135                                        }
1136                                }
1137                        }
1138 
1139                        ResultSet rs = executeMetadataQuery(pStmt);
1140 
1141                        ((com.mysql.jdbc.ResultSet) rs).redefineFieldsForDBMD(new Field[] {
1142                                        new Field("", "TABLE_CAT", java.sql.Types.VARCHAR,
1143                                                        (catalog == null) ? 0 : catalog.length()),
1144                                        new Field("", "TABLE_SCHEM", java.sql.Types.VARCHAR, 0),
1145                                        new Field("", "TABLE_NAME", java.sql.Types.VARCHAR, 255),
1146                                        new Field("", "TABLE_TYPE", java.sql.Types.VARCHAR, 5),
1147                                        new Field("", "REMARKS", java.sql.Types.VARCHAR, 0) });
1148 
1149                        return rs;
1150                } finally {
1151                        if (pStmt != null) {
1152                                pStmt.close();
1153                        }
1154                }
1155        }
1156 
1157        private PreparedStatement prepareMetaDataSafeStatement(String sql)
1158                        throws SQLException {
1159                // Can't use server-side here as we coerce a lot of types to match
1160                // the spec.
1161                PreparedStatement pStmt = this.conn.clientPrepareStatement(sql);
1162 
1163                if (pStmt.getMaxRows() != 0) {
1164                        pStmt.setMaxRows(0);
1165                }
1166 
1167                pStmt.setHoldResultsOpenOverClose(true);
1168 
1169                return pStmt;
1170        }
1171}

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