~team-java-connector/mariadb-java-client/mariadb_java_connector_1.1.7

« back to all changes in this revision

Viewing changes to src/main/java/org/mariadb/jdbc/MySQLDatabaseMetaData.java

  • Committer: Puneet Dewan
  • Date: 2014-05-22 21:11:43 UTC
  • Revision ID: puneetd30@gmail.com-20140522211143-fk6no51e4berop92
Original code version 1.1.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
MariaDB Client for Java
 
3
 
 
4
Copyright (c) 2012 Monty Program Ab.
 
5
 
 
6
This library is free software; you can redistribute it and/or modify it under
 
7
the terms of the GNU Lesser General Public License as published by the Free
 
8
Software Foundation; either version 2.1 of the License, or (at your option)
 
9
any later version.
 
10
 
 
11
This library is distributed in the hope that it will be useful, but
 
12
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
13
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 
14
for more details.
 
15
 
 
16
You should have received a copy of the GNU Lesser General Public License along
 
17
with this library; if not, write to Monty Program Ab info@montyprogram.com.
 
18
 
 
19
This particular MariaDB Client for Java file is work
 
20
derived from a Drizzle-JDBC. Drizzle-JDBC file which is covered by subject to
 
21
the following copyright and notice provisions:
 
22
 
 
23
Copyright (c) 2009-2011, Marcus Eriksson
 
24
 
 
25
Redistribution and use in source and binary forms, with or without modification,
 
26
are permitted provided that the following conditions are met:
 
27
Redistributions of source code must retain the above copyright notice, this list
 
28
of conditions and the following disclaimer.
 
29
 
 
30
Redistributions in binary form must reproduce the above copyright notice, this
 
31
list of conditions and the following disclaimer in the documentation and/or
 
32
other materials provided with the distribution.
 
33
 
 
34
Neither the name of the driver nor the names of its contributors may not be
 
35
used to endorse or promote products derived from this software without specific
 
36
prior written permission.
 
37
 
 
38
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS  AND CONTRIBUTORS "AS IS"
 
39
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 
40
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
41
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 
42
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
43
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 
44
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 
45
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
46
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 
47
OF SUCH DAMAGE.
 
48
*/
 
49
 
 
50
package org.mariadb.jdbc;
 
51
 
 
52
import org.mariadb.jdbc.internal.common.Utils;
 
53
import org.mariadb.jdbc.internal.mysql.MySQLType;
 
54
import org.mariadb.jdbc.internal.mysql.MySQLValueObject;
 
55
 
 
56
import java.sql.*;
 
57
import java.text.ParseException;
 
58
import java.util.ArrayList;
 
59
import java.util.Arrays;
 
60
import java.util.Comparator;
 
61
import java.util.List;
 
62
 
 
63
public class MySQLDatabaseMetaData implements DatabaseMetaData {
 
64
    private String url;
 
65
    private MySQLConnection connection;
 
66
    private String databaseProductName = "MySQL";
 
67
    private String username;
 
68
    
 
69
    private  String dataTypeClause (String fullTypeColumnName){
 
70
        return
 
71
        " CASE data_type" +
 
72
        " WHEN 'bit' THEN "         + Types.BIT +
 
73
        " WHEN 'tinyblob' THEN "    + Types.LONGVARBINARY +
 
74
        " WHEN 'mediumblob' THEN "  + Types.LONGVARBINARY +
 
75
        " WHEN 'longblob' THEN "    + Types.LONGVARBINARY +
 
76
        " WHEN 'blob' THEN "        + Types.LONGVARBINARY +
 
77
        " WHEN 'tinytext' THEN "    + Types.LONGVARCHAR +
 
78
        " WHEN 'mediumtext' THEN "  + Types.LONGVARCHAR +
 
79
        " WHEN 'longtext' THEN "    + Types.LONGVARCHAR +
 
80
        " WHEN 'text' THEN "        + Types.LONGVARCHAR +
 
81
        " WHEN 'date' THEN "        + Types.DATE +
 
82
        " WHEN 'datetime' THEN "    + Types.TIMESTAMP +
 
83
        " WHEN 'decimal' THEN "     + Types.DECIMAL +
 
84
        " WHEN 'double' THEN "      + Types.DOUBLE +
 
85
        " WHEN 'enum' THEN "        + Types.VARCHAR +
 
86
        " WHEN 'float' THEN "        + Types.FLOAT+
 
87
        " WHEN 'int' THEN IF( " + fullTypeColumnName + " like '%unsigned%', "+Types.BIGINT+","+ Types.INTEGER+ ")" + 
 
88
        " WHEN 'bigint' THEN "      + Types.BIGINT +
 
89
        " WHEN 'mediumint' THEN "   + Types.INTEGER +
 
90
        " WHEN 'null' THEN "        + Types.NULL +
 
91
        " WHEN 'set' THEN "         + Types.VARCHAR +
 
92
        " WHEN 'smallint' THEN IF( " + fullTypeColumnName + " like '%unsigned%', "+Types.INTEGER+","+ Types.SMALLINT + ")" +
 
93
        " WHEN 'varchar' THEN "     + Types.VARCHAR +
 
94
        " WHEN 'varbinary' THEN "   + Types.VARBINARY +
 
95
        " WHEN 'char' THEN "        + Types.CHAR +
 
96
        " WHEN 'binary' THEN "      + Types.BINARY +
 
97
        " WHEN 'time' THEN "        + Types.TIME +
 
98
        " WHEN 'timestamp' THEN "   + Types.TIMESTAMP +
 
99
        " WHEN 'tinyint' THEN "  + (((connection.getProtocol().datatypeMappingFlags &  MySQLValueObject.TINYINT1_IS_BIT)== 0)? Types.TINYINT : "IF(" + fullTypeColumnName + "='tinyint(1)'," + Types.BIT + "," + Types.TINYINT + ") ") +  
 
100
        " WHEN 'year' THEN "  + (((connection.getProtocol().datatypeMappingFlags &  MySQLValueObject.YEAR_IS_DATE_TYPE)== 0)? Types.SMALLINT :Types.DATE) +  
 
101
        " ELSE "                    + Types.OTHER +  
 
102
        " END ";
 
103
    }
 
104
 
 
105
    /* Remove length from column type spec,convert to uppercase,  e.g  bigint(10) unsigned becomes BIGINT UNSIGNED */ 
 
106
    static String columnTypeClause(String columnName) {
 
107
    
 
108
        return 
 
109
                " UCASE(IF( " + columnName +  " LIKE '%(%)%', CONCAT (SUBSTRING( " + columnName + ",1, LOCATE('('," 
 
110
                + columnName +") - 1 ), SUBSTRING(" + columnName + ",1+locate(')'," + columnName + "))), " 
 
111
                + columnName + "))";
 
112
    }
 
113
    public MySQLDatabaseMetaData(Connection connection, String user, String url) {
 
114
        this.connection = (MySQLConnection)connection;
 
115
        this.username = user;
 
116
        this.url = url;
 
117
        this.connection.getProtocol().getServerVersion();
 
118
    }
 
119
 
 
120
 
 
121
    private ResultSet executeQuery(String sql) throws SQLException {
 
122
        MySQLResultSet rs =  (MySQLResultSet)connection.createStatement().executeQuery(sql);
 
123
        rs.setStatement(null); // bypass Hibernate statement tracking (CONJ-49)
 
124
        return rs;
 
125
    }
 
126
    
 
127
    
 
128
    private String escapeQuote(String s) {
 
129
        if (s == null)
 
130
            return "NULL";    
 
131
        return "'" + Utils.escapeString(s, connection.noBackslashEscapes) + "'";
 
132
    }
 
133
 
 
134
    /**
 
135
     * Generate part of the information schema query that restricts catalog names
 
136
     * In the driver, catalogs is the equivalent to MySQL schemas.
 
137
     * 
 
138
     * @param columnName - column name in the information schema table
 
139
     * @param catalog - catalog name.
 
140
     * 
 
141
     * This driver does not (always) follow JDBC standard for following special values, due 
 
142
     * to ConnectorJ compatibility
 
143
     * 
 
144
     * 1. empty string ("") - matches current catalog (i.e database).JDBC standard says
 
145
     * only tables without catalog should be returned - such tables do not exist in MySQL.
 
146
     * If there is no current catalog, then empty string matches any catalog.
 
147
     *   
 
148
     * 2. null  - if nullCatalogMeansCurrent=true (which is the default), then the handling is the same
 
149
     * as for "" . i.e return current catalog.
 
150
     *   
 
151
     * JDBC-conforming way would be to match any catalog with null parameter. This 
 
152
     * can be switched with nullCatalogMeansCurrent=false in the connection URL.
 
153
     * 
 
154
     * @return part of SQL query ,that restricts search for the catalog.
 
155
     */
 
156
    String catalogCond(String columnName, String catalog) {
 
157
        if (catalog == null && connection.nullCatalogMeansCurrent) {
 
158
            /* Treat null catalog as current */
 
159
            catalog = "";
 
160
        }
 
161
        
 
162
        if (catalog == null) {
 
163
            return "(1 = 1)"; 
 
164
        }
 
165
        if (catalog.equals("")) {
 
166
            return "(ISNULL(database()) OR (" + columnName + " = database()))";
 
167
        }
 
168
        return "(" + columnName + " = " + escapeQuote(catalog) + ")" ;
 
169
        
 
170
    }
 
171
    
 
172
     // Helper to generate  information schema queries with "like" or "equals" condition (typically  on table name)
 
173
    String patternCond(String columnName, String tableName) {
 
174
        if (tableName == null) {
 
175
            return "(1 = 1)";
 
176
        }
 
177
        String predicate = (tableName.indexOf('%') == -1 && tableName.indexOf('_') == -1)? "="  : "LIKE";
 
178
        return "(" + columnName + " " + predicate + " '" + Utils.escapeString(tableName, true) + "')";
 
179
    }
 
180
 
 
181
    public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException {
 
182
        String sql =
 
183
                "SELECT A.TABLE_SCHEMA TABLE_CAT, NULL TABLE_SCHEM, A.TABLE_NAME, A.COLUMN_NAME, B.SEQ_IN_INDEX KEY_SEQ, NULL PK_NAME "
 
184
                 + " FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.STATISTICS B"
 
185
                 + " WHERE A.COLUMN_KEY='pri' AND B.INDEX_NAME='PRIMARY' "
 
186
                 + " AND "
 
187
                 + catalogCond("A.TABLE_SCHEMA",catalog)
 
188
                 + " AND "
 
189
                 + catalogCond("B.TABLE_SCHEMA",catalog)
 
190
                 + " AND "
 
191
                 + patternCond("A.TABLE_NAME", table)
 
192
                 + " AND "
 
193
                 + patternCond("B.TABLE_NAME", table)
 
194
                 + " AND A.TABLE_SCHEMA = B.TABLE_SCHEMA AND A.TABLE_NAME = B.TABLE_NAME AND A.COLUMN_NAME = B.COLUMN_NAME "
 
195
                 + " ORDER BY A.COLUMN_NAME";
 
196
 
 
197
        return executeQuery(sql);
 
198
 
 
199
    }
 
200
 
 
201
    
 
202
    
 
203
   /**
 
204
     * Maps standard table types to mysql ones - helper since table type is never "table" in mysql, it is "base table"
 
205
     * @param tableType the table type defined by user
 
206
     * @return the internal table type.
 
207
     */
 
208
    private String mapTableTypes(String tableType) {
 
209
        if(tableType.equals("TABLE")) {
 
210
            return "BASE TABLE";
 
211
        }
 
212
        return tableType;
 
213
    }
 
214
 
 
215
    public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) 
 
