~ubuntu-branches/ubuntu/oneiric/mysql-connector-java/oneiric

« back to all changes in this revision

Viewing changes to src/com/mysql/jdbc/DatabaseMetaDataUsingInfoSchema.java

  • Committer: Bazaar Package Importer
  • Author(s): Marcus Better
  • Date: 2006-12-29 13:29:04 UTC
  • mfrom: (1.1.3 upstream) (3.1.1 etch)
  • Revision ID: james.westby@ubuntu.com-20061229132904-uj7edcmwgtuxh6li
Tags: 5.0.4+dfsg-2
Corrected the symlink `/usr/share/java/mysql.jar'. Thanks to Javier
Kohen. (Closes: #404858)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 */
 
23
package com.mysql.jdbc;
 
24
 
 
25
import java.sql.ResultSet;
 
26
import java.sql.SQLException;
 
27
import 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
 */
 
36
public 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 CASE WHEN CHARACTER_MAXIMUM_LENGTH > " 
 
222
                                                + Integer.MAX_VALUE + " THEN " + Integer.MAX_VALUE + 
 
223
                                                " ELSE CHARACTER_MAXIMUM_LENGTH END END AS COLUMN_SIZE, "
 
224
                                                + " NULL AS BUFFER_LENGTH,"
 
225
                                                + "NUMERIC_SCALE AS DECIMAL_DIGITS,"
 
226
                                                + "10 AS NUM_PREC_RADIX,"
 
227
                                                + "NULL AS NULLABLE,"
 
228
                                                + "COLUMN_COMMENT AS REMARKS,"
 
229
                                                + "COLUMN_DEFAULT AS COLUMN_DEF,"
 
230
                                                + "NULL AS SQL_DATA_TYPE,"
 
231
                                                + "NULL AS SQL_DATETIME_SUB,"
 
232
                                                + "CHARACTER_OCTET_LENGTH AS CHAR_OCTET_LENGTH,"
 
233
                                                + "ORDINAL_POSITION,"
 
234
                                                + "IS_NULLABLE "
 
235
                                                + "FROM INFORMATION_SCHEMA.COLUMNS WHERE "
 
236
                                                + "TABLE_SCHEMA LIKE ? AND TABLE_NAME LIKE ? AND COLUMN_NAME LIKE ? "
 
237
                                                + "ORDER BY TABLE_SCHEMA, TABLE_NAME, ORDINAL_POSITION");
 
238
 
 
239
                PreparedStatement pStmt = null;
 
240
 
 
241
                try {
 
242
                        pStmt = prepareMetaDataSafeStatement(sqlBuf.toString());
 
243
                        pStmt.setString(1, catalog);
 
244
                        pStmt.setString(2, tableName);
 
245
                        pStmt.setString(3, columnNamePattern);
 
246
 
 
247
                        ResultSet rs = executeMetadataQuery(pStmt);
 
248
 
 
249
                        ((com.mysql.jdbc.ResultSet) rs).redefineFieldsForDBMD(new Field[] {
 
250
                                        new Field("", "TABLE_CAT", Types.CHAR, 255),
 
251
                                        new Field("", "TABLE_SCHEM", Types.CHAR, 0),
 
252
                                        new Field("", "TABLE_NAME", Types.CHAR, 255),
 
253
                                        new Field("", "COLUMN_NAME", Types.CHAR, 32),
 
254
                                        new Field("", "DATA_TYPE", Types.SMALLINT, 5),
 
255
                                        new Field("", "TYPE_NAME", Types.CHAR, 16),
 
256
                                        new Field("", "COLUMN_SIZE", Types.INTEGER, Integer
 
257
                                                        .toString(Integer.MAX_VALUE).length()),
 
258
                                        new Field("", "BUFFER_LENGTH", Types.INTEGER, 10),
 
259
                                        new Field("", "DECIMAL_DIGITS", Types.INTEGER, 10),
 
260
                                        new Field("", "NUM_PREC_RADIX", Types.INTEGER, 10),
 
261
                                        new Field("", "NULLABLE", Types.INTEGER, 10),
 
262
                                        new Field("", "REMARKS", Types.CHAR, 0),
 
263
                                        new Field("", "COLUMN_DEF", Types.CHAR, 0),
 
264
                                        new Field("", "SQL_DATA_TYPE", Types.INTEGER, 10),
 
265
                                        new Field("", "SQL_DATETIME_SUB", Types.INTEGER, 10),
 
266
                                        new Field("", "CHAR_OCTET_LENGTH", Types.INTEGER, Integer
 
267
                                                        .toString(Integer.MAX_VALUE).length()),
 
268
                                        new Field("", "ORDINAL_POSITION", Types.INTEGER, 10),
 
269
                                        new Field("", "IS_NULLABLE", Types.CHAR, 3) });
 
270
 
 
271
                        return rs;
 
272
                } finally {
 
273
                        if (pStmt != null) {
 
274
                                pStmt.close();
 
275
                        }
 
276
                }
 
277
        }
 
278
 
 
279
        /**
 
280
         * Get a description of the foreign key columns in the foreign key table
 
281
         * that reference the primary key columns of the primary key table (describe
 
282
         * how one table imports another's key.) This should normally return a
 
283
         * single foreign key/primary key pair (most tables only import a foreign
 
284
         * key from a table once.) They are ordered by FKTABLE_CAT, FKTABLE_SCHEM,
 
285
         * FKTABLE_NAME, and KEY_SEQ.
 
286
         * <P>
 
287
         * Each foreign key column description has the following columns:
 
288
         * <OL>
 
289
         * <li> <B>PKTABLE_CAT</B> String => primary key table catalog (may be
 
290
         * null) </li>
 
291
         * <li> <B>PKTABLE_SCHEM</B> String => primary key table schema (may be
 
292
         * null) </li>
 
293
         * <li> <B>PKTABLE_NAME</B> String => primary key table name </li>
 
294
         * <li> <B>PKCOLUMN_NAME</B> String => primary key column name </li>
 
295
         * <li> <B>FKTABLE_CAT</B> String => foreign key table catalog (may be
 
296
         * null) being exported (may be null) </li>
 
297
         * <li> <B>FKTABLE_SCHEM</B> String => foreign key table schema (may be
 
298
         * null) being exported (may be null) </li>
 
299
         * <li> <B>FKTABLE_NAME</B> String => foreign key table name being exported
 
300
         * </li>
 
301
         * <li> <B>FKCOLUMN_NAME</B> String => foreign key column name being
 
302
         * exported </li>
 
303
         * <li> <B>KEY_SEQ</B> short => sequence number within foreign key </li>
 
304
         * <li> <B>UPDATE_RULE</B> short => What happens to foreign key when
 
305
         * primary is updated:
 
306
         * <UL>
 
307
         * <li> importedKeyCascade - change imported key to agree with primary key
 
308
         * update </li>
 
309
         * <li> importedKeyRestrict - do not allow update of primary key if it has
 
310
         * been imported </li>
 
311
         * <li> importedKeySetNull - change imported key to NULL if its primary key
 
312
         * has been updated </li>
 
313
         * </ul>
 
314
         * </li>
 
315
         * <li> <B>DELETE_RULE</B> short => What happens to the foreign key when
 
316
         * primary is deleted.
 
317
         * <UL>
 
318
         * <li> importedKeyCascade - delete rows that import a deleted key </li>
 
319
         * <li> importedKeyRestrict - do not allow delete of primary key if it has
 
320
         * been imported </li>
 
321
         * <li> importedKeySetNull - change imported key to NULL if its primary key
 
322
         * has been deleted </li>
 
323
         * </ul>
 
324
         * </li>
 
325
         * <li> <B>FK_NAME</B> String => foreign key identifier (may be null) </li>
 
326
         * <li> <B>PK_NAME</B> String => primary key identifier (may be null) </li>
 
327
         * </ol>
 
328
         * </p>
 
329
         * 
 
330
         * @param primaryCatalog
 
331
         *            a catalog name; "" retrieves those without a catalog
 
332
         * @param primarySchema
 
333
         *            a schema name pattern; "" retrieves those without a schema
 
334
         * @param primaryTable
 
335
         *            a table name
 
336
         * @param foreignCatalog
 
337
         *            a catalog name; "" retrieves those without a catalog
 
338
         * @param foreignSchema
 
339
         *            a schema name pattern; "" retrieves those without a schema
 
340
         * @param foreignTable
 
341
         *            a table name
 
342
         * @return ResultSet each row is a foreign key column description
 
343
         * @throws SQLException
 
344
         *             if a database access error occurs
 
345
         */
 
346
        public java.sql.ResultSet getCrossReference(String primaryCatalog,
 
347
                        String primarySchema, String primaryTable, String foreignCatalog,
 
348
                        String foreignSchema, String foreignTable) throws SQLException {
 
349
                if (primaryTable == null) {
 
350
                        throw SQLError.createSQLException("Table not specified.",
 
351
                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
 
352
                }
 
353
 
 
354
                if (primaryCatalog == null) {
 
355
                        if (!this.conn.getNullCatalogMeansCurrent()) {
 
356
                                throw SQLError.createSQLException("'catalog' parameter can not be null",
 
357
                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
 
358
                        }
 
359
 
 
360
                        primaryCatalog = this.database;
 
361
                }
 
362
 
 
363
                if (foreignCatalog == null) {
 
364
                        if (!this.conn.getNullCatalogMeansCurrent()) {
 
365
                                throw SQLError.createSQLException("'catalog' parameter can not be null",
 
366
                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
 
367
                        }
 
368
 
 
369
                        foreignCatalog = this.database;
 
370
                }
 
371
 
 
372
                Field[] fields = new Field[14];
 
373
                fields[0] = new Field("", "PKTABLE_CAT", Types.CHAR, 255);
 
374
                fields[1] = new Field("", "PKTABLE_SCHEM", Types.CHAR, 0);
 
375
                fields[2] = new Field("", "PKTABLE_NAME", Types.CHAR, 255);
 
376
                fields[3] = new Field("", "PKCOLUMN_NAME", Types.CHAR, 32);
 
377
                fields[4] = new Field("", "FKTABLE_CAT", Types.CHAR, 255);
 
378
                fields[5] = new Field("", "FKTABLE_SCHEM", Types.CHAR, 0);
 
379
                fields[6] = new Field("", "FKTABLE_NAME", Types.CHAR, 255);
 
380
                fields[7] = new Field("", "FKCOLUMN_NAME", Types.CHAR, 32);
 
381
                fields[8] = new Field("", "KEY_SEQ", Types.SMALLINT, 2);
 
382
                fields[9] = new Field("", "UPDATE_RULE", Types.SMALLINT, 2);
 
383
                fields[10] = new Field("", "DELETE_RULE", Types.SMALLINT, 2);
 
384
                fields[11] = new Field("", "FK_NAME", Types.CHAR, 0);
 
385
                fields[12] = new Field("", "PK_NAME", Types.CHAR, 0);
 
386
                fields[13] = new Field("", "DEFERRABILITY", Types.INTEGER, 2);
 
387
 
 
388
                String sql = "SELECT "
 
389
                                + "A.REFERENCED_TABLE_SCHEMA AS PKTABLE_CAT,"
 
390
                                + "NULL AS PKTABLE_SCHEM,"
 
391
                                + "A.REFERENCED_TABLE_NAME AS PKTABLE_NAME,"
 
392
                                + "A.REFERENCED_COLUMN_NAME AS PKCOLUMN_NAME,"
 
393
                                + "A.TABLE_SCHEMA AS FKTABLE_CAT,"
 
394
                                + "NULL AS FKTABLE_SCHEM,"
 
395
                                + "A.TABLE_NAME AS FKTABLE_NAME, "
 
396
                                + "A.COLUMN_NAME AS FKCOLUMN_NAME, "
 
397
                                + "A.ORDINAL_POSITION AS KEY_SEQ,"
 
398
                                + importedKeyRestrict
 
399
                                + " AS UPDATE_RULE,"
 
400
                                + importedKeyRestrict
 
401
                                + " AS DELETE_RULE,"
 
402
                                + "A.CONSTRAINT_NAME AS FK_NAME,"
 
403
                                + "NULL AS PK_NAME,"
 
404
                                + importedKeyNotDeferrable
 
405
                                + " AS DEFERRABILITY "
 
406
                                + "FROM "
 
407
                                + "INFORMATION_SCHEMA.KEY_COLUMN_USAGE A,"
 
408
                                + "INFORMATION_SCHEMA.TABLE_CONSTRAINTS B "
 
409
                                + "WHERE "
 
410
                                + "A.TABLE_SCHEMA=B.TABLE_SCHEMA AND A.TABLE_NAME=B.TABLE_NAME "
 
411
                                + "AND "
 
412
                                + "A.CONSTRAINT_NAME=B.CONSTRAINT_NAME AND B.CONSTRAINT_TYPE IS NOT NULL "
 
413
                                + "AND A.REFERENCED_TABLE_SCHEMA=? AND A.REFERENCED_TABLE_NAME=? "
 
414
                                + "AND A.TABLE_SCHEMA=? AND A.TABLE_NAME=? " + "ORDER BY "
 
415
                                + "A.TABLE_SCHEMA, A.TABLE_NAME, A.ORDINAL_POSITION";
 
416
 
 
417
                PreparedStatement pStmt = null;
 
418
 
 
419
                try {
 
420
                        pStmt = prepareMetaDataSafeStatement(sql);
 
421
                        pStmt.setString(1, primaryCatalog);
 
422
                        pStmt.setString(2, primaryTable);
 
423
                        pStmt.setString(3, foreignCatalog);
 
424
                        pStmt.setString(4, foreignTable);
 
425
 
 
426
                        ResultSet rs = executeMetadataQuery(pStmt);
 
427
                        ((com.mysql.jdbc.ResultSet) rs).redefineFieldsForDBMD(new Field[] {
 
428
                                        new Field("", "PKTABLE_CAT", Types.CHAR, 255),
 
429
                                        new Field("", "PKTABLE_SCHEM", Types.CHAR, 0),
 
430
                                        new Field("", "PKTABLE_NAME", Types.CHAR, 255),
 
431
                                        new Field("", "PKCOLUMN_NAME", Types.CHAR, 32),
 
432
                                        new Field("", "FKTABLE_CAT", Types.CHAR, 255),
 
433
                                        new Field("", "FKTABLE_SCHEM", Types.CHAR, 0),
 
434
                                        new Field("", "FKTABLE_NAME", Types.CHAR, 255),
 
435
                                        new Field("", "FKCOLUMN_NAME", Types.CHAR, 32),
 
436
                                        new Field("", "KEY_SEQ", Types.SMALLINT, 2),
 
437
                                        new Field("", "UPDATE_RULE", Types.SMALLINT, 2),
 
438
                                        new Field("", "DELETE_RULE", Types.SMALLINT, 2),
 
439
                                        new Field("", "FK_NAME", Types.CHAR, 0),
 
440
                                        new Field("", "PK_NAME", Types.CHAR, 0),
 
441
                                        new Field("", "DEFERRABILITY", Types.INTEGER, 2) });
 
442
 
 
443
                        return rs;
 
444
                } finally {
 
445
                        if (pStmt != null) {
 
446
                                pStmt.close();
 
447
                        }
 
448
                }
 
449
        }
 
450
 
 
451
        /**
 
452
         * Get a description of a foreign key columns that reference a table's
 
453
         * primary key columns (the foreign keys exported by a table). They are
 
454
         * ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.
 
455
         * <P>
 
456
         * Each foreign key column description has the following columns:
 
457
         * <OL>
 
458
         * <li> <B>PKTABLE_CAT</B> String => primary key table catalog (may be
 
459
         * null) </li>
 
460
         * <li> <B>PKTABLE_SCHEM</B> String => primary key table schema (may be
 
461
         * null) </li>
 
462
         * <li> <B>PKTABLE_NAME</B> String => primary key table name </li>
 
463
         * <li> <B>PKCOLUMN_NAME</B> String => primary key column name </li>
 
464
         * <li> <B>FKTABLE_CAT</B> String => foreign key table catalog (may be
 
465
         * null) being exported (may be null) </li>
 
466
         * <li> <B>FKTABLE_SCHEM</B> String => foreign key table schema (may be
 
467
         * null) being exported (may be null) </li>
 
468
         * <li> <B>FKTABLE_NAME</B> String => foreign key table name being exported
 
469
         * </li>
 
470
         * <li> <B>FKCOLUMN_NAME</B> String => foreign key column name being
 
471
         * exported </li>
 
472
         * <li> <B>KEY_SEQ</B> short => sequence number within foreign key </li>
 
473
         * <li> <B>UPDATE_RULE</B> short => What happens to foreign key when
 
474
         * primary is updated:
 
475
         * <UL>
 
476
         * <li> importedKeyCascade - change imported key to agree with primary key
 
477
         * update </li>
 
478
         * <li> importedKeyRestrict - do not allow update of primary key if it has
 
479
         * been imported </li>
 
480
         * <li> importedKeySetNull - change imported key to NULL if its primary key
 
481
         * has been updated </li>
 
482
         * </ul>
 
483
         * </li>
 
484
         * <li> <B>DELETE_RULE</B> short => What happens to the foreign key when
 
485
         * primary is deleted.
 
486
         * <UL>
 
487
         * <li> importedKeyCascade - delete rows that import a deleted key </li>
 
488
         * <li> importedKeyRestrict - do not allow delete of primary key if it has
 
489
         * been imported </li>
 
490
         * <li> importedKeySetNull - change imported key to NULL if its primary key
 
491
         * has been deleted </li>
 
492
         * </ul>
 
493
         * </li>
 
494
         * <li> <B>FK_NAME</B> String => foreign key identifier (may be null) </li>
 
495
         * <li> <B>PK_NAME</B> String => primary key identifier (may be null) </li>
 
496
         * </ol>
 
497
         * </p>
 
498
         * 
 
499
         * @param catalog
 
500
         *            a catalog name; "" retrieves those without a catalog
 
501
         * @param schema
 
502
         *            a schema name pattern; "" retrieves those without a schema
 
503
         * @param table
 
504
         *            a table name
 
505
         * @return ResultSet each row is a foreign key column description
 
506
         * @throws SQLException
 
507
         *             if a database access error occurs
 
508
         * @see #getImportedKeys
 
509
         */
 
510
        public java.sql.ResultSet getExportedKeys(String catalog, String schema,
 
511
                        String table) throws SQLException {
 
512
                // TODO: Can't determine actions using INFORMATION_SCHEMA yet...
 
513
 
 
514
                if (table == null) {
 
515
                        throw SQLError.createSQLException("Table not specified.",
 
516
                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
 
517
                }
 
518
 
 
519
                if (catalog == null) {
 
520
                        if (!this.conn.getNullCatalogMeansCurrent()) {
 
521
                                throw SQLError.createSQLException("'catalog' parameter can not be null",
 
522
                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
 
523
                        }
 
524
 
 
525
                        catalog = this.database;
 
526
                }
 
527
 
 
528
                String sql = "SELECT "
 
529
                                + "A.REFERENCED_TABLE_SCHEMA AS PKTABLE_CAT,"
 
530
                                + "NULL AS PKTABLE_SCHEM,"
 
531
                                + "A.REFERENCED_TABLE_NAME AS PKTABLE_NAME, "
 
532
                                + "A.REFERENCED_COLUMN_NAME AS PKCOLUMN_NAME, "
 
533
                                + "A.TABLE_SCHEMA AS FKTABLE_CAT,"
 
534
                                + "NULL AS FKTABLE_SCHEM,"
 
535
                                + "A.TABLE_NAME AS FKTABLE_NAME,"
 
536
                                + "A.COLUMN_NAME AS FKCOLUMN_NAME, "
 
537
                                + "A.ORDINAL_POSITION AS KEY_SEQ,"
 
538
                                + importedKeyRestrict
 
539
                                + " AS UPDATE_RULE,"
 
540
                                + importedKeyRestrict
 
541
                                + " AS DELETE_RULE,"
 
542
                                + "A.CONSTRAINT_NAME AS FK_NAME,"
 
543
                                + "NULL AS PK_NAME,"
 
544
                                + importedKeyNotDeferrable
 
545
                                + " AS DEFERRABILITY "
 
546
                                + "FROM "
 
547
                                + "INFORMATION_SCHEMA.KEY_COLUMN_USAGE A,"
 
548
                                + "INFORMATION_SCHEMA.TABLE_CONSTRAINTS B "
 
549
                                + "WHERE "
 
550
                                + "A.TABLE_SCHEMA=B.TABLE_SCHEMA AND A.TABLE_NAME=B.TABLE_NAME "
 
551
                                + "AND "
 
552
                                + "A.CONSTRAINT_NAME=B.CONSTRAINT_NAME AND B.CONSTRAINT_TYPE IS NOT NULL "
 
553
                                + "AND A.REFERENCED_TABLE_SCHEMA=? AND A.REFERENCED_TABLE_NAME=? "
 
554
                                + "ORDER BY A.TABLE_SCHEMA, A.TABLE_NAME, A.ORDINAL_POSITION";
 
555
 
 
556
                PreparedStatement pStmt = null;
 
557
 
 
558
                try {
 
559
                        pStmt = prepareMetaDataSafeStatement(sql);
 
560
                        pStmt.setString(1, catalog);
 
561
                        pStmt.setString(2, table);
 
562
 
 
563
                        ResultSet rs = executeMetadataQuery(pStmt);
 
564
 
 
565
                        ((com.mysql.jdbc.ResultSet) rs).redefineFieldsForDBMD(new Field[] {
 
566
                                        new Field("", "PKTABLE_CAT", Types.CHAR, 255),
 
567
                                        new Field("", "PKTABLE_SCHEM", Types.CHAR, 0),
 
568
                                        new Field("", "PKTABLE_NAME", Types.CHAR, 255),
 
569
                                        new Field("", "PKCOLUMN_NAME", Types.CHAR, 32),
 
570
                                        new Field("", "FKTABLE_CAT", Types.CHAR, 255),
 
571
                                        new Field("", "FKTABLE_SCHEM", Types.CHAR, 0),
 
572
                                        new Field("", "FKTABLE_NAME", Types.CHAR, 255),
 
573
                                        new Field("", "FKCOLUMN_NAME", Types.CHAR, 32),
 
574
                                        new Field("", "KEY_SEQ", Types.SMALLINT, 2),
 
575
                                        new Field("", "UPDATE_RULE", Types.SMALLINT, 2),
 
576
                                        new Field("", "DELETE_RULE", Types.SMALLINT, 2),
 
577
                                        new Field("", "FK_NAME", Types.CHAR, 255),
 
578
                                        new Field("", "PK_NAME", Types.CHAR, 0),
 
579
                                        new Field("", "DEFERRABILITY", Types.INTEGER, 2) });
 
580
 
 
581
                        return rs;
 
582
                } finally {
 
583
                        if (pStmt != null) {
 
584
                                pStmt.close();
 
585
                        }
 
586
                }
 
587
 
 
588
        }
 
589
 
 
590
        /*
 
591
         * 
 
592
         * getTablePrivileges
 
593
         * 
 
594
         * if (getMysqlVersion() > 49999) { if (!strcasecmp("localhost",
 
595
         * m_pSettings->pConnection->host)) { sprintf(user, "A.GRANTEE =
 
596
         * \"'%s'@'localhost'\" OR A.GRANTEE LIKE \"'%'@'localhost'\"",
 
597
         * m_pSettings->pConnection->user, m_pSettings->pConnection->user); } else {
 
598
         * sprintf(user, "\"'%s'@'%s'\" LIKE A.GRANTEE",
 
599
         * m_pSettings->pConnection->user, m_pSettings->pConnection->host); }
 
600
         * 
 
601
         * sprintf(query, "SELECT DISTINCT A.TABLE_CATALOG, B.TABLE_SCHEMA,
 
602
         * B.TABLE_NAME, CURRENT_USER(), " \ "A.PRIVILEGE_TYPE FROM
 
603
         * INFORMATION_SCHEMA.USER_PRIVILEGES A, INFORMATION_SCHEMA.TABLES B " \
 
604
         * "WHERE B.TABLE_SCHEMA LIKE '%s' AND B.TABLE_NAME LIKE '%s' AND (%s) " \
 
605
         * "UNION " \ "SELECT DISTINCT A.TABLE_CATALOG, B.TABLE_SCHEMA,
 
606
         * B.TABLE_NAME, CURRENT_USER(), A.PRIVILEGE_TYPE " \ "FROM
 
607
         * INFORMATION_SCHEMA.SCHEMA_PRIVILEGES A, INFORMATION_SCHEMA.TABLES B WHERE " \
 
608
         * "B.TABLE_SCHEMA LIKE '%s' AND B.TABLE_NAME LIKE '%s' AND (%s) " \ "UNION "\
 
609
         * "SELECT DISTINCT A.TABLE_CATALOG, A.TABLE_SCHEMA, A.TABLE_NAME,
 
610
         * CURRENT_USER, A.PRIVILEGE_TYPE FROM " \
 
611
         * "INFORMATION_SCHEMA.TABLE_PRIVILEGES A WHERE A.TABLE_SCHEMA LIKE '%s' AND
 
612
         * A.TABLE_NAME LIKE '%s' " \ "AND (%s)", schemaName, tableName, user,
 
613
         * schemaName, tableName, user, schemaName, tableName, user );
 
614
         */
 
615
 
 
616
        /**
 
617
         * Get a description of the primary key columns that are referenced by a
 
618
         * table's foreign key columns (the primary keys imported by a table). They
 
619
         * are ordered by PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.
 
620
         * <P>
 
621
         * Each primary key column description has the following columns:
 
622
         * <OL>
 
623
         * <li> <B>PKTABLE_CAT</B> String => primary key table catalog being
 
624
         * imported (may be null) </li>
 
625
         * <li> <B>PKTABLE_SCHEM</B> String => primary key table schema being
 
626
         * imported (may be null) </li>
 
627
         * <li> <B>PKTABLE_NAME</B> String => primary key table name being imported
 
628
         * </li>
 
629
         * <li> <B>PKCOLUMN_NAME</B> String => primary key column name being
 
630
         * imported </li>
 
631
         * <li> <B>FKTABLE_CAT</B> String => foreign key table catalog (may be
 
632
         * null) </li>
 
633
         * <li> <B>FKTABLE_SCHEM</B> String => foreign key table schema (may be
 
634
         * null) </li>
 
635
         * <li> <B>FKTABLE_NAME</B> String => foreign key table name </li>
 
636
         * <li> <B>FKCOLUMN_NAME</B> String => foreign key column name </li>
 
637
         * <li> <B>KEY_SEQ</B> short => sequence number within foreign key </li>
 
638
         * <li> <B>UPDATE_RULE</B> short => What happens to foreign key when
 
639
         * primary is updated:
 
640
         * <UL>
 
641
         * <li> importedKeyCascade - change imported key to agree with primary key
 
642
         * update </li>
 
643
         * <li> importedKeyRestrict - do not allow update of primary key if it has
 
644
         * been imported </li>
 
645
         * <li> importedKeySetNull - change imported key to NULL if its primary key
 
646
         * has been updated </li>
 
647
         * </ul>
 
648
         * </li>
 
649
         * <li> <B>DELETE_RULE</B> short => What happens to the foreign key when
 
650
         * primary is deleted.
 
651
         * <UL>
 
652
         * <li> importedKeyCascade - delete rows that import a deleted key </li>
 
653
         * <li> importedKeyRestrict - do not allow delete of primary key if it has
 
654
         * been imported </li>
 
655
         * <li> importedKeySetNull - change imported key to NULL if its primary key
 
656
         * has been deleted </li>
 
657
         * </ul>
 
658
         * </li>
 
659
         * <li> <B>FK_NAME</B> String => foreign key name (may be null) </li>
 
660
         * <li> <B>PK_NAME</B> String => primary key name (may be null) </li>
 
661
         * </ol>
 
662
         * </p>
 
663
         * 
 
664
         * @param catalog
 
665
         *            a catalog name; "" retrieves those without a catalog
 
666
         * @param schema
 
667
         *            a schema name pattern; "" retrieves those without a schema
 
668
         * @param table
 
669
         *            a table name
 
670
         * @return ResultSet each row is a primary key column description
 
671
         * @throws SQLException
 
672
         *             if a database access error occurs
 
673
         * @see #getExportedKeys
 
674
         */
 
675
        public java.sql.ResultSet getImportedKeys(String catalog, String schema,
 
676
                        String table) throws SQLException {
 
677
                if (table == null) {
 
678
                        throw SQLError.createSQLException("Table not specified.",
 
679
                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
 
680
                }
 
681
 
 
682
                if (catalog == null) {
 
683
                        if (!this.conn.getNullCatalogMeansCurrent()) {
 
684
                                throw SQLError.createSQLException("'catalog' parameter can not be null",
 
685
                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
 
686
                        }
 
687
 
 
688
                        catalog = this.database;
 
689
                }
 
690
 
 
691
                String sql = "SELECT "
 
692
                                + "A.REFERENCED_TABLE_SCHEMA AS PKTABLE_CAT,"
 
693
                                + "NULL AS PKTABLE_SCHEM,"
 
694
                                + "A.REFERENCED_TABLE_NAME AS PKTABLE_NAME,"
 
695
                                + "A.REFERENCED_COLUMN_NAME AS PKCOLUMN_NAME,"
 
696
                                + "A.TABLE_SCHEMA AS FKTABLE_CAT,"
 
697
                                + "NULL AS FKTABLE_SCHEM,"
 
698
                                + "A.TABLE_NAME AS FKTABLE_NAME, "
 
699
                                + "A.COLUMN_NAME AS FKCOLUMN_NAME, "
 
700
                                + "A.ORDINAL_POSITION AS KEY_SEQ,"
 
701
                                + importedKeyRestrict
 
702
                                + " AS UPDATE_RULE,"
 
703
                                + importedKeyRestrict
 
704
                                + " AS DELETE_RULE,"
 
705
                                + "A.CONSTRAINT_NAME AS FK_NAME,"
 
706
                                + "NULL AS PK_NAME, "
 
707
                                + importedKeyNotDeferrable
 
708
                                + " AS DEFERRABILITY "
 
709
                                + "FROM "
 
710
                                + "INFORMATION_SCHEMA.KEY_COLUMN_USAGE A, "
 
711
                                + "INFORMATION_SCHEMA.TABLE_CONSTRAINTS B WHERE A.TABLE_SCHEMA=? "
 
712
                                + "AND A.CONSTRAINT_NAME=B.CONSTRAINT_NAME AND A.TABLE_NAME=? "
 
713
                                + "AND "
 
714
                                + "B.TABLE_NAME=? AND A.REFERENCED_TABLE_SCHEMA IS NOT NULL "
 
715
                                + " ORDER BY "
 
716
                                + "A.REFERENCED_TABLE_SCHEMA, A.REFERENCED_TABLE_NAME, "
 
717
                                + "A.ORDINAL_POSITION";
 
718
 
 
719
                PreparedStatement pStmt = null;
 
720
 
 
721
                try {
 
722
                        pStmt = prepareMetaDataSafeStatement(sql);
 
723
                        pStmt.setString(1, catalog);
 
724
                        pStmt.setString(2, table);
 
725
                        pStmt.setString(3, table);
 
726
 
 
727
                        ResultSet rs = executeMetadataQuery(pStmt);
 
728
 
 
729
                        ((com.mysql.jdbc.ResultSet) rs).redefineFieldsForDBMD(new Field[] {
 
730
                                        new Field("", "PKTABLE_CAT", Types.CHAR, 255),
 
731
                                        new Field("", "PKTABLE_SCHEM", Types.CHAR, 0),
 
732
                                        new Field("", "PKTABLE_NAME", Types.CHAR, 255),
 
733
                                        new Field("", "PKCOLUMN_NAME", Types.CHAR, 32),
 
734
                                        new Field("", "FKTABLE_CAT", Types.CHAR, 255),
 
735
                                        new Field("", "FKTABLE_SCHEM", Types.CHAR, 0),
 
736
                                        new Field("", "FKTABLE_NAME", Types.CHAR, 255),
 
737
                                        new Field("", "FKCOLUMN_NAME", Types.CHAR, 32),
 
738
                                        new Field("", "KEY_SEQ", Types.SMALLINT, 2),
 
739
                                        new Field("", "UPDATE_RULE", Types.SMALLINT, 2),
 
740
                                        new Field("", "DELETE_RULE", Types.SMALLINT, 2),
 
741
                                        new Field("", "FK_NAME", Types.CHAR, 255),
 
742
                                        new Field("", "PK_NAME", Types.CHAR, 0),
 
743
                                        new Field("", "DEFERRABILITY", Types.INTEGER, 2) });
 
744
 
 
745
                        return rs;
 
746
                } finally {
 
747
                        if (pStmt != null) {
 
748
                                pStmt.close();
 
749
                        }
 
750
                }
 
751
        }
 
752
 
 
753
        /**
 
754
         * Get a description of a table's indices and statistics. They are ordered
 
755
         * by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.
 
756
         * <P>
 
757
         * Each index column description has the following columns:
 
758
         * <OL>
 
759
         * <li> <B>TABLE_CAT</B> String => table catalog (may be null) </li>
 
760
         * <li> <B>TABLE_SCHEM</B> String => table schema (may be null) </li>
 
761
         * <li> <B>TABLE_NAME</B> String => table name </li>
 
762
         * <li> <B>NON_UNIQUE</B> boolean => Can index values be non-unique? false
 
763
         * when TYPE is tableIndexStatistic </li>
 
764
         * <li> <B>INDEX_QUALIFIER</B> String => index catalog (may be null); null
 
765
         * when TYPE is tableIndexStatistic </li>
 
766
         * <li> <B>INDEX_NAME</B> String => index name; null when TYPE is
 
767
         * tableIndexStatistic </li>
 
768
         * <li> <B>TYPE</B> short => index type:
 
769
         * <UL>
 
770
         * <li> tableIndexStatistic - this identifies table statistics that are
 
771
         * returned in conjuction with a table's index descriptions </li>
 
772
         * <li> tableIndexClustered - this is a clustered index </li>
 
773
         * <li> tableIndexHashed - this is a hashed index </li>
 
774
         * <li> tableIndexOther - this is some other style of index </li>
 
775
         * </ul>
 
776
         * </li>
 
777
         * <li> <B>ORDINAL_POSITION</B> short => column sequence number within
 
778
         * index; zero when TYPE is tableIndexStatistic </li>
 
779
         * <li> <B>COLUMN_NAME</B> String => column name; null when TYPE is
 
780
         * tableIndexStatistic </li>
 
781
         * <li> <B>ASC_OR_DESC</B> String => column sort sequence, "A" =>
 
782
         * ascending, "D" => descending, may be null if sort sequence is not
 
783
         * supported; null when TYPE is tableIndexStatistic </li>
 
784
         * <li> <B>CARDINALITY</B> int => When TYPE is tableIndexStatisic then this
 
785
         * is the number of rows in the table; otherwise it is the number of unique
 
786
         * values in the index. </li>
 
787
         * <li> <B>PAGES</B> int => When TYPE is tableIndexStatisic then this is
 
788
         * the number of pages used for the table, otherwise it is the number of
 
789
         * pages used for the current index. </li>
 
790
         * <li> <B>FILTER_CONDITION</B> String => Filter condition, if any. (may be
 
791
         * null) </li>
 
792
         * </ol>
 
793
         * </p>
 
794
         * 
 
795
         * @param catalog
 
796
         *            a catalog name; "" retrieves those without a catalog
 
797
         * @param schema
 
798
         *            a schema name pattern; "" retrieves those without a schema
 
799
         * @param table
 
800
         *            a table name
 
801
         * @param unique
 
802
         *            when true, return only indices for unique values; when false,
 
803
         *            return indices regardless of whether unique or not
 
804
         * @param approximate
 
805
         *            when true, result is allowed to reflect approximate or out of
 
806
         *            data values; when false, results are requested to be accurate
 
807
         * @return ResultSet each row is an index column description
 
808
         * @throws SQLException
 
809
         *             DOCUMENT ME!
 
810
         */
 
811
        public ResultSet getIndexInfo(String catalog, String schema, String table,
 
812
                        boolean unique, boolean approximate) throws SQLException {
 
813
                StringBuffer sqlBuf = new StringBuffer("SELECT "
 
814
                                + "TABLE_SCHEMA AS TABLE_CAT, " + "NULL AS TABLE_SCHEM,"
 
815
                                + "TABLE_NAME," + "NON_UNIQUE,"
 
816
                                + "TABLE_SCHEMA AS INDEX_QUALIFIER," + "INDEX_NAME,"
 
817
                                + tableIndexOther + " AS TYPE,"
 
818
                                + "SEQ_IN_INDEX AS ORDINAL_POSITION," + "COLUMN_NAME,"
 
819
                                + "COLLATION AS ASC_OR_DESC," + "CARDINALITY,"
 
820
                                + "NULL AS PAGES," + "NULL AS FILTER_CONDITION "
 
821
                                + "FROM INFORMATION_SCHEMA.STATISTICS WHERE "
 
822
                                + "TABLE_SCHEMA LIKE ? AND " + "TABLE_NAME LIKE ?");
 
823
 
 
824
                if (unique) {
 
825
                        sqlBuf.append(" AND NON_UNIQUE=0 ");
 
826
                }
 
827
 
 
828
                sqlBuf.append("ORDER BY NON_UNIQUE, INDEX_NAME, SEQ_IN_INDEX");
 
829
 
 
830
                PreparedStatement pStmt = null;
 
831
 
 
832
                try {
 
833
                        pStmt = prepareMetaDataSafeStatement(sqlBuf.toString());
 
834
 
 
835
                        pStmt.setString(1, catalog);
 
836
                        pStmt.setString(2, table);
 
837
 
 
838
                        ResultSet rs = executeMetadataQuery(pStmt);
 
839
 
 
840
                        ((com.mysql.jdbc.ResultSet) rs).redefineFieldsForDBMD(new Field[] {
 
841
                                        new Field("", "TABLE_CAT", Types.CHAR, 255),
 
842
                                        new Field("", "TABLE_SCHEM", Types.CHAR, 0),
 
843
                                        new Field("", "TABLE_NAME", Types.CHAR, 255),
 
844
                                        new Field("", "NON_UNIQUE", Types.CHAR, 4),
 
845
                                        new Field("", "INDEX_QUALIFIER", Types.CHAR, 1),
 
846
                                        new Field("", "INDEX_NAME", Types.CHAR, 32),
 
847
                                        new Field("", "TYPE", Types.CHAR, 32),
 
848
                                        new Field("", "ORDINAL_POSITION", Types.SMALLINT, 5),
 
849
                                        new Field("", "COLUMN_NAME", Types.CHAR, 32),
 
850
                                        new Field("", "ASC_OR_DESC", Types.CHAR, 1),
 
851
                                        new Field("", "CARDINALITY", Types.INTEGER, 10),
 
852
                                        new Field("", "PAGES", Types.INTEGER, 10),
 
853
                                        new Field("", "FILTER_CONDITION", Types.CHAR, 32) });
 
854
 
 
855
                        return rs;
 
856
                } finally {
 
857
                        if (pStmt != null) {
 
858
                                pStmt.close();
 
859
                        }
 
860
                }
 
861
        }
 
862
 
 
863
        /**
 
864
         * Get a description of a table's primary key columns. They are ordered by
 
865
         * COLUMN_NAME.
 
866
         * <P>
 
867
         * Each column description has the following columns:
 
868
         * <OL>
 
869
         * <li> <B>TABLE_CAT</B> String => table catalog (may be null) </li>
 
870
         * <li> <B>TABLE_SCHEM</B> String => table schema (may be null) </li>
 
871
         * <li> <B>TABLE_NAME</B> String => table name </li>
 
872
         * <li> <B>COLUMN_NAME</B> String => column name </li>
 
873
         * <li> <B>KEY_SEQ</B> short => sequence number within primary key </li>
 
874
         * <li> <B>PK_NAME</B> String => primary key name (may be null) </li>
 
875
         * </ol>
 
876
         * </p>
 
877
         * 
 
878
         * @param catalog
 
879
         *            a catalog name; "" retrieves those without a catalog
 
880
         * @param schema
 
881
         *            a schema name pattern; "" retrieves those without a schema
 
882
         * @param table
 
883
         *            a table name
 
884
         * @return ResultSet each row is a primary key column description
 
885
         * @throws SQLException
 
886
         *             DOCUMENT ME!
 
887
         */
 
888
        public java.sql.ResultSet getPrimaryKeys(String catalog, String schema,
 
889
                        String table) throws SQLException {
 
890
 
 
891
                if (catalog == null) {
 
892
                        if (!this.conn.getNullCatalogMeansCurrent()) {
 
893
                                throw SQLError.createSQLException("'catalog' parameter can not be null",
 
894
                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
 
895
                        }
 
896
 
 
897
                        catalog = this.database;
 
898
                }
 
899
 
 
900
                if (table == null) {
 
901
                        throw SQLError.createSQLException("Table not specified.",
 
902
                                        SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
 
903
                }
 
904
 
 
905
                String sql = "SELECT TABLE_SCHEMA AS TABLE_CAT, NULL AS TABLE_SCHEM, TABLE_NAME, "
 
906
                                + "COLUMN_NAME, SEQ_IN_INDEX AS KEY_SEQ, 'PRIMARY' AS PK_NAME FROM INFORMATION_SCHEMA.STATISTICS "
 
907
                                + "WHERE TABLE_SCHEMA LIKE ? AND TABLE_NAME LIKE ? AND "
 
908
                                + "INDEX_NAME='PRIMARY' ORDER BY TABLE_SCHEMA, TABLE_NAME, INDEX_NAME, SEQ_IN_INDEX";
 
909
 
 
910
                PreparedStatement pStmt = null;
 
911
 
 
912
                try {
 
913
                        pStmt = prepareMetaDataSafeStatement(sql);
 
914
 
 
915
                        pStmt.setString(1, catalog);
 
916
                        pStmt.setString(2, table);
 
917
 
 
918
                        ResultSet rs = executeMetadataQuery(pStmt);
 
919
                        ((com.mysql.jdbc.ResultSet) rs).redefineFieldsForDBMD(new Field[] {
 
920
                                        new Field("", "TABLE_CAT", Types.CHAR, 255),
 
921
                                        new Field("", "TABLE_SCHEM", Types.CHAR, 0),
 
922
                                        new Field("", "TABLE_NAME", Types.CHAR, 255),
 
923
                                        new Field("", "COLUMN_NAME", Types.CHAR, 32),
 
924
                                        new Field("", "KEY_SEQ", Types.SMALLINT, 5),
 
925
                                        new Field("", "PK_NAME", Types.CHAR, 32) });
 
926
 
 
927
                        return rs;
 
928
                } finally {
 
929
                        if (pStmt != null) {
 
930
                                pStmt.close();
 
931
                        }
 
932
                }
 
933
        }
 
934
 
 
935
        /**
 
936
         * Get a description of stored procedures available in a catalog.
 
937
         * <P>
 
938
         * Only procedure descriptions matching the schema and procedure name
 
939
         * criteria are returned. They are ordered by PROCEDURE_SCHEM, and
 
940
         * PROCEDURE_NAME.
 
941
         * </p>
 
942
         * <P>
 
943
         * Each procedure description has the the following columns:
 
944
         * <OL>
 
945
         * <li> <B>PROCEDURE_CAT</B> String => procedure catalog (may be null)
 
946
         * </li>
 
947
         * <li> <B>PROCEDURE_SCHEM</B> String => procedure schema (may be null)
 
948
         * </li>
 
949
         * <li> <B>PROCEDURE_NAME</B> String => procedure name </li>
 
950
         * <li> reserved for future use </li>
 
951
         * <li> reserved for future use </li>
 
952
         * <li> reserved for future use </li>
 
953
         * <li> <B>REMARKS</B> String => explanatory comment on the procedure </li>
 
954
         * <li> <B>PROCEDURE_TYPE</B> short => kind of procedure:
 
955
         * <UL>
 
956
         * <li> procedureResultUnknown - May return a result </li>
 
957
         * <li> procedureNoResult - Does not return a result </li>
 
958
         * <li> procedureReturnsResult - Returns a result </li>
 
959
         * </ul>
 
960
         * </li>
 
961
         * </ol>
 
962
         * </p>
 
963
         * 
 
964
         * @param catalog
 
965
         *            a catalog name; "" retrieves those without a catalog
 
966
         * @param schemaPattern
 
967
         *            a schema name pattern; "" retrieves those without a schema
 
968
         * @param procedureNamePattern
 
969
         *            a procedure name pattern
 
970
         * @return ResultSet each row is a procedure description
 
971
         * @throws SQLException
 
972
         *             if a database access error occurs
 
973
         * @see #getSearchStringEscape
 
974
         */
 
975
        public ResultSet getProcedures(String catalog, String schemaPattern,
 
976
                        String procedureNamePattern) throws SQLException {
 
977
 
 
978
                if ((procedureNamePattern == null)
 
979
                                || (procedureNamePattern.length() == 0)) {
 
980
                        if (this.conn.getNullNamePatternMatchesAll()) {
 
981
                                procedureNamePattern = "%";
 
982
                        } else {
 
983
                                throw SQLError.createSQLException(
 
984
                                                "Procedure name pattern can not be NULL or empty.",
 
985
                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
 
986
                        }
 
987
                }
 
988
 
 
989
                String db = null;
 
990
 
 
991
                if (catalog == null) {
 
992
                        db = this.database;
 
993
                } else if (catalog.length() > 0) {
 
994
                        db = catalog;
 
995
                } else {
 
996
                        if (!this.conn.getNullCatalogMeansCurrent()) {
 
997
                                throw SQLError.createSQLException("'catalog' parameter can not be null",
 
998
                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
 
999
                        }
 
1000
 
 
1001
                        catalog = null;
 
1002
                        db = null;
 
1003
                }
 
1004
 
 
1005
                String sql = "SELECT ROUTINE_SCHEMA AS PROCEDURE_CAT, "
 
1006
                                + "NULL AS PROCEDURE_SCHEM, "
 
1007
                                + "ROUTINE_NAME AS PROCEDURE_NAME, " + "NULL AS RESERVED_1, "
 
1008
                                + "NULL AS RESERVED_2, " + "NULL AS RESERVED_3, "
 
1009
                                + "ROUTINE_COMMENT AS REMARKS, "
 
1010
                                + "CASE WHEN ROUTINE_TYPE = 'PROCEDURE' THEN "
 
1011
                                + procedureNoResult + " WHEN ROUTINE_TYPE='FUNCTION' THEN "
 
1012
                                + procedureReturnsResult + " ELSE " + procedureResultUnknown
 
1013
                                + " END AS PROCEDURE_TYPE "
 
1014
                                + "FROM INFORMATION_SCHEMA.ROUTINES WHERE "
 
1015
                                + "ROUTINE_SCHEMA LIKE ? AND ROUTINE_NAME LIKE ? "
 
1016
                                + "ORDER BY ROUTINE_SCHEMA, ROUTINE_NAME";
 
1017
 
 
1018
                PreparedStatement pStmt = null;
 
1019
 
 
1020
                try {
 
1021
                        pStmt = prepareMetaDataSafeStatement(sql);
 
1022
                        pStmt.setString(1, db);
 
1023
                        pStmt.setString(2, procedureNamePattern);
 
1024
 
 
1025
                        ResultSet rs = executeMetadataQuery(pStmt);
 
1026
                        ((com.mysql.jdbc.ResultSet) rs).redefineFieldsForDBMD(new Field[] {
 
1027
                                        new Field("", "PROCEDURE_CAT", Types.CHAR, 0),
 
1028
                                        new Field("", "PROCEDURE_SCHEM", Types.CHAR, 0),
 
1029
                                        new Field("", "PROCEDURE_NAME", Types.CHAR, 0),
 
1030
                                        new Field("", "reserved1", Types.CHAR, 0),
 
1031
                                        new Field("", "reserved2", Types.CHAR, 0),
 
1032
                                        new Field("", "reserved3", Types.CHAR, 0),
 
1033
                                        new Field("", "REMARKS", Types.CHAR, 0),
 
1034
                                        new Field("", "PROCEDURE_TYPE", Types.SMALLINT, 0) });
 
1035
 
 
1036
                        return rs;
 
1037
                } finally {
 
1038
                        if (pStmt != null) {
 
1039
                                pStmt.close();
 
1040
                        }
 
1041
                }
 
1042
        }
 
1043
 
 
1044
        /**
 
1045
         * Get a description of tables available in a catalog.
 
1046
         * <P>
 
1047
         * Only table descriptions matching the catalog, schema, table name and type
 
1048
         * criteria are returned. They are ordered by TABLE_TYPE, TABLE_SCHEM and
 
1049
         * TABLE_NAME.
 
1050
         * </p>
 
1051
         * <P>
 
1052
         * Each table description has the following columns:
 
1053
         * <OL>
 
1054
         * <li> <B>TABLE_CAT</B> String => table catalog (may be null) </li>
 
1055
         * <li> <B>TABLE_SCHEM</B> String => table schema (may be null) </li>
 
1056
         * <li> <B>TABLE_NAME</B> String => table name </li>
 
1057
         * <li> <B>TABLE_TYPE</B> String => table type. Typical types are "TABLE",
 
1058
         * "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS",
 
1059
         * "SYNONYM". </li>
 
1060
         * <li> <B>REMARKS</B> String => explanatory comment on the table </li>
 
1061
         * </ol>
 
1062
         * </p>
 
1063
         * <P>
 
1064
         * <B>Note:</B> Some databases may not return information for all tables.
 
1065
         * </p>
 
1066
         * 
 
1067
         * @param catalog
 
1068
         *            a catalog name; "" retrieves those without a catalog
 
1069
         * @param schemaPattern
 
1070
         *            a schema name pattern; "" retrieves those without a schema
 
1071
         * @param tableNamePattern
 
1072
         *            a table name pattern
 
1073
         * @param types
 
1074
         *            a list of table types to include; null returns all types
 
1075
         * @return ResultSet each row is a table description
 
1076
         * @throws SQLException
 
1077
         *             DOCUMENT ME!
 
1078
         * @see #getSearchStringEscape
 
1079
         */
 
1080
        public ResultSet getTables(String catalog, String schemaPattern,
 
1081
                        String tableNamePattern, String[] types) throws SQLException {
 
1082
                if (catalog == null) {
 
1083
                        if (!this.conn.getNullCatalogMeansCurrent()) {
 
1084
                                throw SQLError.createSQLException("'catalog' parameter can not be null",
 
1085
                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
 
1086
                        }
 
1087
 
 
1088
                        catalog = this.database;
 
1089
                }
 
1090
 
 
1091
                if (tableNamePattern == null) {
 
1092
                        if (this.conn.getNullNamePatternMatchesAll()) {
 
1093
                                tableNamePattern = "%";
 
1094
                        } else {
 
1095
                                throw SQLError.createSQLException(
 
1096
                                                "Table name pattern can not be NULL or empty.",
 
1097
                                                SQLError.SQL_STATE_ILLEGAL_ARGUMENT);
 
1098
                        }
 
1099
                }
 
1100
 
 
1101
                PreparedStatement pStmt = null;
 
1102
 
 
1103
                String sql = "SELECT TABLE_SCHEMA AS TABLE_CAT, "
 
1104
                                + "NULL AS TABLE_SCHEM, TABLE_NAME, "
 
1105
                                + "CASE WHEN TABLE_TYPE='BASE TABLE' THEN 'TABLE' WHEN TABLE_TYPE='TEMPORARY' THEN 'LOCAL_TEMPORARY' ELSE TABLE_TYPE END AS TABLE_TYPE, "
 
1106
                                + "TABLE_COMMENT AS REMARKS "
 
1107
                                + "FROM INFORMATION_SCHEMA.TABLES WHERE "
 
1108
                                + "TABLE_SCHEMA LIKE ? AND TABLE_NAME LIKE ? AND TABLE_TYPE IN (?,?,?) "
 
1109
                                + "ORDER BY TABLE_TYPE, TABLE_SCHEMA, TABLE_NAME";
 
1110
                try {
 
1111
                        pStmt = prepareMetaDataSafeStatement(sql);
 
1112
                        pStmt.setString(1, catalog);
 
1113
                        pStmt.setString(2, tableNamePattern);
 
1114
 
 
1115
                        // This overloading of IN (...) allows us to cache this
 
1116
                        // prepared statement
 
1117
                        if (types == null || types.length == 0) {
 
1118
                                pStmt.setString(3, "BASE TABLE");
 
1119
                                pStmt.setString(4, "VIEW");
 
1120
                                pStmt.setString(5, "TEMPORARY");
 
1121
                        } else {
 
1122
                                pStmt.setNull(3, Types.VARCHAR);
 
1123
                                pStmt.setNull(4, Types.VARCHAR);
 
1124
                                pStmt.setNull(5, Types.VARCHAR);
 
1125
 
 
1126
                                for (int i = 0; i < types.length; i++) {
 
1127
                                        if ("TABLE".equalsIgnoreCase(types[i])) {
 
1128
                                                pStmt.setString(3, "BASE TABLE");
 
1129
                                        }
 
1130
 
 
1131
                                        if ("VIEW".equalsIgnoreCase(types[i])) {
 
1132
                                                pStmt.setString(4, "VIEW");
 
1133
                                        }
 
1134
 
 
1135
                                        if ("LOCAL TEMPORARY".equalsIgnoreCase(types[i])) {
 
1136
                                                pStmt.setString(5, "TEMPORARY");
 
1137
                                        }
 
1138
                                }
 
1139
                        }
 
1140
 
 
1141
                        ResultSet rs = executeMetadataQuery(pStmt);
 
1142
 
 
1143
                        ((com.mysql.jdbc.ResultSet) rs).redefineFieldsForDBMD(new Field[] {
 
1144
                                        new Field("", "TABLE_CAT", java.sql.Types.VARCHAR,
 
1145
                                                        (catalog == null) ? 0 : catalog.length()),
 
1146
                                        new Field("", "TABLE_SCHEM", java.sql.Types.VARCHAR, 0),
 
1147
                                        new Field("", "TABLE_NAME", java.sql.Types.VARCHAR, 255),
 
1148
                                        new Field("", "TABLE_TYPE", java.sql.Types.VARCHAR, 5),
 
1149
                                        new Field("", "REMARKS", java.sql.Types.VARCHAR, 0) });
 
1150
 
 
1151
                        return rs;
 
1152
                } finally {
 
1153
                        if (pStmt != null) {
 
1154
                                pStmt.close();
 
1155
                        }
 
1156
                }
 
1157
        }
 
1158
 
 
1159
        private PreparedStatement prepareMetaDataSafeStatement(String sql)
 
1160
                        throws SQLException {
 
1161
                // Can't use server-side here as we coerce a lot of types to match
 
1162
                // the spec.
 
1163
                PreparedStatement pStmt = this.conn.clientPrepareStatement(sql);
 
1164
 
 
1165
                if (pStmt.getMaxRows() != 0) {
 
1166
                        pStmt.setMaxRows(0);
 
1167
                }
 
1168
 
 
1169
                pStmt.setHoldResultsOpenOverClose(true);
 
1170
 
 
1171
                return pStmt;
 
1172
        }
 
1173
}