| @@ -0,0 +1,142 @@ | ||
| /* | ||
| * Hibernate, Relational Persistence for Idiomatic Java | ||
| * | ||
| * Copyright (c) 2012, Red Hat Inc. or third-party contributors as | ||
| * indicated by the @author tags or express copyright attribution | ||
| * statements applied by the authors. All third-party contributions are | ||
| * distributed under license by Red Hat Inc. | ||
| * | ||
| * This copyrighted material is made available to anyone wishing to use, modify, | ||
| * copy, or redistribute it subject to the terms and conditions of the GNU | ||
| * Lesser General Public License, as published by the Free Software Foundation. | ||
| * | ||
| * This program is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License | ||
| * for more details. | ||
| * | ||
| * You should have received a copy of the GNU Lesser General Public License | ||
| * along with this distribution; if not, write to: | ||
| * Free Software Foundation, Inc. | ||
| * 51 Franklin Street, Fifth Floor | ||
| * Boston, MA 02110-1301 USA | ||
| */ | ||
| package org.hibernate.service.jdbc.env.internal; | ||
|
|
||
| import org.hibernate.service.jdbc.env.spi.ExtractedDatabaseMetaData; | ||
| import org.hibernate.service.jdbc.env.spi.JdbcEnvironment; | ||
| import org.hibernate.service.jdbc.env.spi.SQLStateType; | ||
|
|
||
| /** | ||
| * Standard implementation of ExtractedDatabaseMetaData | ||
| * | ||
| * @author Steve Ebersole | ||
| */ | ||
| public class ExtractedDatabaseMetaDataImpl implements ExtractedDatabaseMetaData { | ||
| private final JdbcEnvironment jdbcEnvironment; | ||
|
|
||
| private final boolean supportsRefCursors; | ||
| private final boolean supportsNamedParameters; | ||
| private final boolean supportsScrollableResults; | ||
| private final boolean supportsGetGeneratedKeys; | ||
| private final boolean supportsBatchUpdates; | ||
| private final boolean supportsDataDefinitionInTransaction; | ||
| private final boolean doesDataDefinitionCauseTransactionCommit; | ||
| private final SQLStateType sqlStateType; | ||
| private final boolean lobLocatorUpdateCopy; | ||
|
|
||
| /** | ||
| * Form used when {@link java.sql.DatabaseMetaData} is not available. | ||
| * | ||
| * @param jdbcEnvironment The JDBC environment containing this metadata. | ||
| */ | ||
| public ExtractedDatabaseMetaDataImpl(JdbcEnvironment jdbcEnvironment) { | ||
| this.jdbcEnvironment = jdbcEnvironment; | ||
|
|
||
| // if possible, set values that will allow things to still work.... | ||
| this.supportsRefCursors = false; // Java 8 feature, safest to say not. | ||
| this.supportsNamedParameters = false; | ||
| this.supportsScrollableResults = true; | ||
| this.supportsGetGeneratedKeys = false; | ||
| this.supportsBatchUpdates = true; | ||
| this.sqlStateType = SQLStateType.UNKNOWN; | ||
| this.lobLocatorUpdateCopy = true; | ||
|
|
||
| // ugh my favorites... | ||
| this.supportsDataDefinitionInTransaction = false; | ||
| this.doesDataDefinitionCauseTransactionCommit = false; | ||
| } | ||
|
|
||
| public ExtractedDatabaseMetaDataImpl( | ||
| JdbcEnvironmentImpl jdbcEnvironment, | ||
| boolean supportsRefCursors, | ||
| boolean supportsNamedParameters, | ||
| boolean supportsScrollableResults, | ||
| boolean supportsGetGeneratedKeys, | ||
| boolean supportsBatchUpdates, | ||
| boolean supportsDataDefinitionInTransaction, | ||
| boolean doesDataDefinitionCauseTransactionCommit, | ||
| SQLStateType sqlStateType, | ||
| boolean lobLocatorUpdateCopy) { | ||
| this.jdbcEnvironment = jdbcEnvironment; | ||
| this.supportsRefCursors = supportsRefCursors; | ||
| this.supportsNamedParameters = supportsNamedParameters; | ||
| this.supportsScrollableResults = supportsScrollableResults; | ||
| this.supportsGetGeneratedKeys = supportsGetGeneratedKeys; | ||
| this.supportsBatchUpdates = supportsBatchUpdates; | ||
| this.supportsDataDefinitionInTransaction = supportsDataDefinitionInTransaction; | ||
| this.doesDataDefinitionCauseTransactionCommit = doesDataDefinitionCauseTransactionCommit; | ||
| this.sqlStateType = sqlStateType; | ||
| this.lobLocatorUpdateCopy = lobLocatorUpdateCopy; | ||
| } | ||
|
|
||
| @Override | ||
| public JdbcEnvironment getJdbcEnvironment() { | ||
| return jdbcEnvironment; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean supportsRefCursors() { | ||
| return supportsRefCursors; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean supportsNamedParameters() { | ||
| return supportsNamedParameters; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean supportsScrollableResults() { | ||
| return supportsScrollableResults; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean supportsGetGeneratedKeys() { | ||
| return supportsGetGeneratedKeys; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean supportsBatchUpdates() { | ||
| return supportsBatchUpdates; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean supportsDataDefinitionInTransaction() { | ||
| return supportsDataDefinitionInTransaction; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean doesDataDefinitionCauseTransactionCommit() { | ||
| return doesDataDefinitionCauseTransactionCommit; | ||
| } | ||
|
|
||
| @Override | ||
| public SQLStateType getSqlStateType() { | ||
| return sqlStateType; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean doesLobLocatorUpdateCopy() { | ||
| return lobLocatorUpdateCopy; | ||
| } | ||
| } |
| @@ -0,0 +1,117 @@ | ||
| /* | ||
| * Hibernate, Relational Persistence for Idiomatic Java | ||
| * | ||
| * Copyright (c) 2012, Red Hat Inc. or third-party contributors as | ||
| * indicated by the @author tags or express copyright attribution | ||
| * statements applied by the authors. All third-party contributions are | ||
| * distributed under license by Red Hat Inc. | ||
| * | ||
| * This copyrighted material is made available to anyone wishing to use, modify, | ||
| * copy, or redistribute it subject to the terms and conditions of the GNU | ||
| * Lesser General Public License, as published by the Free Software Foundation. | ||
| * | ||
| * This program is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License | ||
| * for more details. | ||
| * | ||
| * You should have received a copy of the GNU Lesser General Public License | ||
| * along with this distribution; if not, write to: | ||
| * Free Software Foundation, Inc. | ||
| * 51 Franklin Street, Fifth Floor | ||
| * Boston, MA 02110-1301 USA | ||
| */ | ||
| package org.hibernate.service.jdbc.env.internal; | ||
|
|
||
| import java.util.Set; | ||
|
|
||
| import org.hibernate.dialect.Dialect; | ||
| import org.hibernate.engine.jdbc.internal.TypeInfo; | ||
| import org.hibernate.engine.jdbc.spi.SqlExceptionHelper; | ||
| import org.hibernate.metamodel.spi.relational.Identifier; | ||
| import org.hibernate.service.Service; | ||
| import org.hibernate.service.jdbc.env.spi.ExtractedDatabaseMetaData; | ||
| import org.hibernate.service.jdbc.env.spi.IdentifierHelper; | ||
| import org.hibernate.service.jdbc.env.spi.QualifiedObjectNameSupport; | ||
|
|
||
| /** | ||
| * Initial look at this concept we keep talking about with merging information from {@link java.sql.DatabaseMetaData} | ||
| * and {@link org.hibernate.dialect.Dialect} | ||
| * | ||
| * @author Steve Ebersole | ||
| */ | ||
| public interface JdbcEnvironment extends Service { | ||
| /** | ||
| * Get the dialect for this environment. | ||
| * | ||
| * @return The dialect. | ||
| */ | ||
| public Dialect getDialect(); | ||
|
|
||
| /** | ||
| * Access to the bits of information we pulled off the JDBC {@link java.sql.DatabaseMetaData} (that did not get | ||
| * "interpreted" into the helpers/delegates available here). | ||
| * | ||
| * @return The values extracted from JDBC DatabaseMetaData | ||
| */ | ||
| public ExtractedDatabaseMetaData getExtractedDatabaseMetaData(); | ||
|
|
||
| /** | ||
| * Get the current database catalog. Typically will come from either {@link java.sql.Connection#getCatalog()} | ||
| * or {@link org.hibernate.cfg.AvailableSettings#DEFAULT_CATALOG}. | ||
| * | ||
| * @return The current catalog. | ||
| */ | ||
| public Identifier getCurrentCatalog(); | ||
|
|
||
| /** | ||
| * Get the current database catalog. Typically will come from either | ||
| * {@link org.hibernate.service.jdbc.env.spi.SchemaNameResolver#resolveSchemaName(java.sql.Connection)} or | ||
| * {@link org.hibernate.cfg.AvailableSettings#DEFAULT_CATALOG}. | ||
| * | ||
| * @return The current schema | ||
| */ | ||
| public Identifier getCurrentSchema(); | ||
|
|
||
| /** | ||
| * Obtain support for reading and writing qualified object names. | ||
| * | ||
| * @return Qualified name support. | ||
| */ | ||
| public QualifiedObjectNameSupport getQualifiedObjectNameSupport(); | ||
|
|
||
| /** | ||
| * Obtain the helper for dealing with identifiers in this environment. | ||
| * | ||
| * @return The identifier helper. | ||
| */ | ||
| public IdentifierHelper getIdentifierHelper(); | ||
|
|
||
| /** | ||
| * Get the complete set of reserved words for this environment. These are significant because they represent | ||
| * the complete set of terms that MUST BE quoted if used as identifiers. This allows us to apply auto-quoting | ||
| * in the metamodel based on these terms. | ||
| * | ||
| * Note that the standard IdentifierHelper returned by {@link #getIdentifierHelper()} already accounts for | ||
| * auto-quoting :) yaay! | ||
| * | ||
| * @return Reserved words | ||
| */ | ||
| public Set<String> getReservedWords(); | ||
|
|
||
| /** | ||
| * Obtain the helper for dealing with JDBC {@link java.sql.SQLException} faults. | ||
| * | ||
| * @return This environment's helper. | ||
| */ | ||
| public SqlExceptionHelper getSqlExceptionHelper(); | ||
|
|
||
| /** | ||
| * Find type information for the type identified by the given "JDBC type code". | ||
| * | ||
| * @param jdbcTypeCode The JDBC type code. | ||
| * | ||
| * @return The corresponding type info. | ||
| */ | ||
| public TypeInfo getTypeInfoForJdbcCode(int jdbcTypeCode); | ||
| } |
| @@ -0,0 +1,294 @@ | ||
| /* | ||
| * Hibernate, Relational Persistence for Idiomatic Java | ||
| * | ||
| * Copyright (c) 2012, Red Hat Inc. or third-party contributors as | ||
| * indicated by the @author tags or express copyright attribution | ||
| * statements applied by the authors. All third-party contributions are | ||
| * distributed under license by Red Hat Inc. | ||
| * | ||
| * This copyrighted material is made available to anyone wishing to use, modify, | ||
| * copy, or redistribute it subject to the terms and conditions of the GNU | ||
| * Lesser General Public License, as published by the Free Software Foundation. | ||
| * | ||
| * This program is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License | ||
| * for more details. | ||
| * | ||
| * You should have received a copy of the GNU Lesser General Public License | ||
| * along with this distribution; if not, write to: | ||
| * Free Software Foundation, Inc. | ||
| * 51 Franklin Street, Fifth Floor | ||
| * Boston, MA 02110-1301 USA | ||
| */ | ||
| package org.hibernate.service.jdbc.env.internal; | ||
|
|
||
| import java.sql.DatabaseMetaData; | ||
| import java.sql.ResultSet; | ||
| import java.sql.SQLException; | ||
| import java.util.Arrays; | ||
| import java.util.HashSet; | ||
| import java.util.LinkedHashSet; | ||
| import java.util.Set; | ||
|
|
||
| import org.hibernate.cfg.AvailableSettings; | ||
| import org.hibernate.dialect.Dialect; | ||
| import org.hibernate.engine.jdbc.internal.TypeInfo; | ||
| import org.hibernate.engine.jdbc.internal.TypeInfoExtracter; | ||
| import org.hibernate.engine.jdbc.spi.SqlExceptionHelper; | ||
| import org.hibernate.exception.internal.SQLExceptionTypeDelegate; | ||
| import org.hibernate.exception.internal.SQLStateConversionDelegate; | ||
| import org.hibernate.exception.internal.StandardSQLExceptionConverter; | ||
| import org.hibernate.exception.spi.SQLExceptionConverter; | ||
| import org.hibernate.metamodel.spi.relational.Identifier; | ||
| import org.hibernate.service.classloading.spi.ClassLoaderService; | ||
| import org.hibernate.service.config.spi.ConfigurationService; | ||
| import org.hibernate.service.config.spi.StandardConverters; | ||
| import org.hibernate.service.jdbc.cursor.internal.StandardRefCursorSupport; | ||
| import org.hibernate.service.jdbc.env.spi.ExtractedDatabaseMetaData; | ||
| import org.hibernate.service.jdbc.env.spi.IdentifierHelper; | ||
| import org.hibernate.service.jdbc.env.spi.JdbcEnvironment; | ||
| import org.hibernate.service.jdbc.env.spi.LobCreatorBuilder; | ||
| import org.hibernate.service.jdbc.env.spi.QualifiedObjectNameSupport; | ||
| import org.hibernate.service.jdbc.env.spi.SQLStateType; | ||
| import org.hibernate.service.jdbc.env.spi.SchemaNameResolver; | ||
| import org.hibernate.service.jdbc.env.spi.StandardQualifiedObjectNameSupportImpl; | ||
| import org.hibernate.service.spi.ServiceRegistryImplementor; | ||
|
|
||
| /** | ||
| * @author Steve Ebersole | ||
| */ | ||
| public class JdbcEnvironmentImpl implements JdbcEnvironment { | ||
| private final ServiceRegistryImplementor serviceRegistry; | ||
| private final Dialect dialect; | ||
|
|
||
| private final SqlExceptionHelper sqlExceptionHelper; | ||
| private final ExtractedDatabaseMetaData extractedMetaDataSupport; | ||
| private final Set<String> reservedWords; | ||
| private final Identifier currentCatalog; | ||
| private final Identifier currentSchema; | ||
| private final IdentifierHelper identifierHelper; | ||
| private final QualifiedObjectNameSupport qualifiedObjectNameSupport; | ||
| private final LobCreatorBuilderImpl lobCreatorBuilder; | ||
| private final LinkedHashSet<TypeInfo> typeInfoSet = new LinkedHashSet<TypeInfo>(); | ||
|
|
||
| /** | ||
| * Constructor form used when the JDBC {@link DatabaseMetaData} is not available. | ||
| * | ||
| * @param serviceRegistry The service registry | ||
| * @param dialect The resolved dialect. | ||
| */ | ||
| public JdbcEnvironmentImpl(ServiceRegistryImplementor serviceRegistry, Dialect dialect) { | ||
| this.serviceRegistry = serviceRegistry; | ||
| this.dialect = dialect; | ||
|
|
||
| this.sqlExceptionHelper = buildSqlExceptionHelper( dialect ); | ||
| this.extractedMetaDataSupport = new ExtractedDatabaseMetaDataImpl( this ); | ||
|
|
||
| // make sure reserved-words, current-catalog and current-schema happen before the identifier-helper! | ||
| this.reservedWords = dialect.getKeywords(); | ||
| this.currentCatalog = Identifier.toIdentifier( | ||
| serviceRegistry.getService( ConfigurationService.class ) | ||
| .getSetting( AvailableSettings.DEFAULT_CATALOG, StandardConverters.STRING ) | ||
| ); | ||
| this.currentSchema = Identifier.toIdentifier( | ||
| serviceRegistry.getService( ConfigurationService.class ) | ||
| .getSetting( AvailableSettings.DEFAULT_SCHEMA, StandardConverters.STRING ) | ||
| ); | ||
|
|
||
| // a simple temporary impl that works on H2 | ||
| this.identifierHelper = new NormalizingIdentifierHelperImpl( | ||
| this, | ||
| true, // storesMixedCaseQuotedIdentifiers | ||
| false, // storesLowerCaseQuotedIdentifiers | ||
| false, // storesUpperCaseQuotedIdentifiers | ||
| true, // storesUpperCaseIdentifiers | ||
| false // storesLowerCaseIdentifiers | ||
| ); | ||
|
|
||
| // again, a simple temporary impl that works on H2 | ||
| this.qualifiedObjectNameSupport = new StandardQualifiedObjectNameSupportImpl( | ||
| ".", | ||
| true, | ||
| dialect.openQuote(), | ||
| dialect.closeQuote() | ||
| ); | ||
|
|
||
| this.lobCreatorBuilder = LobCreatorBuilderImpl.makeLobCreatorBuilder(); | ||
| } | ||
|
|
||
| public JdbcEnvironmentImpl(ServiceRegistryImplementor serviceRegistry, Dialect dialect, DatabaseMetaData dbmd) throws SQLException { | ||
| this.serviceRegistry = serviceRegistry; | ||
| this.dialect = dialect; | ||
|
|
||
| this.sqlExceptionHelper = buildSqlExceptionHelper( dialect ); | ||
|
|
||
| this.extractedMetaDataSupport = new ExtractedDatabaseMetaDataImpl( | ||
| this, | ||
| StandardRefCursorSupport.supportsRefCursors( dbmd ), | ||
| dbmd.supportsNamedParameters(), | ||
| dbmd.supportsResultSetType( ResultSet.TYPE_SCROLL_INSENSITIVE ), | ||
| dbmd.supportsGetGeneratedKeys(), | ||
| dbmd.supportsBatchUpdates(), | ||
| !dbmd.dataDefinitionIgnoredInTransactions(), | ||
| dbmd.dataDefinitionCausesTransactionCommit(), | ||
| parseSQLStateType( dbmd.getSQLStateType() ), | ||
| dbmd.locatorsUpdateCopy() | ||
| ); | ||
|
|
||
| // make sure reserved-words happen before the identifier-helper! | ||
| this.reservedWords = buildMergedReservedWords( dialect, dbmd ); | ||
|
|
||
| this.identifierHelper = new NormalizingIdentifierHelperImpl( | ||
| this, | ||
| dbmd.storesMixedCaseQuotedIdentifiers(), | ||
| dbmd.storesLowerCaseQuotedIdentifiers(), | ||
| dbmd.storesUpperCaseQuotedIdentifiers(), | ||
| dbmd.storesUpperCaseIdentifiers(), | ||
| dbmd.storesLowerCaseIdentifiers() | ||
| ); | ||
|
|
||
| // and that current-catalog and current-schema happen after it | ||
| this.currentCatalog = determineCurrentCatalog( dbmd ); | ||
| this.currentSchema = determineCurrentSchema( dbmd ); | ||
|
|
||
| this.qualifiedObjectNameSupport = new StandardQualifiedObjectNameSupportImpl( | ||
| dbmd.getCatalogSeparator(), | ||
| dbmd.isCatalogAtStart(), | ||
| dialect.openQuote(), | ||
| dialect.closeQuote() | ||
| ); | ||
|
|
||
| this.typeInfoSet.addAll( TypeInfoExtracter.extractTypeInfo( dbmd ) ); | ||
|
|
||
| this.lobCreatorBuilder = LobCreatorBuilderImpl.makeLobCreatorBuilder( | ||
| serviceRegistry.getService( ConfigurationService.class ).getSettings(), | ||
| dbmd.getConnection() | ||
| ); | ||
| } | ||
|
|
||
| private SQLStateType parseSQLStateType(int sqlStateType) { | ||
| switch ( sqlStateType ) { | ||
| case DatabaseMetaData.sqlStateSQL99 : { | ||
| return SQLStateType.SQL99; | ||
| } | ||
| case DatabaseMetaData.sqlStateXOpen : { | ||
| return SQLStateType.XOpen; | ||
| } | ||
| default : { | ||
| return SQLStateType.UNKNOWN; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @SuppressWarnings("deprecation") | ||
| private SqlExceptionHelper buildSqlExceptionHelper(Dialect dialect) { | ||
| SQLExceptionConverter sqlExceptionConverter = dialect.buildSQLExceptionConverter(); | ||
| if ( sqlExceptionConverter == null ) { | ||
| final StandardSQLExceptionConverter converter = new StandardSQLExceptionConverter(); | ||
| sqlExceptionConverter = converter; | ||
| converter.addDelegate( dialect.buildSQLExceptionConversionDelegate() ); | ||
| converter.addDelegate( new SQLExceptionTypeDelegate( dialect ) ); | ||
| converter.addDelegate( new SQLStateConversionDelegate( dialect ) ); | ||
| } | ||
| return new SqlExceptionHelper( sqlExceptionConverter ); | ||
| } | ||
|
|
||
| private Identifier determineCurrentCatalog(DatabaseMetaData dbmd) throws SQLException { | ||
| String currentCatalogName = dbmd.getConnection().getCatalog(); | ||
| if ( currentCatalogName != null ) { | ||
| // intentionally using fromMetaDataObjectName rather than fromMetaDataCatalogName !!! | ||
| return identifierHelper.fromMetaDataObjectName( currentCatalogName ); | ||
| } | ||
| else { | ||
| currentCatalogName = serviceRegistry.getService( ConfigurationService.class ) | ||
| .getSetting( AvailableSettings.DEFAULT_CATALOG, StandardConverters.STRING ); | ||
| return Identifier.toIdentifier( currentCatalogName ); | ||
| } | ||
| } | ||
|
|
||
| private Identifier determineCurrentSchema(DatabaseMetaData dbmd) throws SQLException { | ||
| String currentSchemaName = locateSchemaNameResolver().resolveSchemaName( dbmd.getConnection() ); | ||
| if ( currentSchemaName != null ) { | ||
| // intentionally using fromMetaDataObjectName rather than fromMetaDataSchemaName !!! | ||
| return identifierHelper.fromMetaDataObjectName( currentSchemaName ); | ||
| } | ||
| else { | ||
| currentSchemaName = serviceRegistry.getService( ConfigurationService.class ) | ||
| .getSetting( AvailableSettings.DEFAULT_SCHEMA, StandardConverters.STRING ); | ||
| return Identifier.toIdentifier( currentSchemaName ); | ||
| } | ||
| } | ||
|
|
||
| private SchemaNameResolver locateSchemaNameResolver() { | ||
| final Object setting = serviceRegistry.getService( ConfigurationService.class ) | ||
| .getSettings() | ||
| .get( AvailableSettings.SCHEMA_NAME_RESOLVER ); | ||
| return serviceRegistry.getService( ClassLoaderService.class ) | ||
| .getStrategyInstanceResolver() | ||
| .resolveDefaultableStrategyInstance( setting, SchemaNameResolver.class, TemporarySchemaNameResolver.INSTANCE ); | ||
| } | ||
|
|
||
| private Set<String> buildMergedReservedWords(Dialect dialect, DatabaseMetaData dbmd) throws SQLException { | ||
| Set<String> reservedWords = new HashSet<String>(); | ||
| reservedWords.addAll( dialect.getKeywords() ); | ||
| // todo : do we need to explicitly handle SQL:2003 keywords? | ||
| reservedWords.addAll( Arrays.asList( dbmd.getSQLKeywords().split( "," ) ) ); | ||
| return reservedWords; | ||
| } | ||
|
|
||
| @Override | ||
| public Dialect getDialect() { | ||
| return dialect; | ||
| } | ||
|
|
||
| @Override | ||
| public ExtractedDatabaseMetaData getExtractedDatabaseMetaData() { | ||
| return extractedMetaDataSupport; | ||
| } | ||
|
|
||
| @Override | ||
| public Identifier getCurrentCatalog() { | ||
| return currentCatalog; | ||
| } | ||
|
|
||
| @Override | ||
| public Identifier getCurrentSchema() { | ||
| return currentSchema; | ||
| } | ||
|
|
||
| @Override | ||
| public QualifiedObjectNameSupport getQualifiedObjectNameSupport() { | ||
| return qualifiedObjectNameSupport; | ||
| } | ||
|
|
||
| @Override | ||
| public IdentifierHelper getIdentifierHelper() { | ||
| return identifierHelper; | ||
| } | ||
|
|
||
| @Override | ||
| public Set<String> getReservedWords() { | ||
| return reservedWords; | ||
| } | ||
|
|
||
| @Override | ||
| public SqlExceptionHelper getSqlExceptionHelper() { | ||
| return sqlExceptionHelper; | ||
| } | ||
|
|
||
| @Override | ||
| public LobCreatorBuilder getLobCreatorBuilder() { | ||
| return lobCreatorBuilder; | ||
| } | ||
|
|
||
| @Override | ||
| public TypeInfo getTypeInfoForJdbcCode(int jdbcTypeCode) { | ||
| for ( TypeInfo typeInfo : typeInfoSet ) { | ||
| if ( typeInfo.getJdbcTypeCode() == jdbcTypeCode ) { | ||
| return typeInfo; | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
| } |
| @@ -0,0 +1,186 @@ | ||
| /* | ||
| * Hibernate, Relational Persistence for Idiomatic Java | ||
| * | ||
| * Copyright (c) 2012, Red Hat Inc. or third-party contributors as | ||
| * indicated by the @author tags or express copyright attribution | ||
| * statements applied by the authors. All third-party contributions are | ||
| * distributed under license by Red Hat Inc. | ||
| * | ||
| * This copyrighted material is made available to anyone wishing to use, modify, | ||
| * copy, or redistribute it subject to the terms and conditions of the GNU | ||
| * Lesser General Public License, as published by the Free Software Foundation. | ||
| * | ||
| * This program is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License | ||
| * for more details. | ||
| * | ||
| * You should have received a copy of the GNU Lesser General Public License | ||
| * along with this distribution; if not, write to: | ||
| * Free Software Foundation, Inc. | ||
| * 51 Franklin Street, Fifth Floor | ||
| * Boston, MA 02110-1301 USA | ||
| */ | ||
| package org.hibernate.service.jdbc.env.internal; | ||
|
|
||
| import java.sql.Connection; | ||
| import java.sql.DatabaseMetaData; | ||
| import java.sql.SQLException; | ||
| import java.util.Map; | ||
|
|
||
| import org.jboss.logging.Logger; | ||
|
|
||
| import org.hibernate.MultiTenancyStrategy; | ||
| import org.hibernate.internal.CoreMessageLogger; | ||
| import org.hibernate.internal.util.config.ConfigurationHelper; | ||
| import org.hibernate.service.jdbc.connections.internal.UserSuppliedConnectionException; | ||
| import org.hibernate.service.jdbc.connections.spi.ConnectionProvider; | ||
| import org.hibernate.service.jdbc.connections.spi.JdbcConnectionAccess; | ||
| import org.hibernate.service.jdbc.connections.spi.MultiTenantConnectionProvider; | ||
| import org.hibernate.service.jdbc.dialect.spi.DialectFactory; | ||
| import org.hibernate.service.jdbc.env.spi.JdbcEnvironment; | ||
| import org.hibernate.service.spi.BasicServiceInitiator; | ||
| import org.hibernate.service.spi.ServiceRegistryImplementor; | ||
|
|
||
| /** | ||
| * @author Steve Ebersole | ||
| */ | ||
| public class JdbcEnvironmentInitiator implements BasicServiceInitiator<JdbcEnvironment> { | ||
| private static final CoreMessageLogger log = Logger.getMessageLogger( | ||
| CoreMessageLogger.class, | ||
| JdbcEnvironmentInitiator.class.getName() | ||
| ); | ||
|
|
||
| public static final JdbcEnvironmentInitiator INSTANCE = new JdbcEnvironmentInitiator(); | ||
|
|
||
| @Override | ||
| public Class<JdbcEnvironment> getServiceInitiated() { | ||
| return JdbcEnvironment.class; | ||
| } | ||
|
|
||
| @Override | ||
| public JdbcEnvironment initiateService(Map configurationValues, ServiceRegistryImplementor registry) { | ||
| final DialectFactory dialectFactory = registry.getService( DialectFactory.class ); | ||
|
|
||
| boolean useJdbcMetadata = ConfigurationHelper.getBoolean( | ||
| "hibernate.temp.use_jdbc_metadata_defaults", | ||
| configurationValues, | ||
| true | ||
| ); | ||
|
|
||
| if ( useJdbcMetadata ) { | ||
| final JdbcConnectionAccess jdbcConnectionAccess = buildJdbcConnectionAccess( configurationValues, registry ); | ||
| try { | ||
| final Connection connection = jdbcConnectionAccess.obtainConnection(); | ||
| try { | ||
| final DatabaseMetaData dbmd = connection.getMetaData(); | ||
| if ( log.isDebugEnabled() ) { | ||
| log.debugf( | ||
| "Database ->\n" | ||
| + " name : %s\n" | ||
| + " version : %s\n" | ||
| + " major : %s\n" | ||
| + " minor : %s", | ||
| dbmd.getDatabaseProductName(), | ||
| dbmd.getDatabaseProductVersion(), | ||
| dbmd.getDatabaseMajorVersion(), | ||
| dbmd.getDatabaseMinorVersion() | ||
| ); | ||
| log.debugf( | ||
| "Driver ->\n" | ||
| + " name : %s\n" | ||
| + " version : %s\n" | ||
| + " major : %s\n" | ||
| + " minor : %s", | ||
| dbmd.getDriverName(), | ||
| dbmd.getDriverVersion(), | ||
| dbmd.getDriverMajorVersion(), | ||
| dbmd.getDriverMinorVersion() | ||
| ); | ||
| log.debugf( "JDBC version : %s.%s", dbmd.getJDBCMajorVersion(), dbmd.getJDBCMinorVersion() ); | ||
| } | ||
|
|
||
| return new JdbcEnvironmentImpl( | ||
| registry, | ||
| dialectFactory.buildDialect( configurationValues, connection ), | ||
| dbmd | ||
| ); | ||
| } | ||
| catch (SQLException e) { | ||
| log.unableToObtainConnectionMetadata( e.getMessage() ); | ||
| } | ||
| finally { | ||
| try { | ||
| jdbcConnectionAccess.releaseConnection( connection ); | ||
| } | ||
| catch (SQLException ignore) { | ||
| } | ||
| } | ||
| } | ||
| catch (Exception e) { | ||
| log.unableToObtainConnectionToQueryMetadata( e.getMessage() ); | ||
| } | ||
| } | ||
|
|
||
| // if we get here, either we were asked to not use JDBC metadata or accessing the JDBC metadata failed. | ||
| return new JdbcEnvironmentImpl( registry, dialectFactory.buildDialect( configurationValues, null ) ); | ||
| } | ||
|
|
||
| private JdbcConnectionAccess buildJdbcConnectionAccess(Map configValues, ServiceRegistryImplementor registry) { | ||
| final MultiTenancyStrategy multiTenancyStrategy = MultiTenancyStrategy.determineMultiTenancyStrategy( configValues ); | ||
| if ( MultiTenancyStrategy.NONE == multiTenancyStrategy ) { | ||
| ConnectionProvider connectionProvider = registry.getService( ConnectionProvider.class ); | ||
| return new ConnectionProviderJdbcConnectionAccess( connectionProvider ); | ||
| } | ||
| else { | ||
| final MultiTenantConnectionProvider multiTenantConnectionProvider = registry.getService( MultiTenantConnectionProvider.class ); | ||
| return new MultiTenantConnectionProviderJdbcConnectionAccess( multiTenantConnectionProvider ); | ||
| } | ||
| } | ||
|
|
||
| private static class ConnectionProviderJdbcConnectionAccess implements JdbcConnectionAccess { | ||
| private final ConnectionProvider connectionProvider; | ||
|
|
||
| public ConnectionProviderJdbcConnectionAccess(ConnectionProvider connectionProvider) { | ||
| this.connectionProvider = connectionProvider; | ||
| } | ||
|
|
||
| @Override | ||
| public Connection obtainConnection() throws SQLException { | ||
| return connectionProvider.getConnection(); | ||
| } | ||
|
|
||
| @Override | ||
| public void releaseConnection(Connection connection) throws SQLException { | ||
| connectionProvider.closeConnection( connection ); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean supportsAggressiveRelease() { | ||
| return connectionProvider.supportsAggressiveRelease(); | ||
| } | ||
| } | ||
|
|
||
| private static class MultiTenantConnectionProviderJdbcConnectionAccess implements JdbcConnectionAccess { | ||
| private final MultiTenantConnectionProvider connectionProvider; | ||
|
|
||
| public MultiTenantConnectionProviderJdbcConnectionAccess(MultiTenantConnectionProvider connectionProvider) { | ||
| this.connectionProvider = connectionProvider; | ||
| } | ||
|
|
||
| @Override | ||
| public Connection obtainConnection() throws SQLException { | ||
| return connectionProvider.getAnyConnection(); | ||
| } | ||
|
|
||
| @Override | ||
| public void releaseConnection(Connection connection) throws SQLException { | ||
| connectionProvider.releaseAnyConnection( connection ); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean supportsAggressiveRelease() { | ||
| return connectionProvider.supportsAggressiveRelease(); | ||
| } | ||
| } | ||
| } |
| @@ -0,0 +1 @@ | ||
| package org.hibernate.service.jdbc.env; |
| @@ -21,7 +21,7 @@ | ||
| * 51 Franklin Street, Fifth Floor | ||
| * Boston, MA 02110-1301 USA | ||
| */ | ||
| package org.hibernate.service.jdbc.env.spi; | ||
|
|
||
| import org.hibernate.metamodel.spi.relational.Identifier; | ||
|
|
||
| @@ -0,0 +1,121 @@ | ||
| /* | ||
| * Hibernate, Relational Persistence for Idiomatic Java | ||
| * | ||
| * Copyright (c) 2012, Red Hat Inc. or third-party contributors as | ||
| * indicated by the @author tags or express copyright attribution | ||
| * statements applied by the authors. All third-party contributions are | ||
| * distributed under license by Red Hat Inc. | ||
| * | ||
| * This copyrighted material is made available to anyone wishing to use, modify, | ||
| * copy, or redistribute it subject to the terms and conditions of the GNU | ||
| * Lesser General Public License, as published by the Free Software Foundation. | ||
| * | ||
| * This program is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License | ||
| * for more details. | ||
| * | ||
| * You should have received a copy of the GNU Lesser General Public License | ||
| * along with this distribution; if not, write to: | ||
| * Free Software Foundation, Inc. | ||
| * 51 Franklin Street, Fifth Floor | ||
| * Boston, MA 02110-1301 USA | ||
| */ | ||
| package org.hibernate.service.jdbc.env.spi; | ||
|
|
||
| import java.util.Set; | ||
|
|
||
| import org.hibernate.dialect.Dialect; | ||
| import org.hibernate.engine.jdbc.internal.TypeInfo; | ||
| import org.hibernate.engine.jdbc.spi.SqlExceptionHelper; | ||
| import org.hibernate.metamodel.spi.relational.Identifier; | ||
| import org.hibernate.service.Service; | ||
|
|
||
| /** | ||
| * Initial look at this concept we keep talking about with merging information from {@link java.sql.DatabaseMetaData} | ||
| * and {@link org.hibernate.dialect.Dialect} | ||
| * | ||
| * @author Steve Ebersole | ||
| */ | ||
| public interface JdbcEnvironment extends Service { | ||
| /** | ||
| * Get the dialect for this environment. | ||
| * | ||
| * @return The dialect. | ||
| */ | ||
| public Dialect getDialect(); | ||
|
|
||
| /** | ||
| * Access to the bits of information we pulled off the JDBC {@link java.sql.DatabaseMetaData} (that did not get | ||
| * "interpreted" into the helpers/delegates available here). | ||
| * | ||
| * @return The values extracted from JDBC DatabaseMetaData | ||
| */ | ||
| public ExtractedDatabaseMetaData getExtractedDatabaseMetaData(); | ||
|
|
||
| /** | ||
| * Get the current database catalog. Typically will come from either {@link java.sql.Connection#getCatalog()} | ||
| * or {@link org.hibernate.cfg.AvailableSettings#DEFAULT_CATALOG}. | ||
| * | ||
| * @return The current catalog. | ||
| */ | ||
| public Identifier getCurrentCatalog(); | ||
|
|
||
| /** | ||
| * Get the current database catalog. Typically will come from either | ||
| * {@link SchemaNameResolver#resolveSchemaName(java.sql.Connection)} or | ||
| * {@link org.hibernate.cfg.AvailableSettings#DEFAULT_CATALOG}. | ||
| * | ||
| * @return The current schema | ||
| */ | ||
| public Identifier getCurrentSchema(); | ||
|
|
||
| /** | ||
| * Obtain support for reading and writing qualified object names. | ||
| * | ||
| * @return Qualified name support. | ||
| */ | ||
| public QualifiedObjectNameSupport getQualifiedObjectNameSupport(); | ||
|
|
||
| /** | ||
| * Obtain the helper for dealing with identifiers in this environment. | ||
| * | ||
| * @return The identifier helper. | ||
| */ | ||
| public IdentifierHelper getIdentifierHelper(); | ||
|
|
||
| /** | ||
| * Get the complete set of reserved words for this environment. These are significant because they represent | ||
| * the complete set of terms that MUST BE quoted if used as identifiers. This allows us to apply auto-quoting | ||
| * in the metamodel based on these terms. | ||
| * | ||
| * Note that the standard IdentifierHelper returned by {@link #getIdentifierHelper()} already accounts for | ||
| * auto-quoting :) yaay! | ||
| * | ||
| * @return Reserved words | ||
| */ | ||
| public Set<String> getReservedWords(); | ||
|
|
||
| /** | ||
| * Obtain the helper for dealing with JDBC {@link java.sql.SQLException} faults. | ||
| * | ||
| * @return This environment's helper. | ||
| */ | ||
| public SqlExceptionHelper getSqlExceptionHelper(); | ||
|
|
||
| /** | ||
| * Retrieve the delegate for building {@link org.hibernate.engine.jdbc.LobCreator} instances. | ||
| * | ||
| * @return The LobCreator builder. | ||
| */ | ||
| public LobCreatorBuilder getLobCreatorBuilder(); | ||
|
|
||
| /** | ||
| * Find type information for the type identified by the given "JDBC type code". | ||
| * | ||
| * @param jdbcTypeCode The JDBC type code. | ||
| * | ||
| * @return The corresponding type info. | ||
| */ | ||
| public TypeInfo getTypeInfoForJdbcCode(int jdbcTypeCode); | ||
| } |
| @@ -21,7 +21,7 @@ | ||
| * 51 Franklin Street, Fifth Floor | ||
| * Boston, MA 02110-1301 USA | ||
| */ | ||
| package org.hibernate.service.jdbc.env.spi; | ||
|
|
||
| import java.sql.Connection; | ||
| import java.sql.SQLException; | ||
| @@ -0,0 +1,92 @@ | ||
| /* | ||
| * Hibernate, Relational Persistence for Idiomatic Java | ||
| * | ||
| * Copyright (c) 2012, Red Hat Inc. or third-party contributors as | ||
| * indicated by the @author tags or express copyright attribution | ||
| * statements applied by the authors. All third-party contributions are | ||
| * distributed under license by Red Hat Inc. | ||
| * | ||
| * This copyrighted material is made available to anyone wishing to use, modify, | ||
| * copy, or redistribute it subject to the terms and conditions of the GNU | ||
| * Lesser General Public License, as published by the Free Software Foundation. | ||
| * | ||
| * This program is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License | ||
| * for more details. | ||
| * | ||
| * You should have received a copy of the GNU Lesser General Public License | ||
| * along with this distribution; if not, write to: | ||
| * Free Software Foundation, Inc. | ||
| * 51 Franklin Street, Fifth Floor | ||
| * Boston, MA 02110-1301 USA | ||
| */ | ||
| package org.hibernate.service.schema.spi; | ||
|
|
||
| import org.hibernate.TruthValue; | ||
| import org.hibernate.metamodel.spi.relational.Identifier; | ||
|
|
||
| /** | ||
| * Provides access to information about existing table columns | ||
| * | ||
| * @author Christoph Sturm | ||
| * @author Steve Ebersole | ||
| */ | ||
| public interface ColumnInformation { | ||
| /** | ||
| * Access to the containing table. | ||
| * | ||
| * @return The containing table information | ||
| */ | ||
| public TableInformation getContainingTableInformation(); | ||
|
|
||
| /** | ||
| * The simple (not qualified) column name. | ||
| * | ||
| * @return The column simple identifier. | ||
| */ | ||
| public Identifier getColumnIdentifier(); | ||
|
|
||
| /** | ||
| * Is the column nullable. The database is allowed to report unknown, hence the use of TruthValue | ||
| * | ||
| * @return nullability. | ||
| */ | ||
| public TruthValue getNullable(); | ||
|
|
||
| /** | ||
| * The JDBC type-code. | ||
| * | ||
| * @return JDBC type-code | ||
| */ | ||
| public int getTypeCode(); | ||
|
|
||
| /** | ||
| * The database specific type name. | ||
| * | ||
| * @return Type name | ||
| */ | ||
| public String getTypeName(); | ||
|
|
||
| // todo : wrap these in org.hibernate.metamodel.spi.relational.Size ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
|
|
||
| /** | ||
| * The column size (length). | ||
| * | ||
| * @return The column length | ||
| */ | ||
| public int getColumnSize(); | ||
|
|
||
| /** | ||
| * The precision, for numeric types | ||
| * | ||
| * @return The numeric precision | ||
| */ | ||
| public int getDecimalDigits(); | ||
| } | ||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
| @@ -0,0 +1,47 @@ | ||
| /* | ||
| * Hibernate, Relational Persistence for Idiomatic Java | ||
| * | ||
| * Copyright (c) 2012, Red Hat Inc. or third-party contributors as | ||
| * indicated by the @author tags or express copyright attribution | ||
| * statements applied by the authors. All third-party contributions are | ||
| * distributed under license by Red Hat Inc. | ||
| * | ||
| * This copyrighted material is made available to anyone wishing to use, modify, | ||
| * copy, or redistribute it subject to the terms and conditions of the GNU | ||
| * Lesser General Public License, as published by the Free Software Foundation. | ||
| * | ||
| * This program is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License | ||
| * for more details. | ||
| * | ||
| * You should have received a copy of the GNU Lesser General Public License | ||
| * along with this distribution; if not, write to: | ||
| * Free Software Foundation, Inc. | ||
| * 51 Franklin Street, Fifth Floor | ||
| * Boston, MA 02110-1301 USA | ||
| */ | ||
| package org.hibernate.service.schema.spi; | ||
|
|
||
| import java.sql.DatabaseMetaData; | ||
| import java.sql.SQLException; | ||
|
|
||
| /** | ||
| * Because JDBC (at least up to an including Java 7, JDBC 4) still does not have support for obtaining information | ||
| * about sequences from DatabaseMetaData. | ||
| * | ||
| * @author Steve Ebersole | ||
| */ | ||
| public interface SequenceInformationExtractor { | ||
| /** | ||
| * Get the information about sequences. | ||
| * | ||
| * @param databaseMetaData The JDBC DatabaseMetadata | ||
| * | ||
| * @return The extracted information about existing sequences. | ||
| * | ||
| * @throws SQLException Don't bother handling SQLExceptions (unless you want to), we will deal with them in the | ||
| * caller. | ||
| */ | ||
| public Iterable<SequenceInformation> extractMetadata(DatabaseMetaData databaseMetaData) throws SQLException; | ||
| } |
| @@ -0,0 +1,75 @@ | ||
| /* | ||
| * Hibernate, Relational Persistence for Idiomatic Java | ||
| * | ||
| * Copyright (c) 2012, Red Hat Inc. or third-party contributors as | ||
| * indicated by the @author tags or express copyright attribution | ||
| * statements applied by the authors. All third-party contributions are | ||
| * distributed under license by Red Hat Inc. | ||
| * | ||
| * This copyrighted material is made available to anyone wishing to use, modify, | ||
| * copy, or redistribute it subject to the terms and conditions of the GNU | ||
| * Lesser General Public License, as published by the Free Software Foundation. | ||
| * | ||
| * This program is distributed in the hope that it will be useful, | ||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
| * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License | ||
| * for more details. | ||
| * | ||
| * You should have received a copy of the GNU Lesser General Public License | ||
| * along with this distribution; if not, write to: | ||
| * Free Software Foundation, Inc. | ||
| * 51 Franklin Street, Fifth Floor | ||
| * Boston, MA 02110-1301 USA | ||
| */ | ||
| package org.hibernate.service.schema.spi; | ||
|
|
||
| import org.hibernate.metamodel.spi.relational.ForeignKey; | ||
| import org.hibernate.metamodel.spi.relational.Identifier; | ||
| import org.hibernate.metamodel.spi.relational.ObjectName; | ||
| import org.hibernate.tool.hbm2ddl.IndexMetadata; | ||
|
|
||
| /** | ||
| * Provides access to information about existing tables in the database | ||
| * | ||
| * @author Christoph Sturm | ||
| * @author Max Rydahl Andersen | ||
| * @author Steve Ebersole | ||
| */ | ||
| public interface TableInformation { | ||
| /** | ||
| * Get the qualified name of the table. | ||
| * | ||
| * @return The qualified table name | ||
| */ | ||
| public ObjectName getName(); | ||
|
|
||
| /** | ||
| * Retrieve the named ColumnInformation | ||
| * | ||
| * @param columnIdentifier The column identifier (simple name) | ||
| * | ||
| * @return The matching column information. May return {@code null} | ||
| */ | ||
| public ColumnInformation getColumnInformation(Identifier columnIdentifier); | ||
|
|
||
| /** | ||
| * Retrieve the named ForeignKeyInformation | ||
| * | ||
| * @param keyName The foreign key identifier (simple name) | ||
| * | ||
| * @return The matching foreign key information. May return {@code null} | ||
| */ | ||
| public ForeignKeyInformation getForeignKeyInformation(Identifier keyName); | ||
|
|
||
| /** | ||
| * Obtain an iterable over all the table's defined foreign keys. | ||
| * | ||
| * @return The iterable. | ||
| */ | ||
| public Iterable<ForeignKeyInformation> getForeignKeyInformations(); | ||
|
|
||
| /** | ||
| * todo : create an IndexInformation... | ||
| */ | ||
| public IndexMetadata getIndexMetadata(Identifier indexName); | ||
| } |