216
            throws SQLException {
 
217
 
 
218
        String sql = 
 
219
         "SELECT TABLE_SCHEMA TABLE_CAT, NULL  TABLE_SCHEM,  TABLE_NAME, TABLE_TYPE, TABLE_COMMENT REMARKS,"
 
220
         + " NULL TYPE_CAT, NULL TYPE_SCHEM, NULL TYPE_NAME, NULL SELF_REFERENCING_COL_NAME, " 
 
221
         + " NULL REF_GENERATION" 
 
222
         + " FROM INFORMATION_SCHEMA.TABLES "
 
223
         + " WHERE "
 
224
         + catalogCond("TABLE_SCHEMA",catalog)  
 
225
         + " AND "
 
226
         + patternCond("TABLE_NAME", tableNamePattern);
 
227
        
 
228
        if (types != null && types.length > 0) {
 
229
            sql += " AND TABLE_TYPE IN (" ; 
 
230
            for (int i=0 ; i < types.length; i++) {
 
231
                if(types[i] == null)
 
232
                    continue;
 
233
                String type = escapeQuote(mapTableTypes(types[i]));
 
234
                if (i == types.length -1)
 
235
                    sql += type + ")";
 
236
                else
 
237
                    sql += type + ",";
 
238
            }            
 
239
        }
 
240
        
 
241
        sql += " ORDER BY TABLE_TYPE, TABLE_SCHEMA, TABLE_NAME";
 
242
 
 
243
        return executeQuery(sql);
 
244
    }
 
245
    
 
246
    public ResultSet getColumns(String catalog,  String schemaPattern,  String tableNamePattern,  String columnNamePattern)
 
247
        throws SQLException {
 
248
 
 
249
        String sql = 
 
250
        "SELECT TABLE_SCHEMA TABLE_CAT, NULL TABLE_SCHEM, TABLE_NAME, COLUMN_NAME," 
 
251
        + dataTypeClause("COLUMN_TYPE") + " DATA_TYPE,"
 
252
        + columnTypeClause("COLUMN_TYPE") +" TYPE_NAME, "
 
253
        + " CASE COLUMN_TYPE"
 
254
        + "  WHEN 'time' THEN 8"
 
255
        + "  WHEN 'date' THEN 10"       /* TODO : microseconds */
 
256
        + "  WHEN 'datetime' THEN 19"   
 
257
        + "  WHEN 'timestamp' THEN 19"
 
258
        + "  ELSE "
 
259
        + "  IF(NUMERIC_PRECISION IS NULL, LEAST(CHARACTER_MAXIMUM_LENGTH,"+Integer.MAX_VALUE+"), NUMERIC_PRECISION) "
 
260
        + " END" 
 
261
        + " COLUMN_SIZE, 65535 BUFFER_LENGTH, NUMERIC_SCALE DECIMAL_DIGITS,"  
 
262
        + " 10 NUM_PREC_RADIX, IF(IS_NULLABLE = 'yes',1,0) NULLABLE,COLUMN_COMMENT REMARKS," 
 
263
        + " COLUMN_DEFAULT COLUMN_DEF, 0 SQL_DATA_TYPE, 0 SQL_DATETIME_SUB,  "  
 
264
        + " LEAST(CHARACTER_OCTET_LENGTH," + Integer.MAX_VALUE + ") CHAR_OCTET_LENGTH,"
 
265
        + " ORDINAL_POSITION, IS_NULLABLE, NULL SCOPE_CATALOG, NULL SCOPE_SCHEMA, NULL SCOPE_TABLE, NULL SOURCE_DATA_TYPE,"
 
266
        + " IF(EXTRA = 'auto_increment','YES','NO') IS_AUTOINCREMENT "
 
267
        + " FROM INFORMATION_SCHEMA.COLUMNS  WHERE "
 
268
        + catalogCond("TABLE_SCHEMA", catalog)
 
269
        + " AND "
 
270
        + patternCond("TABLE_NAME", tableNamePattern)
 
271
        + " AND "
 
272
        + patternCond("COLUMN_NAME", columnNamePattern) 
 
273
        + " ORDER BY TABLE_CAT, TABLE_SCHEM, TABLE_NAME, ORDINAL_POSITION";
 
274
        
 
275
        return executeQuery(sql);
 
276
    }
 
277
 
 
278
    public ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException {
 
279
        if (table == null) {
 
280
            throw new SQLException("'table' parameter in getExportedKeys cannot be null");
 
281
        }
 
282
        String sql =
 
283
        "SELECT KCU.REFERENCED_TABLE_SCHEMA PKTABLE_CAT, NULL PKTABLE_SCHEM,  KCU.REFERENCED_TABLE_NAME PKTABLE_NAME," 
 
284
        + " KCU.REFERENCED_COLUMN_NAME PKCOLUMN_NAME, KCU.TABLE_SCHEMA FKTABLE_CAT, NULL FKTABLE_SCHEM, "
 
285
        + " KCU.TABLE_NAME FKTABLE_NAME, KCU.COLUMN_NAME FKCOLUMN_NAME, KCU.POSITION_IN_UNIQUE_CONSTRAINT KEY_SEQ,"
 
286
        + " CASE update_rule "
 
287
        + "   WHEN 'RESTRICT' THEN 1" 
 
288
        + "   WHEN 'NO ACTION' THEN 3" 
 
289
        + "   WHEN 'CASCADE' THEN 0" 
 
290
        + "   WHEN 'SET NULL' THEN 2"
 
291
        + "   WHEN 'SET DEFAULT' THEN 4"
 
292
        + " END UPDATE_RULE,"
 
293
        + " CASE DELETE_RULE" 
 
294
        + "  WHEN 'RESTRICT' THEN 1"
 
295
        + "  WHEN 'NO ACTION' THEN 3"
 
296
        + "  WHEN 'CASCADE' THEN 0"
 
297
        + "  WHEN 'SET NULL' THEN 2"
 
298
        + "  WHEN 'SET DEFAULT' THEN 4"
 
299
        + " END DELETE_RULE,"
 
300
        + " RC.CONSTRAINT_NAME FK_NAME,"
 
301
        + " NULL PK_NAME,"
 
302
        + " 6 DEFERRABILITY"
 
303
        + " FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU"
 
304
        + " INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC"
 
305
        + " ON KCU.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA"
 
306
        + " AND KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME"
 
307
        + " WHERE "
 
308
        + catalogCond("KCU.REFERENCED_TABLE_SCHEMA", catalog)
 
309
        + " AND "
 
310
        + " KCU.REFERENCED_TABLE_NAME = " + escapeQuote(table) 
 
311
        + " ORDER BY FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, KEY_SEQ";
 
312
 
 
313
        return executeQuery(sql);
 
314
    }
 
315
 
 
316
 
 
317
 
 
318
 
 
319
 
 
320
   public ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException {
 
321
 
 
322
       // We avoid using information schema queries by default, because this appears to be an expensive
 
323
       // query (CONJ-41).
 
324
       if (table == null) {
 
325
         throw new SQLException("'table' parameter in getImportedKeys cannot be null");
 
326
       }
 
327
 
 
328
       if (catalog == null && connection.nullCatalogMeansCurrent) {
 
329
            /* Treat null catalog as current */
 
330
            catalog = "";
 
331
       }
 
332
       if (catalog == null) {
 
333
           return getImportedKeysUsingInformationSchema(catalog, schema, table);
 
334
       }
 
335
 
 
336
       if (catalog.equals("")) {
 
337
           catalog = connection.getCatalog();
 
338
           if (catalog == null || catalog.equals("")) {
 
339
               return getImportedKeysUsingInformationSchema(catalog, schema, table);
 
340
           }
 
341
       }
 
342
 
 
343
       try {
 
344
            return getImportedKeysUsingShowCreateTable(catalog, schema, table);
 
345
       } catch (Exception e) {
 
346
           // Likely, parsing failed, try out I_S query.
 
347
           return getImportedKeysUsingInformationSchema(catalog, schema, table);
 
348
       }
 
349
   }
 
350
 
 
351
    public ResultSet getImportedKeysUsingInformationSchema( String catalog,  String schema,  String table) throws SQLException {
 
352
        if (table == null) {
 
353
            throw new SQLException("'table' parameter in getImportedKeys cannot be null"); 
 
354
        }
 
355
        String sql = 
 
356
          "SELECT KCU.REFERENCED_TABLE_SCHEMA PKTABLE_CAT, NULL PKTABLE_SCHEM,  KCU.REFERENCED_TABLE_NAME PKTABLE_NAME," 
 
357
        + " KCU.REFERENCED_COLUMN_NAME PKCOLUMN_NAME, KCU.TABLE_SCHEMA FKTABLE_CAT, NULL FKTABLE_SCHEM, "
 
358
        + " KCU.TABLE_NAME FKTABLE_NAME, KCU.COLUMN_NAME FKCOLUMN_NAME, KCU.POSITION_IN_UNIQUE_CONSTRAINT KEY_SEQ,"
 
359
        + " CASE update_rule "
 
360
        + "   WHEN 'RESTRICT' THEN 1" 
 
361
        + "   WHEN 'NO ACTION' THEN 3" 
 
362
        + "   WHEN 'CASCADE' THEN 0" 
 
363
        + "   WHEN 'SET NULL' THEN 2"
 
364
        + "   WHEN 'SET DEFAULT' THEN 4"
 
365
        + " END UPDATE_RULE,"
 
366
        + " CASE DELETE_RULE" 
 
367
        + "  WHEN 'RESTRICT' THEN 1"
 
368
        + "  WHEN 'NO ACTION' THEN 3"
 
369
        + "  WHEN 'CASCADE' THEN 0"
 
370
        + "  WHEN 'SET NULL' THEN 2"
 
371
        + "  WHEN 'SET DEFAULT' THEN 4"
 
372
        + " END DELETE_RULE,"
 
373
        + " RC.CONSTRAINT_NAME FK_NAME,"
 
374
        + " NULL PK_NAME,"
 
375
        + " 6 DEFERRABILITY"
 
376
        + " FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU"
 
377
        + " INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC"
 
378
        + " ON KCU.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA"
 
379
        + " AND KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME"
 
380
        + " WHERE "
 
381
        + catalogCond("KCU.TABLE_SCHEMA", catalog)
 
382
        + " AND "
 
383
        + " KCU.TABLE_NAME = " + escapeQuote(table) 
 
384
        + " ORDER BY PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME, KEY_SEQ";
 
385
        
 
386
        return executeQuery(sql);
 
387
    }
 
388
 
 
389
    public  ResultSet  getImportedKeysUsingShowCreateTable( String catalog,  String schema,  String table) throws Exception {
 
390
 
 
391
      if (catalog == null || catalog.equals(""))
 
392
          throw new IllegalArgumentException("catalog");
 
393
 
 
394
      if (table == null || table.equals(""))
 
395
          throw new IllegalArgumentException("table");
 
396
 
 
397
      ResultSet rs = connection.createStatement().executeQuery("SHOW CREATE TABLE "  +
 
398
      MySQLConnection.quoteIdentifier(catalog) + "." +  MySQLConnection.quoteIdentifier(table));
 
399
      rs.next();
 
400
      String tableDef = rs.getString(2);
 
401
      return ShowCreateTableParser.getImportedKeys(tableDef, table, catalog, connection);
 
402
    }
 
