| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.openjpa.jdbc.sql; |
| |
| import java.security.AccessController; |
| import java.security.PrivilegedActionException; |
| import java.sql.Connection; |
| import java.sql.DatabaseMetaData; |
| import java.sql.SQLException; |
| import java.util.Locale; |
| import java.util.Objects; |
| |
| import javax.sql.DataSource; |
| |
| import org.apache.openjpa.jdbc.conf.JDBCConfiguration; |
| import org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl; |
| import org.apache.openjpa.lib.conf.Configurations; |
| import org.apache.openjpa.lib.conf.PluginValue; |
| import org.apache.openjpa.lib.log.Log; |
| import org.apache.openjpa.lib.util.J2DoPrivHelper; |
| import org.apache.openjpa.lib.util.Localizer; |
| import org.apache.openjpa.lib.util.StringUtil; |
| import org.apache.openjpa.util.StoreException; |
| import org.apache.openjpa.util.UserException; |
| |
| /** |
| * Factory class to instantiate a dictionary. It will use |
| * the following heuristic: |
| * <ul> |
| * <li>Check to see if there is a DictionaryClass property, |
| * and if so, use that to instantiate the dictionary.</li> |
| * <li>Check the URL in the JDBCConfiguration against a list |
| * of pre-defined URLs for various dictionaries.</li> |
| * <li>Check the driver in the JDBCConfiguration against a list of known |
| * patterns.</li> |
| * <li>Acquire a connection and check its database metadata.</li> |
| * <li>Return an instance of the generic DBDictionary.</li> |
| * </ul> |
| * |
| * @author Marc Prud'hommeaux |
| */ |
| public class DBDictionaryFactory { |
| |
| private static final Localizer _loc = Localizer.forPackage |
| (DBDictionaryFactory.class); |
| |
| /** |
| * Create the dictionary for the given class name and properties. |
| */ |
| public static DBDictionary newDBDictionary(JDBCConfiguration conf, |
| String dclass, String props) { |
| return newDBDictionary(conf, dclass, props, null); |
| } |
| |
| /** |
| * Attempt to create the dictionary from the given connection URL and |
| * driver name, either or both of which may be null. If the dictionary |
| * cannot be calculated, returns null. |
| */ |
| public static DBDictionary calculateDBDictionary(JDBCConfiguration conf, |
| String url, String driver, String props) { |
| String dclass = dictionaryClassForString(getProtocol(url), conf); |
| if (dclass == null) |
| dclass = dictionaryClassForString(driver, conf); |
| if (dclass == null) |
| return null; |
| return newDBDictionary(conf, dclass, props); |
| } |
| |
| /** |
| * Create the dictionary using connection metadata to determine its type. |
| */ |
| public static DBDictionary newDBDictionary(JDBCConfiguration conf, |
| DataSource ds, String props) { |
| Connection conn = null; |
| try { |
| conn = ds.getConnection(); |
| DatabaseMetaData meta = conn.getMetaData(); |
| String dclass = dictionaryClassForString(meta.getDatabaseProductName(), conf); |
| if (dclass == null) |
| dclass = dictionaryClassForString(getProtocol(meta.getURL()), conf); |
| if (dclass != null && dclass.contains("MySQL")) { |
| // MariaDB returns "MySQL" for product name, need to verify by looking at product version. |
| final String checkMariaDB = dictionaryClassForString(meta.getDatabaseProductVersion(), conf); |
| if (checkMariaDB != null) { |
| dclass = checkMariaDB; |
| } |
| } |
| if (dclass == null) |
| dclass = DBDictionary.class.getName(); |
| return newDBDictionary(conf, dclass, props, conn); |
| } catch (SQLException se) { |
| throw new StoreException(se).setFatal(true); |
| } finally { |
| if (conn != null) |
| try { |
| conn.close(); |
| } catch (SQLException se) { |
| } |
| } |
| } |
| |
| /* |
| * Returns the "jdbc:" protocol of the url parameter. Looks for the prefix |
| * string up to the 3rd ':' or the 1st '@', '/' or '\', whichever comes |
| * first. |
| * |
| * This method is package qualified so that TestDictionaryFactory class can |
| * access and test this method behavior. |
| */ |
| static String getProtocol(String url) { |
| String protocol = null; |
| if (!StringUtil.isEmpty(url)) { |
| if (url.startsWith("jdbc:")) { |
| int colonCount = 1; |
| int next = "jdbc:".length(); |
| int protoEnd = next; |
| while (colonCount < 3 && next < url.length()) { |
| char c = url.charAt(next++); |
| if (c == ':') { |
| ++colonCount; |
| protoEnd = next; |
| } else if (c == '@' || c == '/' || c == '\\') { |
| --next; |
| break; |
| } |
| } |
| protocol = url.substring(0, protoEnd); |
| } |
| } |
| return protocol; |
| } |
| |
| /** |
| * Create the dictionary using the given class name and properties; the |
| * connection may be null if not supplied to the factory. |
| */ |
| private static DBDictionary newDBDictionary(JDBCConfiguration conf, |
| String dclass, String props, Connection conn) { |
| DBDictionary dict = null; |
| try { |
| Class<?> c = Class.forName(dclass, true, |
| AccessController.doPrivileged( |
| J2DoPrivHelper.getClassLoaderAction( |
| DBDictionary.class))); |
| dict = (DBDictionary) AccessController.doPrivileged( |
| J2DoPrivHelper.newInstanceAction(c)); |
| } catch (ClassNotFoundException cnfe) { |
| // if the dictionary was not found, make another attempt |
| // at loading the dictionary using the current thread. |
| try { |
| Class<?> c = Thread.currentThread().getContextClassLoader().loadClass(dclass); |
| dict = (DBDictionary) AccessController.doPrivileged( |
| J2DoPrivHelper.newInstanceAction(c)); |
| } catch (Exception e) { |
| if (e instanceof PrivilegedActionException) |
| e = ((PrivilegedActionException) e).getException(); |
| throw new UserException(e).setFatal(true); |
| } |
| } catch (Exception e) { |
| if (e instanceof PrivilegedActionException) |
| e = ((PrivilegedActionException) e).getException(); |
| throw new UserException(e).setFatal(true); |
| } |
| |
| // warn if we could not locate the appropriate dictionary |
| Log log = conf.getLog(JDBCConfiguration.LOG_JDBC); |
| if (log.isWarnEnabled() && dict.getClass() == DBDictionary.class) |
| log.warn(_loc.get("warn-generic")); |
| |
| if (log.isInfoEnabled()) { |
| String infoString = ""; |
| if (conn != null) { |
| try { |
| DatabaseMetaData meta = conn.getMetaData(); |
| infoString = " (" + meta.getDatabaseProductName() + " " |
| + meta.getDatabaseProductVersion() + " ," |
| + meta.getDriverName() + " " |
| + meta.getDriverVersion() + ")"; |
| } catch (SQLException se) { |
| if (log.isTraceEnabled()) |
| log.trace(se.toString(), se); |
| } |
| } |
| |
| log.info(_loc.get("using-dict", dclass, infoString)); |
| } |
| |
| // set the dictionary's metadata |
| Configurations.configureInstance(dict, conf, props, "DBDictionary"); |
| if (conn != null) { |
| try { |
| dict.connectedConfiguration(conn); |
| } catch (SQLException se) { |
| throw new StoreException(se).setFatal(true); |
| } |
| } |
| return dict; |
| } |
| |
| /** |
| * Guess the dictionary class name to use based on the product string. |
| */ |
| private static String dictionaryClassForString(String prod, JDBCConfiguration conf) { |
| if (StringUtil.isEmpty(prod)) |
| return null; |
| prod = prod.toLowerCase(Locale.ENGLISH); |
| |
| PluginValue dbdictionaryPlugin = ((JDBCConfigurationImpl) conf) |
| .dbdictionaryPlugin; |
| |
| if (prod.indexOf("oracle") != -1) |
| return dbdictionaryPlugin.unalias("oracle"); |
| if (prod.indexOf("sqlserver") != -1) |
| return dbdictionaryPlugin.unalias("sqlserver"); |
| if (prod.indexOf("jsqlconnect") != -1) |
| return dbdictionaryPlugin.unalias("sqlserver"); |
| if (prod.indexOf("mariadb") != -1) |
| return dbdictionaryPlugin.unalias("mariadb"); |
| if (prod.indexOf("mysql") != -1) |
| return dbdictionaryPlugin.unalias("mysql"); |
| if (prod.indexOf("postgres") != -1) |
| return dbdictionaryPlugin.unalias("postgres"); |
| if (prod.indexOf("sybase") != -1) |
| return dbdictionaryPlugin.unalias("sybase"); |
| if (prod.indexOf("adaptive server") != -1) |
| return dbdictionaryPlugin.unalias("sybase"); |
| if (prod.indexOf("informix") != -1 || prod.indexOf("ids") != -1) |
| return dbdictionaryPlugin.unalias("informix"); |
| if (prod.indexOf("ingres") != -1) |
| return dbdictionaryPlugin.unalias("ingres"); |
| if (prod.indexOf("hsql") != -1) |
| return dbdictionaryPlugin.unalias("hsql"); |
| if (prod.indexOf("foxpro") != -1) |
| return dbdictionaryPlugin.unalias("foxpro"); |
| if (prod.indexOf("interbase") != -1) |
| return InterbaseDictionary.class.getName(); |
| if (prod.indexOf("jdatastore") != -1) |
| return JDataStoreDictionary.class.getName(); |
| if (prod.indexOf("borland") != -1) |
| return JDataStoreDictionary.class.getName(); |
| if (prod.indexOf("access") != -1) |
| return dbdictionaryPlugin.unalias("access"); |
| if (prod.indexOf("pointbase") != -1) |
| return dbdictionaryPlugin.unalias("pointbase"); |
| if (prod.indexOf("empress") != -1) |
| return dbdictionaryPlugin.unalias("empress"); |
| if (prod.indexOf("firebird") != -1) |
| return FirebirdDictionary.class.getName(); |
| if (prod.indexOf("cache") != -1) |
| return CacheDictionary.class.getName(); |
| if (prod.indexOf("derby") != -1) |
| return dbdictionaryPlugin.unalias("derby"); |
| if (prod.indexOf("sapdb") != -1) { |
| return dbdictionaryPlugin.unalias("maxdb"); |
| } |
| // test h2 in a special way, because there's a decent chance the string |
| // h2 could appear in the URL of another database |
| if (prod.indexOf("jdbc:h2:") != -1) |
| return dbdictionaryPlugin.unalias("h2"); |
| if (prod.indexOf("h2 database") != -1) |
| return dbdictionaryPlugin.unalias("h2"); |
| // test db2 last, because there's a decent chance this string could |
| // appear in the URL of another database (like if the db is named |
| // "testdb2" or something) |
| if (prod.indexOf("db2") != -1 || prod.indexOf("as400") != -1) |
| return dbdictionaryPlugin.unalias("db2"); |
| if (prod.indexOf("soliddb") != -1) |
| return dbdictionaryPlugin.unalias("soliddb"); |
| |
| // known dbs that we don't support |
| if (prod.indexOf("cloudscape") != -1) |
| return DBDictionary.class.getName(); |
| if (prod.indexOf("daffodil") != -1) |
| return DBDictionary.class.getName(); |
| if (prod.indexOf("idb") != -1) // instantdb |
| return DBDictionary.class.getName(); |
| |
| String prodClassName = dbdictionaryPlugin.unalias(prod); |
| if (!Objects.equals(prod, prodClassName)) |
| return prodClassName; |
| |
| // give up |
| return null; |
| } |
| |
| /** |
| * Return a string containing all the property values of the given |
| * database metadata. |
| */ |
| public static String toString(DatabaseMetaData meta) |
| throws SQLException { |
| String lineSep = J2DoPrivHelper.getLineSeparator(); |
| StringBuilder buf = new StringBuilder(4096); |
| try { |
| buf.append("catalogSeparator: ") |
| .append(meta.getCatalogSeparator()) |
| .append(lineSep) |
| .append("catalogTerm: ") |
| .append(meta.getCatalogTerm()) |
| .append(lineSep) |
| .append("databaseProductName: ") |
| .append(meta.getDatabaseProductName()) |
| .append(lineSep) |
| .append("databaseProductVersion: ") |
| .append(meta.getDatabaseProductVersion()) |
| .append(lineSep) |
| .append("driverName: ") |
| .append(meta.getDriverName()) |
| .append(lineSep) |
| .append("driverVersion: ") |
| .append(meta.getDriverVersion()) |
| .append(lineSep) |
| .append("extraNameCharacters: ") |
| .append(meta.getExtraNameCharacters()) |
| .append(lineSep) |
| .append("identifierQuoteString: ") |
| .append(meta.getIdentifierQuoteString()) |
| .append(lineSep) |
| .append("numericFunctions: ") |
| .append(meta.getNumericFunctions()) |
| .append(lineSep) |
| .append("procedureTerm: ") |
| .append(meta.getProcedureTerm()) |
| .append(lineSep) |
| .append("schemaTerm: ") |
| .append(meta.getSchemaTerm()) |
| .append(lineSep) |
| .append("searchStringEscape: ") |
| .append(meta.getSearchStringEscape()) |
| .append(lineSep) |
| .append("sqlKeywords: ") |
| .append(meta.getSQLKeywords()) |
| .append(lineSep) |
| .append("stringFunctions: ") |
| .append(meta.getStringFunctions()) |
| .append(lineSep) |
| .append("systemFunctions: ") |
| .append(meta.getSystemFunctions()) |
| .append(lineSep) |
| .append("timeDateFunctions: ") |
| .append(meta.getTimeDateFunctions()) |
| .append(lineSep) |
| .append("url: ") |
| .append(meta.getURL()) |
| .append(lineSep) |
| .append("userName: ") |
| .append(meta.getUserName()) |
| .append(lineSep) |
| .append("defaultTransactionIsolation: ") |
| .append(meta.getDefaultTransactionIsolation()) |
| .append(lineSep) |
| .append("driverMajorVersion: ") |
| .append(meta.getDriverMajorVersion()) |
| .append(lineSep) |
| .append("driverMinorVersion: ") |
| .append(meta.getDriverMinorVersion()) |
| .append(lineSep) |
| .append("maxBinaryLiteralLength: ") |
| .append(meta.getMaxBinaryLiteralLength()) |
| .append(lineSep) |
| .append("maxCatalogNameLength: ") |
| .append(meta.getMaxCatalogNameLength()) |
| .append(lineSep) |
| .append("maxCharLiteralLength: ") |
| .append(meta.getMaxCharLiteralLength()) |
| .append(lineSep) |
| .append("maxColumnNameLength: ") |
| .append(meta.getMaxColumnNameLength()) |
| .append(lineSep) |
| .append("maxColumnsInGroupBy: ") |
| .append(meta.getMaxColumnsInGroupBy()) |
| .append(lineSep) |
| .append("maxColumnsInIndex: ") |
| .append(meta.getMaxColumnsInIndex()) |
| .append(lineSep) |
| .append("maxColumnsInOrderBy: ") |
| .append(meta.getMaxColumnsInOrderBy()) |
| .append(lineSep) |
| .append("maxColumnsInSelect: ") |
| .append(meta.getMaxColumnsInSelect()) |
| .append(lineSep) |
| .append("maxColumnsInTable: ") |
| .append(meta.getMaxColumnsInTable()) |
| .append(lineSep) |
| .append("maxConnections: ") |
| .append(meta.getMaxConnections()) |
| .append(lineSep) |
| .append("maxCursorNameLength: ") |
| .append(meta.getMaxCursorNameLength()) |
| .append(lineSep) |
| .append("maxIndexLength: ") |
| .append(meta.getMaxIndexLength()) |
| .append(lineSep) |
| .append("maxProcedureNameLength: ") |
| .append(meta.getMaxProcedureNameLength()) |
| .append(lineSep) |
| .append("maxRowSize: ") |
| .append(meta.getMaxRowSize()) |
| .append(lineSep) |
| .append("maxSchemaNameLength: ") |
| .append(meta.getMaxSchemaNameLength()) |
| .append(lineSep) |
| .append("maxStatementLength: ") |
| .append(meta.getMaxStatementLength()) |
| .append(lineSep) |
| .append("maxStatements: ") |
| .append(meta.getMaxStatements()) |
| .append(lineSep) |
| .append("maxTableNameLength: ") |
| .append(meta.getMaxTableNameLength()) |
| .append(lineSep) |
| .append("maxTablesInSelect: ") |
| .append(meta.getMaxTablesInSelect()) |
| .append(lineSep) |
| .append("maxUserNameLength: ") |
| .append(meta.getMaxUserNameLength()) |
| .append(lineSep) |
| .append("isCatalogAtStart: ") |
| .append(meta.isCatalogAtStart()) |
| .append(lineSep) |
| .append("isReadOnly: ") |
| .append(meta.isReadOnly()) |
| .append(lineSep) |
| .append("nullPlusNonNullIsNull: ") |
| .append(meta.nullPlusNonNullIsNull()) |
| .append(lineSep) |
| .append("nullsAreSortedAtEnd: ") |
| .append(meta.nullsAreSortedAtEnd()) |
| .append(lineSep) |
| .append("nullsAreSortedAtStart: ") |
| .append(meta.nullsAreSortedAtStart()) |
| .append(lineSep) |
| .append("nullsAreSortedHigh: ") |
| .append(meta.nullsAreSortedHigh()) |
| .append(lineSep) |
| .append("nullsAreSortedLow: ") |
| .append(meta.nullsAreSortedLow()) |
| .append(lineSep) |
| .append("storesLowerCaseIdentifiers: ") |
| .append(meta.storesLowerCaseIdentifiers()) |
| .append(lineSep) |
| .append("storesLowerCaseQuotedIdentifiers: ") |
| .append(meta.storesLowerCaseQuotedIdentifiers()) |
| .append(lineSep) |
| .append("storesMixedCaseIdentifiers: ") |
| .append(meta.storesMixedCaseIdentifiers()) |
| .append(lineSep) |
| .append("storesMixedCaseQuotedIdentifiers: ") |
| .append(meta.storesMixedCaseQuotedIdentifiers()) |
| .append(lineSep) |
| .append("storesUpperCaseIdentifiers: ") |
| .append(meta.storesUpperCaseIdentifiers()) |
| .append(lineSep) |
| .append("storesUpperCaseQuotedIdentifiers: ") |
| .append(meta.storesUpperCaseQuotedIdentifiers()) |
| .append(lineSep) |
| .append("supportsAlterTableWithAddColumn: ") |
| .append(meta.supportsAlterTableWithAddColumn()) |
| .append(lineSep) |
| .append("supportsAlterTableWithDropColumn: ") |
| .append(meta.supportsAlterTableWithDropColumn()) |
| .append(lineSep) |
| .append("supportsANSI92EntryLevelSQL: ") |
| .append(meta.supportsANSI92EntryLevelSQL()) |
| .append(lineSep) |
| .append("supportsANSI92FullSQL: ") |
| .append(meta.supportsANSI92FullSQL()) |
| .append(lineSep) |
| .append("supportsANSI92IntermediateSQL: ") |
| .append(meta.supportsANSI92IntermediateSQL()) |
| .append(lineSep) |
| .append("supportsCatalogsInDataManipulation: ") |
| .append(meta.supportsCatalogsInDataManipulation()) |
| .append(lineSep) |
| .append("supportsCatalogsInIndexDefinitions: ") |
| .append(meta.supportsCatalogsInIndexDefinitions()) |
| .append(lineSep) |
| .append("supportsCatalogsInPrivilegeDefinitions: ") |
| .append(meta.supportsCatalogsInPrivilegeDefinitions()) |
| .append(lineSep) |
| .append("supportsCatalogsInProcedureCalls: ") |
| .append(meta.supportsCatalogsInProcedureCalls()) |
| .append(lineSep) |
| .append("supportsCatalogsInTableDefinitions: ") |
| .append(meta.supportsCatalogsInTableDefinitions()) |
| .append(lineSep) |
| .append("supportsColumnAliasing: ") |
| .append(meta.supportsColumnAliasing()) |
| .append(lineSep) |
| .append("supportsConvert: ") |
| .append(meta.supportsConvert()) |
| .append(lineSep) |
| .append("supportsCoreSQLGrammar: ") |
| .append(meta.supportsCoreSQLGrammar()) |
| .append(lineSep) |
| .append("supportsCorrelatedSubqueries: ") |
| .append(meta.supportsCorrelatedSubqueries()) |
| .append(lineSep) |
| .append( |
| "supportsDataDefinitionAndDataManipulationTransactions: ") |
| .append(meta. |
| supportsDataDefinitionAndDataManipulationTransactions()) |
| .append(lineSep) |
| .append("supportsDataManipulationTransactionsOnly: ") |
| .append(meta.supportsDataManipulationTransactionsOnly()) |
| .append(lineSep) |
| .append("supportsDifferentTableCorrelationNames: ") |
| .append(meta.supportsDifferentTableCorrelationNames()) |
| .append(lineSep) |
| .append("supportsExpressionsInOrderBy: ") |
| .append(meta.supportsExpressionsInOrderBy()) |
| .append(lineSep) |
| .append("supportsExtendedSQLGrammar: ") |
| .append(meta.supportsExtendedSQLGrammar()) |
| .append(lineSep) |
| .append("supportsFullOuterJoins: ") |
| .append(meta.supportsFullOuterJoins()) |
| .append(lineSep) |
| .append("supportsGroupBy: ") |
| .append(meta.supportsGroupBy()) |
| .append(lineSep) |
| .append("supportsGroupByBeyondSelect: ") |
| .append(meta.supportsGroupByBeyondSelect()) |
| .append(lineSep) |
| .append("supportsGroupByUnrelated: ") |
| .append(meta.supportsGroupByUnrelated()) |
| .append(lineSep) |
| .append("supportsIntegrityEnhancementFacility: ") |
| .append(meta.supportsIntegrityEnhancementFacility()) |
| .append(lineSep) |
| .append("supportsLikeEscapeClause: ") |
| .append(meta.supportsLikeEscapeClause()) |
| .append(lineSep) |
| .append("supportsLimitedOuterJoins: ") |
| .append(meta.supportsLimitedOuterJoins()) |
| .append(lineSep) |
| .append("supportsMinimumSQLGrammar: ") |
| .append(meta.supportsMinimumSQLGrammar()) |
| .append(lineSep) |
| .append("supportsMixedCaseIdentifiers: ") |
| .append(meta.supportsMixedCaseIdentifiers()) |
| .append(lineSep) |
| .append("supportsMixedCaseQuotedIdentifiers: ") |
| .append(meta.supportsMixedCaseQuotedIdentifiers()) |
| .append(lineSep) |
| .append("supportsMultipleResultSets: ") |
| .append(meta.supportsMultipleResultSets()) |
| .append(lineSep) |
| .append("supportsMultipleTransactions: ") |
| .append(meta.supportsMultipleTransactions()) |
| .append(lineSep) |
| .append("supportsNonNullableColumns: ") |
| .append(meta.supportsNonNullableColumns()) |
| .append(lineSep) |
| .append("supportsOpenCursorsAcrossCommit: ") |
| .append(meta.supportsOpenCursorsAcrossCommit()) |
| .append(lineSep) |
| .append("supportsOpenCursorsAcrossRollback: ") |
| .append(meta.supportsOpenCursorsAcrossRollback()) |
| .append(lineSep) |
| .append("supportsOpenStatementsAcrossCommit: ") |
| .append(meta.supportsOpenStatementsAcrossCommit()) |
| .append(lineSep) |
| .append("supportsOpenStatementsAcrossRollback: ") |
| .append(meta.supportsOpenStatementsAcrossRollback()) |
| .append(lineSep) |
| .append("supportsOrderByUnrelated: ") |
| .append(meta.supportsOrderByUnrelated()) |
| .append(lineSep) |
| .append("supportsOuterJoins: ") |
| .append(meta.supportsOuterJoins()) |
| .append(lineSep) |
| .append("supportsPositionedDelete: ") |
| .append(meta.supportsPositionedDelete()) |
| .append(lineSep) |
| .append("supportsPositionedUpdate: ") |
| .append(meta.supportsPositionedUpdate()) |
| .append(lineSep) |
| .append("supportsSchemasInDataManipulation: ") |
| .append(meta.supportsSchemasInDataManipulation()) |
| .append(lineSep) |
| .append("supportsSchemasInIndexDefinitions: ") |
| .append(meta.supportsSchemasInIndexDefinitions()) |
| .append(lineSep) |
| .append("supportsSchemasInPrivilegeDefinitions: ") |
| .append(meta.supportsSchemasInPrivilegeDefinitions()) |
| .append(lineSep) |
| .append("supportsSchemasInProcedureCalls: ") |
| .append(meta.supportsSchemasInProcedureCalls()) |
| .append(lineSep) |
| .append("supportsSchemasInTableDefinitions: ") |
| .append(meta.supportsSchemasInTableDefinitions()) |
| .append(lineSep) |
| .append("supportsSelectForUpdate: ") |
| .append(meta.supportsSelectForUpdate()) |
| .append(lineSep) |
| .append("supportsStoredProcedures: ") |
| .append(meta.supportsStoredProcedures()) |
| .append(lineSep) |
| .append("supportsSubqueriesInComparisons: ") |
| .append(meta.supportsSubqueriesInComparisons()) |
| .append(lineSep) |
| .append("supportsSubqueriesInExists: ") |
| .append(meta.supportsSubqueriesInExists()) |
| .append(lineSep) |
| .append("supportsSubqueriesInIns: ") |
| .append(meta.supportsSubqueriesInIns()) |
| .append(lineSep) |
| .append("supportsSubqueriesInQuantifieds: ") |
| .append(meta.supportsSubqueriesInQuantifieds()) |
| .append(lineSep) |
| .append("supportsTableCorrelationNames: ") |
| .append(meta.supportsTableCorrelationNames()) |
| .append(lineSep) |
| .append("supportsTransactions: ") |
| .append(meta.supportsTransactions()) |
| .append(lineSep) |
| .append("supportsUnion: ") |
| .append(meta.supportsUnion()) |
| .append(lineSep) |
| .append("supportsUnionAll: ") |
| .append(meta.supportsUnionAll()) |
| .append(lineSep) |
| .append("usesLocalFilePerTable: ") |
| .append(meta.usesLocalFilePerTable()) |
| .append(lineSep) |
| .append("usesLocalFiles: ") |
| .append(meta.usesLocalFiles()) |
| .append(lineSep) |
| .append("allProceduresAreCallable: ") |
| .append(meta.allProceduresAreCallable()) |
| .append(lineSep) |
| .append("allTablesAreSelectable: ") |
| .append(meta.allTablesAreSelectable()) |
| .append(lineSep) |
| .append("dataDefinitionCausesTransactionCommit: ") |
| .append(meta.dataDefinitionCausesTransactionCommit()) |
| .append(lineSep) |
| .append("dataDefinitionIgnoredInTransactions: ") |
| .append(meta.dataDefinitionIgnoredInTransactions()) |
| .append(lineSep) |
| .append("doesMaxRowSizeIncludeBlobs: ") |
| .append(meta.doesMaxRowSizeIncludeBlobs()) |
| .append(lineSep) |
| .append("supportsBatchUpdates: ") |
| .append(meta.supportsBatchUpdates()); |
| } catch (Throwable t) { |
| // maybe abstract method error for jdbc 3 metadata method, or |
| // other error |
| buf.append(lineSep).append("Caught throwable: ").append(t); |
| } |
| |
| return buf.toString(); |
| } |
| } |