2
MariaDB Client for Java
4
Copyright (c) 2012 Monty Program Ab.
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)
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
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.
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:
23
Copyright (c) 2009-2011, Marcus Eriksson
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.
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.
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.
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
50
package org.mariadb.jdbc;
52
import org.mariadb.jdbc.internal.common.Utils;
53
import org.mariadb.jdbc.internal.mysql.MySQLType;
54
import org.mariadb.jdbc.internal.mysql.MySQLValueObject;
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;
63
public class MySQLDatabaseMetaData implements DatabaseMetaData {
65
private MySQLConnection connection;
66
private String databaseProductName = "MySQL";
67
private String username;
69
private String dataTypeClause (String fullTypeColumnName){
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 +
105
/* Remove length from column type spec,convert to uppercase, e.g bigint(10) unsigned becomes BIGINT UNSIGNED */
106
static String columnTypeClause(String columnName) {
109
" UCASE(IF( " + columnName + " LIKE '%(%)%', CONCAT (SUBSTRING( " + columnName + ",1, LOCATE('(',"
110
+ columnName +") - 1 ), SUBSTRING(" + columnName + ",1+locate(')'," + columnName + "))), "
113
public MySQLDatabaseMetaData(Connection connection, String user, String url) {
114
this.connection = (MySQLConnection)connection;
115
this.username = user;
117
this.connection.getProtocol().getServerVersion();
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)
128
private String escapeQuote(String s) {
131
return "'" + Utils.escapeString(s, connection.noBackslashEscapes) + "'";
135
* Generate part of the information schema query that restricts catalog names
136
* In the driver, catalogs is the equivalent to MySQL schemas.
138
* @param columnName - column name in the information schema table
139
* @param catalog - catalog name.
141
* This driver does not (always) follow JDBC standard for following special values, due
142
* to ConnectorJ compatibility
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.
148
* 2. null - if nullCatalogMeansCurrent=true (which is the default), then the handling is the same
149
* as for "" . i.e return current catalog.
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.
154
* @return part of SQL query ,that restricts search for the catalog.
156
String catalogCond(String columnName, String catalog) {
157
if (catalog == null && connection.nullCatalogMeansCurrent) {
158
/* Treat null catalog as current */
162
if (catalog == null) {
165
if (catalog.equals("")) {
166
return "(ISNULL(database()) OR (" + columnName + " = database()))";
168
return "(" + columnName + " = " + escapeQuote(catalog) + ")" ;
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) {
177
String predicate = (tableName.indexOf('%') == -1 && tableName.indexOf('_') == -1)? "=" : "LIKE";
178
return "(" + columnName + " " + predicate + " '" + Utils.escapeString(tableName, true) + "')";
181
public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException {
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' "
187
+ catalogCond("A.TABLE_SCHEMA",catalog)
189
+ catalogCond("B.TABLE_SCHEMA",catalog)
191
+ patternCond("A.TABLE_NAME", table)
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";
197
return executeQuery(sql);
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.
208
private String mapTableTypes(String tableType) {
209
if(tableType.equals("TABLE")) {
215
public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types)
216
throws SQLException {
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 "
224
+ catalogCond("TABLE_SCHEMA",catalog)
226
+ patternCond("TABLE_NAME", tableNamePattern);
228
if (types != null && types.length > 0) {
229
sql += " AND TABLE_TYPE IN (" ;
230
for (int i=0 ; i < types.length; i++) {
233
String type = escapeQuote(mapTableTypes(types[i]));
234
if (i == types.length -1)
241
sql += " ORDER BY TABLE_TYPE, TABLE_SCHEMA, TABLE_NAME";
243
return executeQuery(sql);
246
public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern)
247
throws SQLException {
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"
259
+ " IF(NUMERIC_PRECISION IS NULL, LEAST(CHARACTER_MAXIMUM_LENGTH,"+Integer.MAX_VALUE+"), NUMERIC_PRECISION) "
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)
270
+ patternCond("TABLE_NAME", tableNamePattern)
272
+ patternCond("COLUMN_NAME", columnNamePattern)
273
+ " ORDER BY TABLE_CAT, TABLE_SCHEM, TABLE_NAME, ORDINAL_POSITION";
275
return executeQuery(sql);
278
public ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException {
280
throw new SQLException("'table' parameter in getExportedKeys cannot be null");
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,"
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"
308
+ catalogCond("KCU.REFERENCED_TABLE_SCHEMA", catalog)
310
+ " KCU.REFERENCED_TABLE_NAME = " + escapeQuote(table)
311
+ " ORDER BY FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, KEY_SEQ";
313
return executeQuery(sql);
320
public ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException {
322
// We avoid using information schema queries by default, because this appears to be an expensive
325
throw new SQLException("'table' parameter in getImportedKeys cannot be null");
328
if (catalog == null && connection.nullCatalogMeansCurrent) {
329
/* Treat null catalog as current */
332
if (catalog == null) {
333
return getImportedKeysUsingInformationSchema(catalog, schema, table);
336
if (catalog.equals("")) {
337
catalog = connection.getCatalog();
338
if (catalog == null || catalog.equals("")) {
339
return getImportedKeysUsingInformationSchema(catalog, schema, table);
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);
351
public ResultSet getImportedKeysUsingInformationSchema( String catalog, String schema, String table) throws SQLException {
353
throw new SQLException("'table' parameter in getImportedKeys cannot be null");
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,"
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"
381
+ catalogCond("KCU.TABLE_SCHEMA", catalog)
383
+ " KCU.TABLE_NAME = " + escapeQuote(table)
384
+ " ORDER BY PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME, KEY_SEQ";
386
return executeQuery(sql);
389
public ResultSet getImportedKeysUsingShowCreateTable( String catalog, String schema, String table) throws Exception {
391
if (catalog == null || catalog.equals(""))
392
throw new IllegalArgumentException("catalog");
394
if (table == null || table.equals(""))
395
throw new IllegalArgumentException("table");
397
ResultSet rs = connection.createStatement().executeQuery("SHOW CREATE TABLE " +
398
MySQLConnection.quoteIdentifier(catalog) + "." + MySQLConnection.quoteIdentifier(table));
400
String tableDef = rs.getString(2);
401
return ShowCreateTableParser.getImportedKeys(tableDef, table, catalog, connection);
404
public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, final boolean nullable)
405
throws SQLException {
408
throw new SQLException("'table' parameter cannot be null in getBestRowIdentifier()");
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,"
417
+ " FROM INFORMATION_SCHEMA.COLUMNS"
418
+ " WHERE COLUMN_KEY IN('PRI', 'MUL', 'UNI')"
420
+ catalogCond("TABLE_SCHEMA",catalog)
421
+ " AND TABLE_NAME = " + escapeQuote(table);
423
return executeQuery(sql);
426
public boolean generatedKeyAlwaysReturned() throws SQLException {
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 " +
439
public boolean allProceduresAreCallable() throws SQLException {
443
public boolean allTablesAreSelectable() throws SQLException {
447
public String getURL() throws SQLException {
451
public String getUserName() throws SQLException {
456
public boolean isReadOnly() throws SQLException {
461
public boolean nullsAreSortedHigh() throws SQLException {
466
public boolean nullsAreSortedLow() throws SQLException {
467
return !nullsAreSortedHigh();
471
public boolean nullsAreSortedAtStart() throws SQLException {
475
public boolean nullsAreSortedAtEnd() throws SQLException {
476
return !nullsAreSortedAtStart();
480
public String getDatabaseProductName() throws SQLException {
481
return databaseProductName;
485
public String getDatabaseProductVersion() throws SQLException {
486
return connection.getProtocol().getServerVersion();
490
public String getDriverName() throws SQLException {
491
return "mariadb-jdbc"; // TODO: get from constants file
494
public String getDriverVersion() throws SQLException {
495
return String.format("%d.%d",getDriverMajorVersion(),getDriverMinorVersion());
499
public int getDriverMajorVersion() {
503
public int getDriverMinorVersion() {
508
public boolean usesLocalFiles() throws SQLException {
512
public boolean usesLocalFilePerTable() throws SQLException {
516
public boolean supportsMixedCaseIdentifiers() throws SQLException {
517
return (connection.getLowercaseTableNames() == 0);
520
public boolean storesUpperCaseIdentifiers() throws SQLException {
524
public boolean storesLowerCaseIdentifiers() throws SQLException {
525
return (connection.getLowercaseTableNames() == 1);
528
public boolean storesMixedCaseIdentifiers() throws SQLException {
529
return (connection.getLowercaseTableNames() == 2);
532
public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException {
533
return supportsMixedCaseIdentifiers();
536
public boolean storesUpperCaseQuotedIdentifiers() throws SQLException {
537
return storesUpperCaseIdentifiers();
540
public boolean storesLowerCaseQuotedIdentifiers() throws SQLException {
541
return storesLowerCaseIdentifiers();
544
public boolean storesMixedCaseQuotedIdentifiers() throws SQLException {
545
return storesMixedCaseIdentifiers();
548
public String getIdentifierQuoteString() throws SQLException {
552
public String getSQLKeywords() throws SQLException {
619
"MINUTE_MICROSECOND,"+
623
"NO_WRITE_TO_BINLOG,"+
642
"SECOND_MICROSECOND,"+
650
"SQL_CALC_FOUND_ROWS,"+
675
"IGNORE_SERVER_IDS,"+
676
"MASTER_HEARTBEAT_PERIOD,"+
683
public String getNumericFunctions() throws SQLException {
684
return ""; //TODO : fix
688
public String getStringFunctions() throws SQLException {
689
return ""; //TODO: fix
692
public String getSystemFunctions() throws SQLException {
693
return "DATABASE,USER,SYSTEM_USER,SESSION_USER,LAST_INSERT_ID,VERSION";
697
public String getTimeDateFunctions() throws SQLException {
698
return ""; //TODO : fix
701
public String getSearchStringEscape() throws SQLException {
705
public String getExtraNameCharacters() throws SQLException {
709
public boolean supportsAlterTableWithAddColumn() throws SQLException {
713
public boolean supportsAlterTableWithDropColumn() throws SQLException {
717
public boolean supportsColumnAliasing() throws SQLException {
721
public boolean nullPlusNonNullIsNull() throws SQLException {
725
public boolean supportsConvert() throws SQLException {
726
return false; //TODO: fix
729
public boolean supportsConvert(int fromType, int toType)
730
throws SQLException {
731
return false; // TODO: fix
734
public boolean supportsTableCorrelationNames() throws SQLException {
738
public boolean supportsDifferentTableCorrelationNames() throws SQLException {
742
public boolean supportsExpressionsInOrderBy() throws SQLException {
746
public boolean supportsOrderByUnrelated() throws SQLException {
750
public boolean supportsGroupBy() throws SQLException {
754
public boolean supportsGroupByUnrelated() throws SQLException {
758
public boolean supportsGroupByBeyondSelect() throws SQLException {
762
public boolean supportsLikeEscapeClause() throws SQLException {
766
public boolean supportsMultipleResultSets() throws SQLException {
770
public boolean supportsMultipleTransactions() throws SQLException {
774
public boolean supportsNonNullableColumns() throws SQLException {
778
public boolean supportsMinimumSQLGrammar() throws SQLException {
782
public boolean supportsCoreSQLGrammar() throws SQLException {
786
public boolean supportsExtendedSQLGrammar() throws SQLException {
790
public boolean supportsANSI92EntryLevelSQL() throws SQLException {
794
public boolean supportsANSI92IntermediateSQL() throws SQLException {
798
public boolean supportsANSI92FullSQL() throws SQLException {
802
public boolean supportsIntegrityEnhancementFacility() throws SQLException {
803
return false; //TODO: verify
806
public boolean supportsOuterJoins() throws SQLException {
809
public boolean supportsFullOuterJoins() throws SQLException {
813
public boolean supportsLimitedOuterJoins() throws SQLException {
817
public String getSchemaTerm() throws SQLException {
822
public String getProcedureTerm() throws SQLException {
826
public String getCatalogTerm() throws SQLException {
831
public boolean isCatalogAtStart() throws SQLException {
836
public String getCatalogSeparator() throws SQLException {
841
public boolean supportsSchemasInDataManipulation() throws SQLException {
846
public boolean supportsSchemasInProcedureCalls() throws SQLException {
850
public boolean supportsSchemasInTableDefinitions() throws SQLException {
854
public boolean supportsSchemasInIndexDefinitions() throws SQLException {
858
public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException {
862
public boolean supportsCatalogsInDataManipulation() throws SQLException {
866
public boolean supportsCatalogsInProcedureCalls() throws SQLException {
870
public boolean supportsCatalogsInTableDefinitions() throws SQLException {
874
public boolean supportsCatalogsInIndexDefinitions() throws SQLException {
878
public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException {
882
public boolean supportsPositionedDelete() throws SQLException {
886
public boolean supportsPositionedUpdate() throws SQLException {
890
public boolean supportsSelectForUpdate() throws SQLException {
894
public boolean supportsStoredProcedures() throws SQLException {
899
public boolean supportsSubqueriesInComparisons() throws SQLException {
903
public boolean supportsSubqueriesInExists() throws SQLException {
908
public boolean supportsSubqueriesInIns() throws SQLException {
912
public boolean supportsSubqueriesInQuantifieds() throws SQLException {
917
public boolean supportsCorrelatedSubqueries() throws SQLException {
922
public boolean supportsUnion() throws SQLException {
927
public boolean supportsUnionAll() throws SQLException {
932
public boolean supportsOpenCursorsAcrossCommit() throws SQLException {
936
public boolean supportsOpenCursorsAcrossRollback() throws SQLException {
940
public boolean supportsOpenStatementsAcrossCommit() throws SQLException {
944
public boolean supportsOpenStatementsAcrossRollback() throws SQLException {
948
public int getMaxBinaryLiteralLength() throws SQLException {
952
public int getMaxCharLiteralLength() throws SQLException {
956
public int getMaxColumnNameLength() throws SQLException {
960
public int getMaxColumnsInGroupBy() throws SQLException {
965
public int getMaxColumnsInIndex() throws SQLException {
970
public int getMaxColumnsInOrderBy() throws SQLException {
974
public int getMaxColumnsInSelect() throws SQLException {
979
public int getMaxColumnsInTable() throws SQLException {
983
public int getMaxConnections() throws SQLException {
988
public int getMaxCursorNameLength() throws SQLException {
993
public int getMaxIndexLength() throws SQLException {
996
public int getMaxSchemaNameLength() throws SQLException {
1000
public int getMaxProcedureNameLength() throws SQLException {
1004
public int getMaxCatalogNameLength() throws SQLException {
1008
public int getMaxRowSize() throws SQLException {
1012
public boolean doesMaxRowSizeIncludeBlobs() throws SQLException {
1016
public int getMaxStatementLength() throws SQLException {
1020
public int getMaxStatements() throws SQLException {
1024
public int getMaxTableNameLength() throws SQLException {
1028
public int getMaxTablesInSelect() throws SQLException {
1032
public int getMaxUserNameLength() throws SQLException {
1036
public int getDefaultTransactionIsolation() throws SQLException {
1037
return Connection.TRANSACTION_REPEATABLE_READ;
1040
public boolean supportsTransactions() throws SQLException {
1045
public boolean supportsTransactionIsolationLevel(int level) throws SQLException {
1047
case Connection.TRANSACTION_READ_UNCOMMITTED:
1048
case Connection.TRANSACTION_READ_COMMITTED:
1049
case Connection.TRANSACTION_REPEATABLE_READ:
1050
case Connection.TRANSACTION_SERIALIZABLE:
1058
public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException {
1062
public boolean supportsDataManipulationTransactionsOnly() throws SQLException {
1066
public boolean dataDefinitionCausesTransactionCommit() throws SQLException {
1071
public boolean dataDefinitionIgnoredInTransactions() throws SQLException {
1076
/* Helper to generate information schema with "equality" condition (typically on catalog name)
1080
public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern)
1081
throws SQLException {
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 "
1094
+ catalogCond("ROUTINE_SCHEMA" , catalog)
1096
+ patternCond("ROUTINE_NAME", procedureNamePattern)
1097
+ "/* AND ROUTINE_TYPE='PROCEDURE' */";
1098
return executeQuery(sql);
1102
/* Is INFORMATION_SCHEMA.PARAMETERS available ?*/
1103
boolean haveInformationSchemaParameters() {
1104
return connection.getProtocol().versionGreaterOrEqual(5, 5, 3);
1107
public ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern,
1108
String columnNamePattern) throws SQLException {
1111
if (haveInformationSchemaParameters()) {
1113
* Get info from information_schema.parameters
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 "
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";
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.
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 "
1149
return executeQuery(sql);
1152
public ResultSet getFunctionColumns(String catalog, String schemaPattern, String procedureNamePattern,
1153
String columnNamePattern) throws SQLException {
1156
if (haveInformationSchemaParameters()) {
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 "
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";
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.
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 " ;
1191
return executeQuery(sql);
1194
public ResultSet getSchemas() throws SQLException {
1195
return executeQuery(
1196
"SELECT '' TABLE_SCHEM, '' TABLE_catalog FROM DUAL WHERE 1=0");
1200
public ResultSet getCatalogs() throws SQLException {
1201
return executeQuery(
1202
"SELECT SCHEMA_NAME TABLE_CAT FROM INFORMATION_SCHEMA.SCHEMATA ORDER BY 1");
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");
1210
public ResultSet getColumnPrivileges(String catalog, String schema, String table,
1211
String columnNamePattern) throws SQLException {
1214
throw new SQLException("'table' parameter must not be null");
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)
1222
+ " TABLE_NAME = " + escapeQuote(table)
1224
+ patternCond("COLUMN_NAME",columnNamePattern)
1225
+ " ORDER BY COLUMN_NAME, PRIVILEGE_TYPE";
1227
return executeQuery(sql);
1230
public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern)
1231
throws SQLException {
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 "
1236
+ catalogCond("TABLE_SCHEMA", catalog)
1238
+ patternCond("TABLE_NAME",tableNamePattern)
1239
+ "ORDER BY TABLE_SCHEMA, TABLE_NAME, PRIVILEGE_TYPE ";
1241
return executeQuery(sql);
1244
public ResultSet getVersionColumns(String catalog, String schema, String table)
1245
throws SQLException {
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);
1254
public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable,
1255
String foreignCatalog, String foreignSchema, String foreignTable)
1256
throws SQLException {
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,"
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"
1284
+ catalogCond("KCU.REFERENCED_TABLE_SCHEMA", parentCatalog)
1286
+ catalogCond("KCU.TABLE_SCHEMA", foreignCatalog)
1288
+ " KCU.REFERENCED_TABLE_NAME = " + escapeQuote(parentTable)
1290
+ " KCU.TABLE_NAME = " + escapeQuote(foreignTable)
1291
+ " ORDER BY FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, KEY_SEQ";
1293
return executeQuery(sql);
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"
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
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"}
1353
return MySQLResultSet.createResultSet(columnNames, columnTypes, data, connection.getProtocol());
1356
public ResultSet getIndexInfo(String catalog, String schema, String table,
1357
boolean unique,boolean approximate) throws SQLException {
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)
1367
+ catalogCond("TABLE_SCHEMA",catalog)
1368
+ ((unique) ? " AND NON_UNIQUE = 0" : "")
1369
+ " ORDER BY NON_UNIQUE, TYPE, INDEX_NAME, ORDINAL_POSITION";
1371
return executeQuery(sql);
1375
public boolean supportsResultSetType(int type) throws SQLException {
1380
public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException {
1381
return concurrency == ResultSet.CONCUR_READ_ONLY;
1384
public boolean ownUpdatesAreVisible(int type) throws SQLException {
1389
public boolean ownDeletesAreVisible(int type) throws SQLException {
1394
public boolean ownInsertsAreVisible(int type) throws SQLException {
1399
public boolean othersUpdatesAreVisible(int type) throws SQLException {
1404
public boolean othersDeletesAreVisible(int type) throws SQLException {
1408
public boolean othersInsertsAreVisible(int type) throws SQLException {
1412
public boolean updatesAreDetected(int type) throws SQLException {
1417
public boolean deletesAreDetected(int type) throws SQLException {
1422
public boolean insertsAreDetected(int type) throws SQLException {
1427
public boolean supportsBatchUpdates() throws SQLException {
1432
public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types)
1433
throws SQLException {
1435
"SELECT ' ' TYPE_CAT, NULL TYPE_SCHEM, ' ' TYPE_NAME, ' ' CLASS_NAME, 0 DATA_TYPE, ' ' REMARKS, 0 BASE_TYPE"
1436
+ " FROM DUAL WHERE 1=0";
1438
return executeQuery(sql);
1443
public Connection getConnection() throws SQLException {
1448
public boolean supportsSavepoints() throws SQLException {
1453
public boolean supportsNamedParameters() throws SQLException {
1458
public boolean supportsMultipleOpenResults() throws SQLException {
1463
public boolean supportsGetGeneratedKeys() throws SQLException {
1468
public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern)
1469
throws SQLException {
1471
"SELECT ' ' TYPE_CAT, NULL TYPE_SCHEM, ' ' TYPE_NAME, ' ' SUPERTYPE_CAT, ' ' SUPERTYPE_SCHEM, ' ' SUPERTYPE_NAME"
1472
+ " FROM DUAL WHERE 1=0";
1474
return executeQuery(sql);
1478
public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern)
1479
throws SQLException {
1481
"SELECT ' ' TABLE_CAT, ' ' TABLE_SCHEM, ' ' TABLE_NAME, ' ' SUPERTABLE_NAME FROM DUAL WHERE 1=0";
1482
return executeQuery(sql);
1486
public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern,
1487
String attributeNamePattern) throws SQLException {
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"
1498
return executeQuery(sql);
1501
public boolean supportsResultSetHoldability(int holdability)
1502
throws SQLException {
1503
return holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT;
1507
public int getResultSetHoldability() throws SQLException {
1508
return ResultSet.HOLD_CURSORS_OVER_COMMIT;
1512
public int getDatabaseMajorVersion() throws SQLException {
1513
return connection.getProtocol().getMajorServerVersion();
1517
public int getDatabaseMinorVersion() throws SQLException {
1518
return connection.getProtocol().getMinorServerVersion();
1522
public int getJDBCMajorVersion() throws SQLException {
1526
public int getJDBCMinorVersion() throws SQLException {
1531
public int getSQLStateType() throws SQLException {
1536
public boolean locatorsUpdateCopy() throws SQLException {
1541
public boolean supportsStatementPooling() throws SQLException {
1546
public java.sql.RowIdLifetime getRowIdLifetime() throws SQLException {
1547
return java.sql.RowIdLifetime.ROWID_UNSUPPORTED;
1551
public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException {
1552
return executeQuery("SELECT ' ' table_schem, ' ' table_catalog FROM DUAL WHERE 1=0");
1555
public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException {
1559
public boolean autoCommitFailureClosesAllResultSets() throws SQLException {
1560
return false; //TODO: look into this
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);
1570
public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern)
1571
throws SQLException {
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 "
1577
+ catalogCond("ROUTINE_SCHEMA" , catalog)
1579
+ patternCond("ROUTINE_NAME", functionNamePattern)
1580
+ " AND ROUTINE_TYPE='FUNCTION'";
1582
return executeQuery(sql);
1588
public <T> T unwrap(final Class<T> iface) throws SQLException {
1592
public boolean isWrapperFor(final Class<?> iface) throws SQLException {
1599
/* Create table parsing stuff */
1602
Identifier, i.e table, or column name. Put into ` quotes in SHOW CREATE TABLE. Can be "multi-part", i.e `schema`.`table`
1605
public String schema;
1607
public String toString() {
1609
return schema + "." + name;
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)
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])) {
1630
static int parseIdentifier(char[] s, int startPos, Identifier identifier) throws ParseException {
1631
int pos = skipWhite(s , startPos);
1633
throw new ParseException(new String(s),pos);
1635
StringBuffer sb = new StringBuffer();
1637
for(; pos < s.length; pos++) {
1642
for (int j = 0; j < nQuotes/2; j++)
1644
if (nQuotes %2 == 1) {
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);
1651
identifier.name = sb.toString();
1658
throw new ParseException(new String(s),startPos);
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);
1667
pos = skipWhite(s, pos);
1673
Identifier id = new Identifier();
1674
pos = parseIdentifier(s, pos, id);
1681
throw new ParseException(new String(s,startPos, s.length - startPos),startPos);
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);
1695
static int getImportedKeyAction(String s) {
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");
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"
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};
1727
String[] parts = tableDef.split("\n");
1729
List<String[]> data = new ArrayList<String[]>();
1731
for (String p:parts) {
1732
//System.out.println("--" + p);
1734
if (!p.startsWith("CONSTRAINT") && !p.contains("FOREIGN KEY"))
1736
char [] s = p.toCharArray();
1738
Identifier constraintName = new Identifier();
1739
Identifier pkTable = new Identifier();
1740
List<Identifier> foreignKeyCols = new ArrayList<Identifier>();
1741
List<Identifier> primaryKeyCols = new ArrayList<Identifier>();
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);
1753
int onUpdateReferenceAction = DatabaseMetaData.importedKeyRestrict;
1754
int onDeleteReferenceAction = DatabaseMetaData.importedKeyRestrict;
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);
1764
for(int i = 0; i < primaryKeyCols.size(); i++) {
1766
String[] row = new String[columnNames.length];
1767
row[0] = pkTable.schema;
1768
if (row[0] == null) {
1772
row[2] = pkTable.name;
1773
row[3] = primaryKeyCols.get(i).name;
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;
1783
row[13] = Integer.toString(DatabaseMetaData.importedKeyInitiallyImmediate);
1787
String[][] arr = data.toArray(new String[0][]);
1789
/* Sort array by PKTABLE_CAT, PKTABLE_NAME, and KEY_SEQ.*/
1790
Arrays.sort(arr, new Comparator<String[]>() {
1792
public int compare(String[] row1, String[] row2) {
1793
int result = row1[0].compareTo(row2[0]); //PKTABLE_CAT
1795
result = row1[2].compareTo(row2[2]); //PKTABLE_NAME
1797
result = row1[8].length() - row2[8].length(); // KEY_SEQ
1799
result = row1[8].compareTo(row2[8]);
1805
ResultSet ret = MySQLResultSet.createResultSet(columnNames,columnTypes,arr, c.getProtocol());