403
 
 
404
    public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, final boolean nullable)
 
405
            throws SQLException {
 
406
        
 
407
        if (table == null) {
 
408
            throw new SQLException("'table' parameter cannot be null in getBestRowIdentifier()");
 
409
        }
 
410
        
 
411
        String sql = 
 
412
        "SELECT " + DatabaseMetaData.bestRowUnknown + " SCOPE, COLUMN_NAME,"
 
413
        + dataTypeClause("COLUMN_TYPE") + " DATA_TYPE, DATA_TYPE TYPE_NAME,"
 
414
        + " IF(NUMERIC_PRECISION IS NULL, CHARACTER_MAXIMUM_LENGTH, NUMERIC_PRECISION) COLUMN_SIZE, 0 BUFFER_LENGTH," 
 
415
        + " NUMERIC_SCALE DECIMAL_DIGITS,"
 
416
        + " 1 PSEUDO_COLUMN" 
 
417
        + " FROM INFORMATION_SCHEMA.COLUMNS" 
 
418
        + " WHERE COLUMN_KEY IN('PRI', 'MUL', 'UNI')" 
 
419
        + " AND "
 
420
        + catalogCond("TABLE_SCHEMA",catalog)
 
421
        + " AND TABLE_NAME = " + escapeQuote(table);
 
422
        
 
423
        return executeQuery(sql);
 
424
    }
 
425
 
 
426
    public boolean generatedKeyAlwaysReturned() throws SQLException {
 
427
        return true;
 
428
    }
 
429
 
 
430
    public ResultSet getPseudoColumns(String catalog,  String schemaPattern, String tableNamePattern,
 
431
            String columnNamePattern) throws SQLException {
 
432
        return connection.createStatement().executeQuery(
 
433
            "SELECT ' ' TABLE_CAT, ' ' TABLE_SCHEM," +
 
434
            "' ' TABLE_NAME, ' ' COLUMN_NAME, 0 DATA_TYPE, 0 COLUMN_SIZE, 0 DECIMAL_DIGITS," + 
 
435
            "10 NUM_PREC_RADIX, ' ' COLUMN_USAGE,  ' ' REMARKS, 0 CHAR_OCTET_LENGTH, 'YES' IS_NULLABLE FROM DUAL " +
 
436
            "WHERE 1=0");
 
437
    }
 
438
 
 
439
    public boolean allProceduresAreCallable() throws SQLException {
 
440
        return true;
 
441
    }
 
442
 
 
443
    public boolean allTablesAreSelectable() throws SQLException {
 
444
        return true;
 
445
    }
 
446
 
 
447
    public String getURL() throws SQLException {
 
448
        return url;
 
449
    }
 
450
 
 
451
    public String getUserName() throws SQLException {
 
452
        return username;
 
453
    }
 
454
 
 
455
 
 
456
    public boolean isReadOnly() throws SQLException {
 
457
        return false;
 
458
    }
 
459
 
 
460
 
 
461
    public boolean nullsAreSortedHigh() throws SQLException {
 
462
        return false;
 
463
    }
 
464
 
 
465
 
 
466
    public boolean nullsAreSortedLow() throws SQLException {
 
467
        return !nullsAreSortedHigh();
 
468
    }
 
469
 
 
470
 
 
471
    public boolean nullsAreSortedAtStart() throws SQLException {
 
472
        return false;
 
473
    }
 
474
 
 
475
    public boolean nullsAreSortedAtEnd() throws SQLException {
 
476
        return !nullsAreSortedAtStart();
 
477
    }
 
478
 
 
479
 
 
480
    public String getDatabaseProductName() throws SQLException {
 
481
        return databaseProductName;
 
482
    }
 
483
 
 
484
 
 
485
    public String getDatabaseProductVersion() throws SQLException {
 
486
        return connection.getProtocol().getServerVersion();
 
487
    }
 
488
 
 
489
 
 
490
    public String getDriverName() throws SQLException {
 
491
        return "mariadb-jdbc"; // TODO: get from constants file
 
492
    }
 
493
 
 
494
    public String getDriverVersion() throws SQLException {
 
495
        return String.format("%d.%d",getDriverMajorVersion(),getDriverMinorVersion());
 
496
    }
 
497
 
 
498
 
 
499
    public int getDriverMajorVersion() {
 
500
        return 1;
 
501
    }
 
502
 
 
503
    public int getDriverMinorVersion() {
 
504
        return 1;
 
505
    }
 
506
 
 
507
 
 
508
    public boolean usesLocalFiles() throws SQLException {
 
509
        return false;
 
510
    }
 
511
 
 
512
    public boolean usesLocalFilePerTable() throws SQLException {
 
513
        return false;
 
514
    }
 
515
 
 
516
    public boolean supportsMixedCaseIdentifiers() throws SQLException {
 
517
        return (connection.getLowercaseTableNames() == 0);
 
518
    }
 
519
 
 
520
    public boolean storesUpperCaseIdentifiers() throws SQLException {
 
521
        return false;
 
522
    }
 
523
 
 
524
    public boolean storesLowerCaseIdentifiers() throws SQLException {
 
525
        return (connection.getLowercaseTableNames() == 1);
 
526
    }
 
527
 
 
528
    public boolean storesMixedCaseIdentifiers() throws SQLException {
 
529
        return (connection.getLowercaseTableNames() == 2);
 
530
    }
 
531
 
 
532
    public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException {
 
533
        return supportsMixedCaseIdentifiers();
 
534
    }
 
535
 
 
536
    public boolean storesUpperCaseQuotedIdentifiers() throws SQLException {
 
537
        return storesUpperCaseIdentifiers();
 
538
    }
 
539
 
 
540
    public boolean storesLowerCaseQuotedIdentifiers() throws SQLException {
 
541
        return storesLowerCaseIdentifiers();
 
542
    }
 
543
 
 
544
    public boolean storesMixedCaseQuotedIdentifiers() throws SQLException {
 
545
        return storesMixedCaseIdentifiers();
 
546
    }
 
547
 
 
548
    public String getIdentifierQuoteString() throws SQLException {
 
549
        return "`";
 
550
    }
 
551
 
 
552
    public String getSQLKeywords() throws SQLException {
 
553
        return
 
554
        "ACCESSIBLE,"+
 
555
        "ANALYZE,"+
 
556
        "ASENSITIVE,"+
 
557
        "BEFORE,"+
 
558
        "BIGINT,"+
 
559
        "BINARY,"+
 
560
        "BLOB,"+
 
561
        "CALL,"+
 
562
        "CHANGE,"+
 
563
        "CONDITION,"+
 
564
        "DATABASE,"+
 
565
        "DATABASES,"+
 
566
        "DAY_HOUR,"+
 
567
        "DAY_MICROSECOND,"+
 
568
        "DAY_MINUTE,"+
 
569
        "DAY_SECOND,"+
 
570
        "DELAYED,"+
 
571
        "DETERMINISTIC,"+
 
572
        "DISTINCTROW,"+
 
573
        "DIV,"+
 
574
        "DUAL,"+
 
575
        "EACH,"+
 
576
        "ELSEIF,"+
 
577
        "ENCLOSED,"+
 
578
        "ESCAPED,"+
 
579
        "EXIT,"+
 
580
        "EXPLAIN,"+
 
581
        "FLOAT4,"+
 
582
        "FLOAT8,"+
 
583
        "FORCE,"+
 
584
        "FULLTEXT,"+
 
585
        "HIGH_PRIORITY,"+
 
586
        "HOUR_MICROSECOND,"+
 
587
        "HOUR_MINUTE,"+
 
588
        "HOUR_SECOND,"+
 
589
        "IF,"+
 
590
        "IGNORE,"+
 
591
        "INFILE,"+
 
592
        "INOUT,"+
 
593
        "INT1,"+
 
594
        "INT2,"+
 
595
        "INT3,"+
 
596
        "INT4,"+
 
597
        "INT8,"+
 
598
        "ITERATE,"+
 
599
        "KEY," +
 
600
        "KEYS,"+
 
601
        "KILL,"+
 
602
        "LEAVE,"+
 
603
        "LIMIT,"+
 
604
        "LINEAR,"+
 
605
        "LINES,"+
 
606
        "LOAD,"+
 
607
        "LOCALTIME,"+
 
608
        "LOCALTIMESTAMP,"+
 
609
        "LOCK,"+
 
610
        "LONG,"+
 
611
        "LONGBLOB,"+
 
612
        "LONGTEXT,"+
 
613
        "LOOP,"+
 
614
        "LOW_PRIORITY,"+
 
615
        "MEDIUMBLOB,"+
 
616
        "MEDIUMINT,"+
 
617
        "MEDIUMTEXT,"+
 
618
        "MIDDLEINT,"+
 
619
        "MINUTE_MICROSECOND,"+
 
620
        "MINUTE_SECOND,"+
 
621
        "MOD,"+
 
622
        "MODIFIES,"+
 
623
        "NO_WRITE_TO_BINLOG,"+
 
624
        "OPTIMIZE,"+
 
625
        "OPTIONALLY,"+
 
626
        "OUT,"+
 
627
        "OUTFILE,"+
 
628
        "PURGE,"+
 
629
        "RANGE,"+
 
630
        "READS,"+
 
631
        "READ_ONLY,"+
 
632
        "READ_WRITE,"+
 
633
        "REGEXP,"+
 
634
        "RELEASE,"+
 
635
        "RENAME,"+
 
636
        "REPEAT,"+
 
637
        "REPLACE,"+
 
638
        "REQUIRE,"+
 
639
        "RETURN,"+
 
640
        "RLIKE,"+
 
641
        "SCHEMAS,"+
 
642
        "SECOND_MICROSECOND,"+
 
643
        "SENSITIVE,"+
 
644
        "SEPARATOR,"+
 
645
        "SHOW,"+
 
646
        "SPATIAL,"+
 
647
        "SPECIFIC,"+
 
648
        "SQLEXCEPTION,"+
 
649
        "SQL_BIG_RESULT,"+
 
650
        "SQL_CALC_FOUND_ROWS,"+
 
651
        "SQL_SMALL_RESULT,"+
 
652
        "SSL,"+
 
653
        "STARTING,"+
 
654
        "STRAIGHT_JOIN,"+
 
655
        "TERMINATED,"+
 
656
        "TINYBLOB,"+
 
657
        "TINYINT,"+
 
658
        "TINYTEXT,"+
 
659
        "TRIGGER,"+
 
660
        "UNDO,"+
 
661
        "UNLOCK,"+
 
662
        "UNSIGNED,"+
 
663
        "USE,"+
 
664
        "UTC_DATE,"+
 
665
        "UTC_TIME,"+
 
666
        "UTC_TIMESTAMP,"+
 
667
        "VARBINARY,"+
 
668
        "VARCHARACTER,"+
 
669
        "WHILE,"+
 
670
        "X509,"+
 
671
        "XOR,"+
 
672
        "YEAR_MONTH,"+
 
673
        "ZEROFILL,"+
 
674
        "GENERAL,"+
 
675
        "IGNORE_SERVER_IDS,"+
 
676
        "MASTER_HEARTBEAT_PERIOD,"+
 
677
        "MAXVALUE,"+
 
678
        "RESIGNAL,"+
 
679
        "SIGNAL,"+
 
680
        "SLOW";
 
681
    }
 
682
 
 
683
    public String getNumericFunctions() throws SQLException {
 
684
        return ""; //TODO : fix
 
685
    }
 
686
 
 
687
 
 
688
    public String getStringFunctions() throws SQLException {
 
689
        return ""; //TODO: fix
 
690
    }
 
691
 
 
692
    public String getSystemFunctions() throws SQLException {
 
693
        return "DATABASE,USER,SYSTEM_USER,SESSION_USER,LAST_INSERT_ID,VERSION";
 
694
    }
 
695
 
 
696
 
 
697
    public String getTimeDateFunctions() throws SQLException {
 
698
        return ""; //TODO : fix
 
699
    }
 
700
 
 
701
    public String getSearchStringEscape() throws SQLException {
 
702
        return "\\";
 
703
    }
 
704
 
 
705
    public String getExtraNameCharacters() throws SQLException {
 
706
        return "#@";
 
707
    }
 
708
 
 
709
    public boolean supportsAlterTableWithAddColumn() throws SQLException {
 
710
        return true;
 
711
    }
 
712
 
 
713
    public boolean supportsAlterTableWithDropColumn() throws SQLException {
 
714
        return true;
 
715
    }
 
716
 
 
717
    public boolean supportsColumnAliasing() throws SQLException {
 
718
        return true;
 
719
    }
 
720
 
 
721
    public boolean nullPlusNonNullIsNull() throws SQLException {
 
722
        return true;
 
723
    }
 
724
 
 
725
    public boolean supportsConvert() throws SQLException {
 
726
        return false; //TODO: fix
 
727
    }
 
728
 
 
729
    public boolean supportsConvert(int fromType, int toType)
 
730
            throws SQLException {
 
731
                return false; // TODO: fix
 
732
            }
 
733
 
 
734
    public boolean supportsTableCorrelationNames() throws SQLException {
 
735
        return true;
 
736
    }
 
737
 
 
738
    public boolean supportsDifferentTableCorrelationNames() throws SQLException {
 
739
        return true;
 
740
    }
 
741
 
 
742
    public boolean supportsExpressionsInOrderBy() throws SQLException {
 
743
        return true;
 
744
    }
 
745
 
 
746
    public boolean supportsOrderByUnrelated() throws SQLException {
 
747
        return false;
 
748
    }
 
749
 
 
750
    public boolean supportsGroupBy() throws SQLException {
 
751
        return true;
 
752
    }
 
753
 
 
754
    public boolean supportsGroupByUnrelated() throws SQLException {
 
755
        return true;
 
756
    }
 
757
 
 
758
    public boolean supportsGroupByBeyondSelect() throws SQLException {
 
759
        return true;
 
760
    }
 
761
 
 
762
    public boolean supportsLikeEscapeClause() throws SQLException {
 
763
        return true;
 
764
    }
 
765
 
 
766
    public boolean supportsMultipleResultSets() throws SQLException {
 
767
        return false;
 
768
    }
 
769
 
 
770
    public boolean supportsMultipleTransactions() throws SQLException {
 
771
        return true;
 
772
    }
 
773
 
 
774
    public boolean supportsNonNullableColumns() throws SQLException {
 
775
        return true;
 
776
    }
 
777
 
 
778
    public boolean supportsMinimumSQLGrammar() throws SQLException {
 
779
        return true;
 
780
    }
 
781
 
 
782
    public boolean supportsCoreSQLGrammar() throws SQLException {
 
783
        return true;
 
784
    }
 
785
 
 
786
    public boolean supportsExtendedSQLGrammar() throws SQLException {
 
787
        return false;
 
788
    }
 
789
 
 
790
    public boolean supportsANSI92EntryLevelSQL() throws SQLException {
 
791
        return true;
 
792
    }
 
793
 
 
794
    public boolean supportsANSI92IntermediateSQL() throws SQLException {
 
795
        return false;
 
796
    }
 
797
 
 
798
    public boolean supportsANSI92FullSQL() throws SQLException {
 
799
        return false;
 
800
    }
 
801
 
 
802
    public boolean supportsIntegrityEnhancementFacility() throws SQLException {
 
803
        return false; //TODO: verify
 
804
    }
 
805
 
 
806
    public boolean supportsOuterJoins() throws SQLException {
 
807
        return true;
 
808
    }
 
809
    public boolean supportsFullOuterJoins() throws SQLException {
 
810
        return false;
 
811
    }
 
812
 
 
813
    public boolean supportsLimitedOuterJoins() throws SQLException {
 
814
        return true;
 
815
    }
 
816
 
 
817
    public String getSchemaTerm() throws SQLException {
 
818
        return "";
 
819
    }
 
820
 
 
821
 
 
822
    public String getProcedureTerm() throws SQLException {
 
823
        return "procedure";
 
824
    }
 
825
 
 
826
    public String getCatalogTerm() throws SQLException {
 
827
        return "database";
 
828
    }
 
829
 
 
830
 
 
831
    public boolean isCatalogAtStart() throws SQLException {
 
832
        return true;
 
833
    }
 
834
 
 
835
 
 
836
    public String getCatalogSeparator() throws SQLException {
 
837
        return ".";
 
838
    }
 
839
 
 
840
 
 
841
    public boolean supportsSchemasInDataManipulation() throws SQLException {
 
842
        return false;
 
843
    }
 
844
 
 
845
 
 
846
    public boolean supportsSchemasInProcedureCalls() throws SQLException {
 
847
        return false;
 
848
    }
 
849
 
 
850
    public boolean supportsSchemasInTableDefinitions() throws SQLException {
 
851
        return false;
 
852
    }
 
853
 
 
854
    public boolean supportsSchemasInIndexDefinitions() throws SQLException {
 
855
        return false;
 
856
    }
 
857
 
 
858
    public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException {
 
859
        return true;
 
860
    }
 
861
 
 
862
    public boolean supportsCatalogsInDataManipulation() throws SQLException {
 
863
        return true;
 
864
    }
 
865
 
 
866
    public boolean supportsCatalogsInProcedureCalls() throws SQLException {
 
867
        return true;
 
868
    }
 
869
 
 
870
    public boolean supportsCatalogsInTableDefinitions() throws SQLException {
 
871
        return true;
 
872
    }
 
873
 
 
874
    public boolean supportsCatalogsInIndexDefinitions() throws SQLException {
 
875
        return true;
 
876
    }
 
877
 
 
878
    public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException {
 
879
        return true;
 
880
    }
 
881
 
 
882
    public boolean supportsPositionedDelete() throws SQLException {
 
883
        return false;
 
884
    }
 
885
 
 
886
    public boolean supportsPositionedUpdate() throws SQLException {
 
887
        return false;
 
888
    }
 
889
 
 
890
    public boolean supportsSelectForUpdate() throws SQLException {
 
891
        return true;
 
892
    }
 
893
 
 
894
    public boolean supportsStoredProcedures() throws SQLException {
 
895
        return true;
 
896
    }
 
897
 
 
898
 
 
899
    public boolean supportsSubqueriesInComparisons() throws SQLException {
 
900
        return true;
 
901
    }
 
902
 
 
903
    public boolean supportsSubqueriesInExists() throws SQLException {
 
904
        return true;
 
905
    }
 
906
 
 
907
 
 
908
    public boolean supportsSubqueriesInIns() throws SQLException {
 
909
        return true;
 
910
    }
 
911
 
 
912
    public boolean supportsSubqueriesInQuantifieds() throws SQLException {
 
913
        return true;
 
914
    }
 
915
 
 
916
 
 
917
    public boolean supportsCorrelatedSubqueries() throws SQLException {
 
918
        return true;
 
919
    }
 
920
 
 
921
 
 
922
    public boolean supportsUnion() throws SQLException {
 
923
        return true;
 
924
    }
 
925
 
 
926
 
 
927
    public boolean supportsUnionAll() throws SQLException {
 
928
        return true;
 
929
    }
 
930
 
 
931
 
 
932
    public boolean supportsOpenCursorsAcrossCommit() throws SQLException {
 
933
        return true;
 
934
    }
 
935
 
 
936
    public boolean supportsOpenCursorsAcrossRollback() throws SQLException {
 
937
        return true;
 
938
    }
 
939
 
 
940
    public boolean supportsOpenStatementsAcrossCommit() throws SQLException {
 
941
        return true;
 
942
    }
 
943
 
 
944
    public boolean supportsOpenStatementsAcrossRollback() throws SQLException {
 
945
        return true;
 
946
    }
 
947
 
 
948
    public int getMaxBinaryLiteralLength() throws SQLException {
 
949
        return 16777208;
 
950
    }
 
951
 
 
952
    public int getMaxCharLiteralLength() throws SQLException {
 
953
        return 16777208;
 
954
    }
 
955
 
 
956
    public int getMaxColumnNameLength() throws SQLException {
 
957
        return 64;
 
958
    }
 
959
 
 
960
    public int getMaxColumnsInGroupBy() throws SQLException {
 
961
        return 64;
 
962
    }
 
963
 
 
964
 
 
965
    public int getMaxColumnsInIndex() throws SQLException {
 
966
        return 16;
 
967
    }
 
968
 
 
969
 
 
970
    public int getMaxColumnsInOrderBy() throws SQLException {
 
971
        return 64;
 
972
    }
 
973
 
 
974
    public int getMaxColumnsInSelect() throws SQLException {
 
975
        return 256;
 
976
    }
 
977
 
 
978
 
 
979
    public int getMaxColumnsInTable() throws SQLException {
 
980
        return 0;
 
981
    }
 
982
 
 
983
    public int getMaxConnections() throws SQLException {
 
984
        return 0;
 
985
    }
 
986
 
 
987
 
 
988
    public int getMaxCursorNameLength() throws SQLException {
 
989
        return 0;
 
990
    }
 
991
 
 
992
 
 
993
    public int getMaxIndexLength() throws SQLException {
 
994
        return 256;
 
995
    }
 
996
    public int getMaxSchemaNameLength() throws SQLException {
 
997
        return 32;
 
998
    }
 
999
 
 
1000
    public int getMaxProcedureNameLength() throws SQLException {
 
1001
        return 256;
 
1002
    }
 
1003
 
 
1004
    public int getMaxCatalogNameLength() throws SQLException {
 
1005
        return 0;
 
1006
    }
 
1007
 
 
1008
    public int getMaxRowSize() throws SQLException {
 
1009
        return 0;
 
1010
    }
 
1011
 
 
1012
    public boolean doesMaxRowSizeIncludeBlobs() throws SQLException {
 
1013
        return false;
 
1014
    }
 
1015
 
 
1016
    public int getMaxStatementLength() throws SQLException {
 
1017
        return 0;
 
1018
    }
 
1019
 
 
1020
    public int getMaxStatements() throws SQLException {
 
1021
        return 0;
 
1022
    }
 
1023
 
 
1024
    public int getMaxTableNameLength() throws SQLException {
 
1025
        return 64;
 
1026
    }
 
1027
 
 
1028
    public int getMaxTablesInSelect() throws SQLException {
 
1029
        return 256;
 
1030
    }
 
1031
 
 
1032
    public int getMaxUserNameLength() throws SQLException {
 
1033
        return 16;
 
1034
    }
 
1035
 
 
1036
    public int getDefaultTransactionIsolation() throws SQLException {
 
1037
        return Connection.TRANSACTION_REPEATABLE_READ;
 
1038
    }
 
1039
 
 
1040
    public boolean supportsTransactions() throws SQLException {
 
1041
        return true;
 
1042
    }
 
1043
 
 
1044
 
 
1045
    public boolean supportsTransactionIsolationLevel(int level) throws SQLException {
 
1046
            switch (level) {
 
1047
                case Connection.TRANSACTION_READ_UNCOMMITTED:
 
1048
                case Connection.TRANSACTION_READ_COMMITTED:
 
1049
                case Connection.TRANSACTION_REPEATABLE_READ:
 
1050
                case Connection.TRANSACTION_SERIALIZABLE:
 
1051
                    return true;
 
1052
                default:
 
1053
                    return false;
 
1054
            }
 
1055
    }
 
1056
 
 
1057
 
 
1058
    public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException {
 
1059
        return true;
 
1060
    }
 
1061
 
 
1062
    public boolean supportsDataManipulationTransactionsOnly() throws SQLException {
 
1063
        return false;
 
1064
    }
 
1065
 
 
1066
    public boolean dataDefinitionCausesTransactionCommit() throws SQLException {
 
1067
        return true;
 
1068
    }
 
1069
 
 
1070
 
 
1071
    public boolean dataDefinitionIgnoredInTransactions() throws SQLException {
 
1072
        return false;
 
1073
    }
 
1074
 
 
1075
            
 
1076
    /* Helper to generate  information schema with "equality" condition (typically on catalog name)
 
1077
     */
 
1078
    
 
1079
 
 
1080
    public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern)
 
1081
            throws SQLException {
 
1082
    
 
1083
    String sql = 
 
1084
        "SELECT ROUTINE_SCHEMA PROCEDURE_CAT,NULL PROCEDURE_SCHEM, ROUTINE_NAME PROCEDURE_NAME,"  
 
1085
        + " NULL RESERVED1, NULL RESERVED2, NULL RESERVED3,"
 
1086
        + " CASE ROUTINE_TYPE "
 
1087
        +  "  WHEN 'FUNCTION' THEN " + procedureReturnsResult 
 
1088
        +  "  WHEN 'PROCEDURE' THEN " + procedureNoResult  
 
1089
        +  "  ELSE " + procedureResultUnknown
 
1090
        + " END PROCEDURE_TYPE,"
 
1091
        + " ROUTINE_COMMENT REMARKS, SPECIFIC_NAME "
 
1092
        + " FROM INFORMATION_SCHEMA.ROUTINES "  
 
1093
        + " WHERE " 
 
1094
        + catalogCond("ROUTINE_SCHEMA" , catalog)
 
1095
        + " AND "
 
1096
        + patternCond("ROUTINE_NAME", procedureNamePattern)
 
1097
        + "/* AND ROUTINE_TYPE='PROCEDURE' */";
 
1098
    return executeQuery(sql);
 
1099
    }
 
1100
 
 
1101
    
 
1102
    /* Is INFORMATION_SCHEMA.PARAMETERS available ?*/
 
1103
    boolean haveInformationSchemaParameters() {
 
1104
    return connection.getProtocol().versionGreaterOrEqual(5, 5, 3);
 
1105
    }
 
1106
    
 
1107
    public ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern,
 
1108
            String columnNamePattern) throws SQLException {
 
1109
        String sql;
 
1110
        
 
1111
        if (haveInformationSchemaParameters()) {
 
1112
            /*
 
1113
             *  Get info from information_schema.parameters 
 
1114
             */
 
1115
            sql = 
 
1116
            "SELECT SPECIFIC_SCHEMA PROCEDURE_CAT, NULL PROCEDURE_SCHEM, SPECIFIC_NAME PROCEDURE_NAME,"
 
1117
            +" PARAMETER_NAME COLUMN_NAME, " 
 
1118
            + " CASE PARAMETER_MODE "
 
1119
            + "  WHEN 'IN' THEN " + procedureColumnIn   
 
1120
            + "  WHEN 'OUT' THEN " + procedureColumnOut
 
1121
            + "  WHEN 'INOUT' THEN " + procedureColumnInOut 
 
1122
            + "  ELSE IF(PARAMETER_MODE IS NULL," + procedureColumnReturn + "," + procedureColumnUnknown + ")"
 
1123
            + " END COLUMN_TYPE,"
 
1124
            + dataTypeClause("DTD_IDENTIFIER") + " DATA_TYPE,"
 
1125
            + "DATA_TYPE TYPE_NAME,NUMERIC_PRECISION `PRECISION`,CHARACTER_MAXIMUM_LENGTH LENGTH,NUMERIC_SCALE SCALE,10 RADIX," 
 
1126
            + procedureNullableUnknown +" NULLABLE,NULL REMARKS,NULL COLUMN_DEF,0 SQL_DATA_TYPE,0 SQL_DATETIME_SUB,"
 
1127
            + "CHARACTER_OCTET_LENGTH CHAR_OCTET_LENGTH ,ORDINAL_POSITION, '' IS_NULLABLE, SPECIFIC_NAME "
 
1128
            + " FROM INFORMATION_SCHEMA.PARAMETERS "  
 
1129
            + " WHERE " 
 
1130
            + catalogCond("SPECIFIC_SCHEMA" , catalog)
 
1131
            + " AND "+ patternCond("SPECIFIC_NAME", procedureNamePattern)
 
1132
            + " AND "+ patternCond("PARAMETER_NAME", columnNamePattern)
 
1133
            + " /* AND ROUTINE_TYPE='PROCEDURE' */ "
 
1134
            + " ORDER BY SPECIFIC_SCHEMA, SPECIFIC_NAME, ORDINAL_POSITION";
 
1135
        } else {
 
1136
            
 
1137
            /* No information_schema.parameters
 
1138
             * TODO : figure out what to do with older versions (get info via mysql.proc) 
 
1139
             * For now, just a dummy result set is returned. 
 
1140
             */
 
1141
            sql = 
 
1142
                "SELECT '' PROCEDURE_CAT, '' PROCEDURE_SCHEM , '' PROCEDURE_NAME,'' COLUMN_NAME, 0 COLUMN_TYPE,"
 
1143
            + "0 DATA_TYPE,'' TYPE_NAME, 0 `PRECISION`,0 LENGTH, 0 SCALE,10 RADIX," 
 
1144
            + "0 NULLABLE,NULL REMARKS,NULL COLUMN_DEF,0 SQL_DATA_TYPE,0 SQL_DATETIME_SUB,"
 
1145
            + "0 CHAR_OCTET_LENGTH ,0 ORDINAL_POSITION, '' IS_NULLABLE, '' SPECIFIC_NAME "
 
1146
            + " FROM DUAL "  
 
1147
            + " WHERE 1=0 ";
 
1148
        }
 
1149
        return executeQuery(sql);
 
1150
    }
 
1151
    
 
1152
    public ResultSet getFunctionColumns(String catalog, String schemaPattern, String procedureNamePattern,
 
1153
            String columnNamePattern) throws SQLException {
 
1154
        
 
1155
        String sql;
 
1156
        if (haveInformationSchemaParameters()) {
 
1157
        
 
1158
            sql = "SELECT SPECIFIC_SCHEMA FUNCTION_CAT, NULL FUNCTION_SCHEM, SPECIFIC_NAME FUNCTION_NAME,"
 
1159
            +" PARAMETER_NAME COLUMN_NAME, " 
 
1160
            + " CASE PARAMETER_MODE "
 
1161
            + "  WHEN 'IN' THEN " + functionColumnIn   
 
1162
            + "  WHEN 'OUT' THEN " + functionColumnOut
 
1163
            + "  WHEN 'INOUT' THEN " + functionColumnInOut   
 
1164
            + "  ELSE " + functionReturn
 
1165
            + " END COLUMN_TYPE,"
 
1166
            + dataTypeClause("DTD_IDENTIFIER") + " DATA_TYPE,"
 
1167
            + "DATA_TYPE TYPE_NAME,NUMERIC_PRECISION `PRECISION`,CHARACTER_MAXIMUM_LENGTH LENGTH,NUMERIC_SCALE SCALE,10 RADIX," 
 
1168
            + procedureNullableUnknown +" NULLABLE,NULL REMARKS,"
 
1169
            + "CHARACTER_OCTET_LENGTH CHAR_OCTET_LENGTH ,ORDINAL_POSITION, '' IS_NULLABLE, SPECIFIC_NAME "
 
1170
            + " FROM INFORMATION_SCHEMA.PARAMETERS "  
 
1171
            + " WHERE " 
 
1172
            + catalogCond("SPECIFIC_SCHEMA" , catalog)
 
1173
            + " AND "+ patternCond("SPECIFIC_NAME", procedureNamePattern)
 
1174
            + " AND "+ patternCond("PARAMETER_NAME", columnNamePattern)
 
1175
            + " AND ROUTINE_TYPE='FUNCTION'"
 
1176
            + " ORDER BY SPECIFIC_SCHEMA, SPECIFIC_NAME, ORDINAL_POSITION";
 
1177
        } else {
 
1178
            /* 
 
1179
             * No information_schema.parameters
 
1180
             * TODO : figure out what to do with older versions (get info via mysql.proc) 
 
1181
             * For now, just a dummy result set is returned. 
 
1182
             */
 
1183
            sql = 
 
1184
            "SELECT '' FUNCTION_CAT, NULL FUNCTION_SCHEM, '' FUNCTION_NAME,"
 
1185
            + " '' COLUMN_NAME, 0  COLUMN_TYPE, 0 DATA_TYPE,"
 
1186
            + " '' TYPE_NAME,0 `PRECISION`,0 LENGTH, 0 SCALE,0 RADIX," 
 
1187
            + " 0 NULLABLE,NULL REMARKS, 0 CHAR_OCTET_LENGTH , 0 ORDINAL_POSITION, " 
 
1188
            + " '' IS_NULLABLE, '' SPECIFIC_NAME "
 
1189
            + " FROM DUAL WHERE 1=0 " ;
 
1190
        }
 
1191
        return executeQuery(sql);
 
1192
    }
 
1193
    
 
1194
    public ResultSet getSchemas() throws SQLException {
 
1195
        return executeQuery(
 
1196
            "SELECT '' TABLE_SCHEM, '' TABLE_catalog  FROM DUAL WHERE 1=0");
 
1197
    }
 
1198
 
 
1199
 
 
1200
    public ResultSet getCatalogs() throws SQLException {
 
1201
        return executeQuery(
 
1202
          "SELECT SCHEMA_NAME TABLE_CAT FROM INFORMATION_SCHEMA.SCHEMATA ORDER BY 1");
 
1203
    }
 
1204
 
 
1205
    public ResultSet getTableTypes() throws SQLException {
 
1206
        return executeQuery(
 
1207
          "SELECT 'BASE TABLE' TABLE_TYPE UNION SELECT 'SYSTEM VIEW' TABLE_TYPE UNION SELECT 'VIEW' TABLE_TYPE");
 
1208
    }
 
1209
 
 
1210
    public ResultSet getColumnPrivileges(String catalog, String schema, String table,
 
1211
            String columnNamePattern) throws SQLException {
 
1212
        
 
1213
        if(table == null) {
 
1214
            throw new SQLException("'table' parameter must not be null");
 
1215
        }
 
1216
        String sql = 
 
1217
           "SELECT TABLE_SCHEMA TABLE_CAT, NULL TABLE_SCHEM, TABLE_NAME,"
 
1218
         + " COLUMN_NAME, NULL AS GRANTOR, GRANTEE, PRIVILEGE_TYPE AS PRIVILEGE, IS_GRANTABLE FROM "
 
1219
         + " INFORMATION_SCHEMA.COLUMN_PRIVILEGES WHERE "
 
1220
         + catalogCond("TABLE_SCHEMA", catalog)
 
1221
         + " AND "
 
1222
         + " TABLE_NAME = " + escapeQuote(table) 
 
1223
         + " AND "
 
1224
         + patternCond("COLUMN_NAME",columnNamePattern) 
 
1225
         + " ORDER BY COLUMN_NAME, PRIVILEGE_TYPE";
 
1226
        
 
1227
      return executeQuery(sql);
 
1228
    }
 
1229
 
 
1230
    public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern)
 
1231
            throws SQLException {
 
1232
      String sql = 
 
1233
      "SELECT TABLE_SCHEMA TABLE_CAT,NULL  TABLE_SCHEM, TABLE_NAME, NULL GRANTOR," 
 
1234
      + "GRANTEE, PRIVILEGE_TYPE  PRIVILEGE, IS_GRANTABLE  FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES "
 
1235
      + " WHERE "
 
1236
      + catalogCond("TABLE_SCHEMA", catalog)   
 
1237
      + " AND "
 
1238
      + patternCond("TABLE_NAME",tableNamePattern)
 
1239
      + "ORDER BY TABLE_SCHEMA, TABLE_NAME,  PRIVILEGE_TYPE ";
 
1240
        
 
1241
      return executeQuery(sql);
 
1242
   }
 
1243
 
 
1244
    public ResultSet getVersionColumns(String catalog, String schema, String table)
 
1245
            throws SQLException {
 
1246
        String sql = 
 
1247
            "SELECT 0 SCOPE, ' ' COLUMN_NAME, 0 DATA_TYPE,"  
 
1248
            + " ' ' TYPE_NAME, 0 COLUMN_SIZE, 0 BUFFER_LENGTH,"  
 
1249
            + " 0 DECIMAL_DIGITS, 0 PSEUDO_COLUMN "
 
1250
            + " FROM DUAL WHERE 1 = 0";
 
1251
        return executeQuery(sql);
 
1252
    }
 
1253
 
 
1254
    public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable,
 
1255
            String foreignCatalog, String foreignSchema, String foreignTable) 
 
1256
                    throws SQLException {
 
1257
        
 
1258
         String sql =
 
1259
            "SELECT KCU.REFERENCED_TABLE_SCHEMA PKTABLE_CAT, NULL PKTABLE_SCHEM,  KCU.REFERENCED_TABLE_NAME PKTABLE_NAME," 
 
1260
            + " KCU.REFERENCED_COLUMN_NAME PKCOLUMN_NAME, KCU.TABLE_SCHEMA FKTABLE_CAT, NULL FKTABLE_SCHEM, "
 
1261
            + " KCU.TABLE_NAME FKTABLE_NAME, KCU.COLUMN_NAME FKCOLUMN_NAME, KCU.POSITION_IN_UNIQUE_CONSTRAINT KEY_SEQ,"
 
1262
            + " CASE update_rule "
 
1263
            + "   WHEN 'RESTRICT' THEN 1" 
 
1264
            + "   WHEN 'NO ACTION' THEN 3" 
 
1265
            + "   WHEN 'CASCADE' THEN 0" 
 
1266
            + "   WHEN 'SET NULL' THEN 2"
 
1267
            + "   WHEN 'SET DEFAULT' THEN 4"
 
1268
            + " END UPDATE_RULE,"
 
1269
            + " CASE DELETE_RULE" 
 
1270
            + "  WHEN 'RESTRICT' THEN 1"
 
1271
            + "  WHEN 'NO ACTION' THEN 3"
 
1272
            + "  WHEN 'CASCADE' THEN 0"
 
1273
            + "  WHEN 'SET NULL' THEN 2"
 
1274
            + "  WHEN 'SET DEFAULT' THEN 4"
 
1275
            + " END DELETE_RULE,"
 
1276
            + " RC.CONSTRAINT_NAME FK_NAME,"
 
1277
            + " NULL PK_NAME,"
 
1278
            + " 6 DEFERRABILITY"
 
1279
            + " FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE KCU"
 
1280
            + " INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS RC"
 
1281
            + " ON KCU.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA"
 
1282
            + " AND KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME"
 
1283
            + " WHERE "
 
1284
            + catalogCond("KCU.REFERENCED_TABLE_SCHEMA", parentCatalog)
 
1285
            + " AND "
 
1286
            + catalogCond("KCU.TABLE_SCHEMA", foreignCatalog) 
 
1287
            + " AND "
 
1288
            + " KCU.REFERENCED_TABLE_NAME = " + escapeQuote(parentTable) 
 
1289
            + " AND "
 
1290
            + " KCU.TABLE_NAME = " + escapeQuote(foreignTable)
 
1291
            + " ORDER BY FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, KEY_SEQ";
 
1292
     
 
1293
        return executeQuery(sql);
 
1294
    }
 
1295
 
 
1296
    public ResultSet getTypeInfo() throws SQLException {
 
1297
        String[] columnNames  = {
 
1298
                "TYPE_NAME","DATA_TYPE","PRECISION","LITERAL_PREFIX","LITERAL_SUFFIX",
 
1299
                "CREATE_PARAMS","NULLABLE","CASE_SENSITIVE","SEARCHABLE","UNSIGNED_ATTRIBUTE",
 
1300
                "FIXED_PREC_SCALE","AUTO_INCREMENT","LOCAL_TYPE_NAME","MINIMUM_SCALE","MAXIMUM_SCALE",
 
1301
                "SQL_DATA_TYPE","SQL_DATETIME_SUB","NUM_PREC_RADIX"
 
1302
                };
 
1303
        MySQLType [] columnTypes =  {
 
1304
                MySQLType.VARCHAR, MySQLType.INTEGER,MySQLType.INTEGER,MySQLType.VARCHAR, MySQLType.VARCHAR,
 
1305
                MySQLType.VARCHAR, MySQLType.INTEGER,MySQLType.BIT,MySQLType.SMALLINT,MySQLType.BIT,
 
1306
                MySQLType.BIT, MySQLType.BIT, MySQLType.VARCHAR,MySQLType.SMALLINT,MySQLType.SMALLINT,
 
1307
                MySQLType.INTEGER, MySQLType.INTEGER,MySQLType.INTEGER
 
1308
                };
 
1309
        
 
1310
        String[][] data= {
 
1311
        {"BIT","-7","1","","","","1","1","3","0","0","0","BIT","0","0","0","0","10"},
 
1312
        {"BOOL","-7","1","","","","1","1","3","0","0","0","BOOL","0","0","0","0","10"},
 
1313
        {"TINYINT","-6","3","","","[(M)] [UNSIGNED] [ZEROFILL]","1","0","3","1","0","1","TINYINT","0","0","0","0","10"},
 
1314
        {"TINYINT UNSIGNED","-6","3","","","[(M)] [UNSIGNED] [ZEROFILL]","1","0","3","1","0","1","TINYINT UNSIGNED","0","0","0","0","10"},
 
1315
        {"BIGINT","-5","19","","","[(M)] [UNSIGNED] [ZEROFILL]","1","0","3","1","0","1","BIGINT","0","0","0","0","10"},
 
1316
        {"BIGINT UNSIGNED","-5","20","","","[(M)] [ZEROFILL]","1","0","3","1","0","1","BIGINT UNSIGNED","0","0","0","0","10"},
 
1317
        {"LONG VARBINARY","-4","16777215","'","'","","1","1","3","0","0","0","LONG VARBINARY","0","0","0","0","10"},
 
1318
        {"MEDIUMBLOB","-4","16777215","'","'","","1","1","3","0","0","0","MEDIUMBLOB","0","0","0","0","10"},
 
1319
        {"LONGBLOB","-4","2147483647","'","'","","1","1","3","0","0","0","LONGBLOB","0","0","0","0","10"},
 
1320
        {"BLOB","-4","65535","'","'","","1","1","3","0","0","0","BLOB","0","0","0","0","10"},
 
1321
        {"TINYBLOB","-4","255","'","'","","1","1","3","0","0","0","TINYBLOB","0","0","0","0","10"},
 
1322
        {"VARBINARY","-3","255","'","'","(M)","1","1","3","0","0","0","VARBINARY","0","0","0","0","10"},
 
1323
        {"BINARY","-2","255","'","'","(M)","1","1","3","0","0","0","BINARY","0","0","0","0","10"},
 
1324
        {"LONG VARCHAR","-1","16777215","'","'","","1","0","3","0","0","0","LONG VARCHAR","0","0","0","0","10"},
 
1325
        {"MEDIUMTEXT","-1","16777215","'","'","","1","0","3","0","0","0","MEDIUMTEXT","0","0","0","0","10"},
 
1326
        {"LONGTEXT","-1","2147483647","'","'","","1","0","3","0","0","0","LONGTEXT","0","0","0","0","10"},
 
1327
        {"TEXT","-1","65535","'","'","","1","0","3","0","0","0","TEXT","0","0","0","0","10"},
 
1328
        {"TINYTEXT","-1","255","'","'","","1","0","3","0","0","0","TINYTEXT","0","0","0","0","10"},
 
1329
        {"CHAR","1","255","'","'","(M)","1","0","3","0","0","0","CHAR","0","0","0","0","10"},
 
1330
        {"NUMERIC","2","65","","","[(M,D])] [ZEROFILL]","1","0","3","0","0","1","NUMERIC","-308","308","0","0","10"},
 
1331
        {"DECIMAL","3","65","","","[(M,D])] [ZEROFILL]","1","0","3","0","0","1","DECIMAL","-308","308","0","0","10"},
 
1332
        {"INTEGER","4","10","","","[(M)] [UNSIGNED] [ZEROFILL]","1","0","3","1","0","1","INTEGER","0","0","0","0","10"},
 
1333
        {"INTEGER UNSIGNED","4","10","","","[(M)] [ZEROFILL]","1","0","3","1","0","1","INTEGER UNSIGNED","0","0","0","0","10"},
 
1334
        {"INT","4","10","","","[(M)] [UNSIGNED] [ZEROFILL]","1","0","3","1","0","1","INT","0","0","0","0","10"},
 
1335
        {"INT UNSIGNED","4","10","","","[(M)] [ZEROFILL]","1","0","3","1","0","1","INT UNSIGNED","0","0","0","0","10"},
 
1336
        {"MEDIUMINT","4","7","","","[(M)] [UNSIGNED] [ZEROFILL]","1","0","3","1","0","1","MEDIUMINT","0","0","0","0","10"},
 
1337
        {"MEDIUMINT UNSIGNED","4","8","","","[(M)] [ZEROFILL]","1","0","3","1","0","1","MEDIUMINT UNSIGNED","0","0","0","0","10"},
 
1338
        {"SMALLINT","5","5","","","[(M)] [UNSIGNED] [ZEROFILL]","1","0","3","1","0","1","SMALLINT","0","0","0","0","10"},
 
1339
        {"SMALLINT UNSIGNED","5","5","","","[(M)] [ZEROFILL]","1","0","3","1","0","1","SMALLINT UNSIGNED","0","0","0","0","10"},
 
1340
        {"FLOAT","7","10","","","[(M|D)] [ZEROFILL]","1","0","3","0","0","1","FLOAT","-38","38","0","0","10"},
 
1341
        {"DOUBLE","8","17","","","[(M|D)] [ZEROFILL]","1","0","3","0","0","1","DOUBLE","-308","308","0","0","10"},
 
1342
        {"DOUBLE PRECISION","8","17","","","[(M,D)] [ZEROFILL]","1","0","3","0","0","1","DOUBLE PRECISION","-308","308","0","0","10"},
 
1343
        {"REAL","8","17","","","[(M,D)] [ZEROFILL]","1","0","3","0","0","1","REAL","-308","308","0","0","10"},
 
1344
        {"VARCHAR","12","255","'","'","(M)","1","0","3","0","0","0","VARCHAR","0","0","0","0","10"},
 
1345
        {"ENUM","12","65535","'","'","","1","0","3","0","0","0","ENUM","0","0","0","0","10"},
 
1346
        {"SET","12","64","'","'","","1","0","3","0","0","0","SET","0","0","0","0","10"},
 
1347
        {"DATE","91","10","'","'","","1","0","3","0","0","0","DATE","0","0","0","0","10"},
 
1348
        {"TIME","92","18","'","'","[(M)]","1","0","3","0","0","0","TIME","0","0","0","0","10"},
 
1349
        {"DATETIME","93","27","'","'","[(M)]","1","0","3","0","0","0","DATETIME","0","0","0","0","10"},
 
1350
        {"TIMESTAMP","93","27","'","'","[(M)]","1","0","3","0","0","0","TIMESTAMP","0","0","0","0","10"}
 
1351
        };
 
1352
 
 
1353
        return MySQLResultSet.createResultSet(columnNames, columnTypes, data, connection.getProtocol());
 
1354
    }
 
1355
 
 
1356
    public ResultSet getIndexInfo(String catalog, String schema, String table,
 
1357
            boolean unique,boolean approximate) throws SQLException {
 
1358
    
 
1359
        String sql = 
 
1360
            "SELECT TABLE_SCHEMA TABLE_CAT, NULL TABLE_SCHEM, TABLE_NAME, NON_UNIQUE, "
 
1361
            + " TABLE_SCHEMA INDEX_QUALIFIER, INDEX_NAME, 3 TYPE,"
 
1362
            + " SEQ_IN_INDEX ORDINAL_POSITION, COLUMN_NAME, COLLATION ASC_OR_DESC," 
 
1363
            + " CARDINALITY, NULL PAGES, NULL FILTER_CONDITION"
 
1364
            + " FROM INFORMATION_SCHEMA.STATISTICS" 
 
1365
            + " WHERE TABLE_NAME = " + escapeQuote(table)
 
1366
            + " AND "
 
1367
            + catalogCond("TABLE_SCHEMA",catalog)
 
1368
            + ((unique) ? " AND NON_UNIQUE = 0" : "") 
 
1369
            + " ORDER BY NON_UNIQUE, TYPE, INDEX_NAME, ORDINAL_POSITION";
 
1370
            
 
1371
            return executeQuery(sql);
 
1372
    }
 
1373
    
 
1374
    
 
1375
    public boolean supportsResultSetType(int type) throws SQLException {
 
1376
        return true;
 
1377
    }
 
1378
 
 
1379
 
 
1380
    public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException {
 
1381
         return concurrency == ResultSet.CONCUR_READ_ONLY;
 
1382
    }
 
1383
 
 
1384
    public boolean ownUpdatesAreVisible(int type) throws SQLException {
 
1385
        return false;
 
1386
    }
 
1387
 
 
1388
 
 
1389
    public boolean ownDeletesAreVisible(int type) throws SQLException {
 
1390
        return false;
 
1391
    }
 
1392
 
 
1393
 
 
1394
    public boolean ownInsertsAreVisible(int type) throws SQLException {
 
1395
        return false;
 
1396
    }
 
1397
 
 
1398
 
 
1399
    public boolean othersUpdatesAreVisible(int type) throws SQLException {
 
1400
        return false;
 
1401
    }
 
1402
 
 
1403
 
 
1404
    public boolean othersDeletesAreVisible(int type) throws SQLException {
 
1405
        return false;
 
1406
    }
 
1407
 
 
1408
    public boolean othersInsertsAreVisible(int type) throws SQLException {
 
1409
        return false;
 
1410
    }
 
1411
 
 
1412
    public boolean updatesAreDetected(int type) throws SQLException {
 
1413
        return false;
 
1414
    }
 
1415
 
 
1416
 
 
1417
    public boolean deletesAreDetected(int type) throws SQLException {
 
1418
        return false;
 
1419
    }
 
1420
 
 
1421
 
 
1422
    public boolean insertsAreDetected(int type) throws SQLException {
 
1423
        return false;
 
1424
    }
 
1425
 
 
1426
 
 
1427
    public boolean supportsBatchUpdates() throws SQLException {
 
1428
        return true;
 
1429
    }
 
1430
 
 
1431
 
 
1432
    public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types)
 
1433
            throws SQLException {
 
1434
        String sql = 
 
1435
        "SELECT ' ' TYPE_CAT, NULL TYPE_SCHEM, ' ' TYPE_NAME, ' ' CLASS_NAME, 0 DATA_TYPE, ' ' REMARKS, 0 BASE_TYPE"
 
1436
        + " FROM DUAL WHERE 1=0";
 
1437
        
 
1438
        return executeQuery(sql);
 
1439
    }
 
1440
 
 
1441
 
 
1442
 
 
1443
    public Connection getConnection() throws SQLException {
 
1444
        return connection;
 
1445
    }
 
1446
 
 
1447
 
 
1448
    public boolean supportsSavepoints() throws SQLException {
 
1449
        return true;
 
1450
    }
 
1451
 
 
1452
 
 
1453
    public boolean supportsNamedParameters() throws SQLException {
 
1454
        return false;
 
1455
    }
 
1456
 
 
1457
 
 
1458
    public boolean supportsMultipleOpenResults() throws SQLException {
 
1459
        return false;
 
1460
    }
 
1461
 
 
1462
 
 
1463
    public boolean supportsGetGeneratedKeys() throws SQLException {
 
1464
        return true;
 
1465
    }
 
1466
 
 
1467
 
 
1468
    public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern)
 
1469
            throws SQLException {
 
1470
        String sql = 
 
1471
        "SELECT  ' ' TYPE_CAT, NULL TYPE_SCHEM, ' ' TYPE_NAME, ' ' SUPERTYPE_CAT, ' ' SUPERTYPE_SCHEM, ' '  SUPERTYPE_NAME" 
 
1472
        + " FROM DUAL WHERE 1=0";
 
1473
        
 
1474
        return executeQuery(sql);    
 
1475
    }
 
1476
 
 
1477
 
 
1478
    public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern)
 
1479
            throws SQLException {
 
1480
        String sql = 
 
1481
        "SELECT  ' ' TABLE_CAT, ' ' TABLE_SCHEM, ' ' TABLE_NAME, ' ' SUPERTABLE_NAME FROM DUAL WHERE 1=0";
 
1482
        return executeQuery(sql);                     
 
1483
    }
 
1484
 
 
1485
 
 
1486
    public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern,
 
1487
            String attributeNamePattern) throws SQLException {
 
1488
 
 
1489
      String sql = 
 
1490
        "SELECT ' ' TYPE_CAT, ' ' TYPE_SCHEM, ' ' TYPE_NAME, ' ' ATTR_NAME, 0 DATA_TYPE,"
 
1491
        + " ' ' ATTR_TYPE_NAME, 0 ATTR_SIZE, 0 DECIMAL_DIGITS, 0 NUM_PREC_RADIX, 0 NULLABLE,"
 
1492
        + " ' ' REMARKS, ' ' ATTR_DEF,  0 SQL_DATA_TYPE, 0 SQL_DATETIME_SUB, 0 CHAR_OCTET_LENGTH,"
 
1493
        + " 0 ORDINAL_POSITION, ' ' IS_NULLABLE, ' ' SCOPE_CATALOG, ' ' SCOPE_SCHEMA, ' ' SCOPE_TABLE," 
 
1494
        + " 0 SOURCE_DATA_TYPE"
 
1495
        + " FROM DUAL " 
 
1496
        + " WHERE 1=0";
 
1497
     
 
1498
     return executeQuery(sql);
 
1499
    }
 
1500
 
 
1501
    public boolean supportsResultSetHoldability(int holdability)
 
1502
            throws SQLException {
 
1503
                return holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT;
 
1504
            }
 
1505
 
 
1506
 
 
1507
    public int getResultSetHoldability() throws SQLException {
 
1508
        return ResultSet.HOLD_CURSORS_OVER_COMMIT;
 
1509
    }
 
1510
 
 
1511
 
 
1512
    public int getDatabaseMajorVersion() throws SQLException {
 
1513
       return connection.getProtocol().getMajorServerVersion();
 
1514
    }
 
1515
 
 
1516
 
 
1517
    public int getDatabaseMinorVersion() throws SQLException {
 
1518
        return connection.getProtocol().getMinorServerVersion();
 
1519
    }
 
1520
 
 
1521
 
 
1522
    public int getJDBCMajorVersion() throws SQLException {
 
1523
        return 4;
 
1524
    }
 
1525
 
 
1526
    public int getJDBCMinorVersion() throws SQLException {
 
1527
        return 0;
 
1528
    }
 
1529
 
 
1530
 
 
1531
    public int getSQLStateType() throws SQLException {
 
1532
         return sqlStateSQL;
 
1533
    }
 
1534
 
 
1535
 
 
1536
    public boolean locatorsUpdateCopy() throws SQLException {
 
1537
        return false;
 
1538
    }
 
1539
 
 
1540
 
 
1541
    public boolean supportsStatementPooling() throws SQLException {
 
1542
        return false;
 
1543
    }
 
1544
 
 
1545
 
 
1546
    public java.sql.RowIdLifetime getRowIdLifetime() throws SQLException {
 
1547
        return java.sql.RowIdLifetime.ROWID_UNSUPPORTED;
 
1548
    }
 
1549
 
 
1550
 
 
1551
    public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException {
 
1552
        return executeQuery("SELECT  ' ' table_schem, ' ' table_catalog FROM DUAL WHERE 1=0");
 
1553
    }
 
1554
 
 
1555
    public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException {
 
1556
        return true;
 
1557
    }
 
1558
 
 
1559
    public boolean autoCommitFailureClosesAllResultSets() throws SQLException {
 
1560
        return false; //TODO: look into this
 
1561
    }
 
1562
 
 
1563
 
 
1564
    public ResultSet getClientInfoProperties() throws SQLException {
 
1565
        String sql = "SELECT ' ' NAME, 0 MAX_LEN, ' ' DEFAULT_VALUE, ' ' DESCRIPTION FROM DUAL WHERE 1=0";
 
1566
        return executeQuery(sql);
 
1567
    }
 
1568
 
 
1569
 
 
1570
    public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern)
 
1571
            throws SQLException {
 
1572
        String sql = 
 
1573
        "SELECT ROUTINE_SCHEMA FUNCTION_CAT,NULL FUNCTION_SCHEM, ROUTINE_NAME FUNCTION_NAME,"       
 
1574
        + " ROUTINE_COMMENT REMARKS," + functionNoTable + " FUNCTION_TYPE, SPECIFIC_NAME "
 
1575
        + " FROM INFORMATION_SCHEMA.ROUTINES "  
 
1576
        + " WHERE " 
 
1577
        + catalogCond("ROUTINE_SCHEMA" , catalog)
 
1578
        + " AND "
 
1579
        + patternCond("ROUTINE_NAME", functionNamePattern)
 
1580
        + " AND ROUTINE_TYPE='FUNCTION'";
 
1581
        
 
1582
        return executeQuery(sql);
 
1583
    }
 
1584
 
 
1585
 
 
1586
 
 
1587
 
 
1588
    public <T> T unwrap(final Class<T> iface) throws SQLException {
 
1589
        return null;
 
1590
    }
 
1591
 
 
1592
    public boolean isWrapperFor(final Class<?> iface) throws SQLException {
 
1593
        return false;
 
1594
    }
 
1595
 
 
1596
 
 
1597
}
 
1598
 
 
1599
/*  Create table parsing stuff */
 
1600
 
 
1601
/*
 
1602
 Identifier, i.e table, or column name. Put into ` quotes in SHOW CREATE TABLE. Can be "multi-part", i.e `schema`.`table`
 
1603
 */
 
1604
class Identifier {
 
1605
    public String schema;
 
1606
    public String name;
 
1607
    public String toString() {
 
1608
        if (schema != null)
 
1609
            return schema + "." + name;
 
1610
        return name;
 
1611
    }
 
1612
}
 
1613
 
 
1614
/*
 
1615
 Parse foreign key constraints from "SHOW CREATE TABLE". The single usage of this class is to speedup getImportedKeys
 
1616
 (I_S appear to be too slow, see CONJ-41)
 
1617
*/
 
1618
class ShowCreateTableParser {
 
1619
     // Extract identifier quoted string from input String.
 
1620
     // Return new position, or -1 on error
 
1621
     static int skipWhite(char [] s, int startPos) {
 
1622
         for(int i = startPos; i < s.length; i++) {
 
1623
             if(!Character.isWhitespace(s[i])) {
 
1624
                 return i;
 
1625
             }
 
1626
         }
 
1627
         return s.length;
 
1628
     }
 
1629
 
 
1630
     static int parseIdentifier(char[] s, int startPos, Identifier identifier) throws ParseException {
 
1631
        int pos = skipWhite(s , startPos);
 
1632
        if (s[pos] != '`')
 
1633
            throw new ParseException(new String(s),pos);
 
1634
        pos++;
 
1635
        StringBuffer sb = new StringBuffer();
 
1636
        int nQuotes=0;
 
1637
        for(; pos < s.length; pos++) {
 
1638
            char ch = s[pos];
 
1639
            if (ch  == '`') {
 
1640
                nQuotes++;
 
1641
            } else {
 
1642
                for (int j = 0; j < nQuotes/2; j++)
 
1643
                    sb.append('`');
 
1644
                if (nQuotes %2 == 1) {
 
1645
                    if (ch == '.') {
 
1646
                        if (identifier.schema != null)
 
1647
                            throw new ParseException(new String(s), pos);
 
1648
                        identifier.schema = sb.toString();
 
1649
                        return parseIdentifier(s, pos + 1,identifier);
 
1650
                    }
 
1651
                    identifier.name = sb.toString();
 
1652
                    return pos;
 
1653
                }
 
1654
                nQuotes = 0;
 
1655
                sb.append(ch);
 
1656
            }
 
1657
        }
 
1658
        throw new ParseException(new String(s),startPos);
 
1659
     }
 
1660
    static int parseIdentifierList(char[] s, int startPos,List<Identifier> list) throws ParseException {
 
1661
        int pos = skipWhite(s , startPos);
 
1662
        if (s[pos] != '(') {
 
1663
            throw new ParseException(new String(s),pos);
 
1664
        }
 
1665
        pos++;
 
1666
        for(;;) {
 
1667
            pos = skipWhite(s, pos);
 
1668
            char ch = s[pos];
 
1669
            switch (ch) {
 
1670
                case ')':
 
1671
                    return pos +1 ;
 
1672
                case '`':
 
1673
                    Identifier id = new Identifier();
 
1674
                    pos = parseIdentifier(s, pos, id);
 
1675
                    list.add(id);
 
1676
                    break;
 
1677
                case ',':
 
1678
                    pos++;
 
1679
                    break;
 
1680
                default:
 
1681
                    throw new ParseException(new String(s,startPos, s.length - startPos),startPos);
 
1682
            }
 
1683
        }
 
1684
    }
 
1685
     static int skipKeyword(char[] s, int startPos, String keyword)  throws ParseException{
 
1686
         int pos = skipWhite(s , startPos);
 
1687
         for (int i = 0 ; i < keyword.length(); i++,pos++){
 
1688
             if (s[pos] != keyword.charAt(i)) {
 
1689
                throw new ParseException(new String(s),pos);
 
1690
             }
 
1691
         }
 
1692
         return pos;
 
1693
     }
 
1694
 
 
1695
     static int getImportedKeyAction(String s) {
 
1696
         if(s == null)
 
1697
             return DatabaseMetaData.importedKeyRestrict;
 
1698
         if (s.equals("NO ACTION"))
 
1699
             return DatabaseMetaData.importedKeyNoAction;
 
1700
         if (s.equals("CASCADE"))
 
1701
             return DatabaseMetaData.importedKeyCascade;
 
1702
         if (s.equals("SET NULL"))
 
1703
             return DatabaseMetaData.importedKeySetNull;
 
1704
         if (s.equals("SET DEFAULT"))
 
1705
             return DatabaseMetaData.importedKeySetDefault;
 
1706
         if (s.equals("RESTRICT"))
 
1707
             return DatabaseMetaData.importedKeyRestrict;
 
1708
         throw new AssertionError("should not happen");
 
1709
     }
 
1710
 
 
1711
 
 
1712
     public static ResultSet getImportedKeys(String tableDef, String tableName, String catalog, MySQLConnection c) throws ParseException {
 
1713
         String[] columnNames  = {
 
1714
                 "PKTABLE_CAT","PKTABLE_SCHEM", "PKTABLE_NAME",
 
1715
                 "PKCOLUMN_NAME","FKTABLE_CAT","FKTABLE_SCHEM",
 
1716
                 "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ",
 
1717
                 "UPDATE_RULE","DELETE_RULE","FK_NAME",
 
1718
                 "PK_NAME","DEFERRABILITY"
 
1719
                 };
 
1720
         MySQLType [] columnTypes =  {
 
1721
                 MySQLType.VARCHAR, MySQLType.NULL, MySQLType.VARCHAR,
 
1722
                 MySQLType.VARCHAR, MySQLType.VARCHAR, MySQLType.NULL,
 
1723
                 MySQLType.VARCHAR, MySQLType.VARCHAR, MySQLType.SMALLINT,
 
1724
                 MySQLType.SMALLINT, MySQLType.SMALLINT, MySQLType.VARCHAR,
 
1725
                 MySQLType.NULL,MySQLType.SMALLINT};
 
1726
 
 
1727
         String[] parts = tableDef.split("\n");
 
1728
 
 
1729
         List<String[]> data = new ArrayList<String[]>();
 
1730
 
 
1731
         for (String p:parts) {
 
1732
              //System.out.println("--" + p);
 
1733
              p = p.trim();
 
1734
              if (!p.startsWith("CONSTRAINT") && !p.contains("FOREIGN KEY"))
 
1735
                  continue;
 
1736
              char [] s = p.toCharArray();
 
1737
 
 
1738
              Identifier constraintName = new Identifier();
 
1739
              Identifier pkTable = new Identifier();
 
1740
              List<Identifier> foreignKeyCols = new ArrayList<Identifier>();
 
1741
              List<Identifier> primaryKeyCols = new ArrayList<Identifier>();
 
1742
 
 
1743
              int pos = skipKeyword(s, 0, "CONSTRAINT");
 
1744
              pos = parseIdentifier(s, pos, constraintName);
 
1745
              pos = skipKeyword(s, pos, "FOREIGN KEY");
 
1746
              pos = parseIdentifierList(s, pos, foreignKeyCols);
 
1747
              pos = skipKeyword(s, pos, "REFERENCES");
 
1748
              pos = parseIdentifier(s, pos, pkTable);
 
1749
              parseIdentifierList(s, pos, primaryKeyCols);
 
1750
              if (primaryKeyCols.size() != foreignKeyCols.size()) {
 
1751
                  throw new ParseException(tableDef,0);
 
1752
              }
 
1753
              int onUpdateReferenceAction = DatabaseMetaData.importedKeyRestrict;
 
1754
              int onDeleteReferenceAction = DatabaseMetaData.importedKeyRestrict;
 
1755
 
 
1756
 
 
1757
             for (String referenceAction : new String[] {"RESTRICT", "CASCADE",  "SET NULL", "NO ACTION"}) {
 
1758
                  if (p.contains("ON UPDATE " + referenceAction))
 
1759
                      onUpdateReferenceAction = getImportedKeyAction(referenceAction);
 
1760
                  if (p.contains("ON DELETE " + referenceAction))
 
1761
                      onDeleteReferenceAction =  getImportedKeyAction(referenceAction);
 
1762
             }
 
1763
 
 
1764
             for(int i = 0; i < primaryKeyCols.size(); i++) {
 
1765
 
 
1766
                 String[] row = new String[columnNames.length];
 
1767
                 row[0] =  pkTable.schema;
 
1768
                 if (row[0] == null) {
 
1769
                     row[0] = catalog;
 
1770
                 }
 
1771
                 row[1] = null;
 
1772
                 row[2] = pkTable.name;
 
1773
                 row[3] = primaryKeyCols.get(i).name;
 
1774
                 row[4] = catalog;
 
1775
                 row[5] = null;
 
1776
                 row[6] = tableName;
 
1777
                 row[7] = foreignKeyCols.get(i).name;
 
1778
                 row[8] = Integer.toString(i+1);
 
1779
                 row[9] = Integer.toString(onUpdateReferenceAction);
 
1780
                 row[10] = Integer.toString(onDeleteReferenceAction);
 
1781
                 row[11] = constraintName.name;
 
1782
                 row[12] = null;
 
1783
                 row[13] = Integer.toString(DatabaseMetaData.importedKeyInitiallyImmediate);
 
1784
                 data.add(row);
 
1785
             }
 
1786
         }
 
1787
         String[][] arr = data.toArray(new String[0][]);
 
1788
 
 
1789
         /* Sort array by PKTABLE_CAT, PKTABLE_NAME, and KEY_SEQ.*/
 
1790
         Arrays.sort(arr, new Comparator<String[]>() {
 
1791
             @Override
 
1792
             public int compare(String[] row1, String[] row2) {
 
1793
                 int result = row1[0].compareTo(row2[0]);   //PKTABLE_CAT
 
1794
                 if (result == 0){
 
1795
                    result = row1[2].compareTo(row2[2]);   //PKTABLE_NAME
 
1796
                    if (result == 0) {
 
1797
                        result = row1[8].length() - row2[8].length();  // KEY_SEQ
 
1798
                        if (result == 0)
 
1799
                            result =  row1[8].compareTo(row2[8]);
 
1800
                    }
 
1801
                 }
 
1802
                 return result;
 
1803
             }
 
1804
         });
 
1805
         ResultSet ret =  MySQLResultSet.createResultSet(columnNames,columnTypes,arr, c.getProtocol());
 
1806
         return ret;
 
1807
      }
 
1808
 }