HHH-9820 - Handle JDBC drivers that do not properly report metadata regarding case of identifiers
This commit is contained in:
parent
d58ef6950c
commit
a51f300253
|
@ -11,6 +11,7 @@ import java.io.OutputStream;
|
|||
import java.sql.Blob;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Clob;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.NClob;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
@ -53,6 +54,8 @@ import org.hibernate.dialect.unique.UniqueDelegate;
|
|||
import org.hibernate.engine.jdbc.LobCreator;
|
||||
import org.hibernate.engine.jdbc.env.internal.DefaultSchemaNameResolver;
|
||||
import org.hibernate.engine.jdbc.env.spi.AnsiSqlKeywords;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
|
||||
import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport;
|
||||
import org.hibernate.engine.jdbc.env.spi.SchemaNameResolver;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
|
@ -1846,7 +1849,8 @@ public abstract class Dialect implements ConversionContext {
|
|||
}
|
||||
|
||||
/**
|
||||
* @deprecated See {@link #determineKeywordsForAutoQuoting} instead
|
||||
* @deprecated These are only ever used (if at all) from the code that handles identifier quoting. So
|
||||
* see {@link #buildIdentifierHelper} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public Set<String> getKeywords() {
|
||||
|
@ -1854,29 +1858,46 @@ public abstract class Dialect implements ConversionContext {
|
|||
}
|
||||
|
||||
/**
|
||||
* Hook into auto-quoting of identifiers that are deemed to be keywords. By default we
|
||||
* return all of the following here:<ul>
|
||||
* <li>all keywords as defined by ANSI SQL:2003 specification</li>
|
||||
* <li>all "extra" keywords reported by the JDBC driver </li>
|
||||
* <li>all Dialect-registered "extra" keywords</li>
|
||||
* Build the IdentifierHelper indicated by this Dialect for handling identifier conversions.
|
||||
* Returning {@code null} is allowed and indicates that Hibernate should fallback to building a
|
||||
* "standard" helper. In the fallback path, any changes made to the IdentifierHelperBuilder
|
||||
* during this call will still be incorporated into the built IdentifierHelper.
|
||||
* <p/>
|
||||
* The incoming builder will have the following set:<ul>
|
||||
* <li>{@link IdentifierHelperBuilder#isGloballyQuoteIdentifiers()}</li>
|
||||
* <li>{@link IdentifierHelperBuilder#getUnquotedCaseStrategy()} - initialized to UPPER</li>
|
||||
* <li>{@link IdentifierHelperBuilder#getQuotedCaseStrategy()} - initialized to MIXED</li>
|
||||
* </ul>
|
||||
* <p/>
|
||||
* Subclasses are free to override this as they see fit. Just be aware that overriding this
|
||||
* does affect what identifiers are auto-quoted based on being seen as a keyword.
|
||||
* <p/>
|
||||
* NOTE: The code that ultimately consumes these and uses them stores them in a case-insensitive
|
||||
* Set, so case here does not matter.
|
||||
* By default Hibernate will do the following:<ul>
|
||||
* <li>Call {@link IdentifierHelperBuilder#applyIdentifierCasing(DatabaseMetaData)}
|
||||
* <li>Call {@link IdentifierHelperBuilder#applyReservedWords(DatabaseMetaData)}
|
||||
* <li>Applies {@link AnsiSqlKeywords#sql2003()} as reserved words</li>
|
||||
* <li>Applies the {#link #sqlKeywords} collected here as reserved words</li>
|
||||
* <li>Applies the Dialect's NameQualifierSupport, if it defines one</li>
|
||||
* </ul>
|
||||
*
|
||||
* @see org.hibernate.engine.jdbc.env.spi.AnsiSqlKeywords#sql2003()
|
||||
* @see java.sql.DatabaseMetaData#getSQLKeywords()
|
||||
* @see #registerKeyword
|
||||
* @param builder A semi-configured IdentifierHelper builder.
|
||||
* @param dbMetaData Access to the metadata returned from the driver if needed and if available. WARNING: may be {@code null}
|
||||
*
|
||||
* @return The IdentifierHelper instance to use, or {@code null} to indicate Hibernate should use its fallback path
|
||||
*
|
||||
* @throws SQLException Accessing the DatabaseMetaData can throw it. Just re-throw and Hibernate will handle.
|
||||
*
|
||||
* @see #getNameQualifierSupport()
|
||||
*/
|
||||
public Set<String> determineKeywordsForAutoQuoting(Set<String> databaseMetadataReportedKeywords) {
|
||||
final Set<String> keywords = new HashSet<String>();
|
||||
keywords.addAll( AnsiSqlKeywords.INSTANCE.sql2003() );
|
||||
keywords.addAll( databaseMetadataReportedKeywords );
|
||||
keywords.addAll( sqlKeywords );
|
||||
return keywords;
|
||||
public IdentifierHelper buildIdentifierHelper(
|
||||
IdentifierHelperBuilder builder,
|
||||
DatabaseMetaData dbMetaData) throws SQLException {
|
||||
builder.applyIdentifierCasing( dbMetaData );
|
||||
|
||||
builder.applyReservedWords( dbMetaData );
|
||||
builder.applyReservedWords( AnsiSqlKeywords.INSTANCE.sql2003() );
|
||||
builder.applyReservedWords( sqlKeywords );
|
||||
|
||||
builder.setNameQualifierSupport( getNameQualifierSupport() );
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,11 +9,9 @@ package org.hibernate.engine.jdbc.env.internal;
|
|||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.hibernate.boot.model.naming.Identifier;
|
||||
import org.hibernate.boot.registry.selector.spi.StrategySelector;
|
||||
|
@ -22,7 +20,9 @@ import org.hibernate.dialect.Dialect;
|
|||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.engine.config.spi.StandardConverters;
|
||||
import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
|
||||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||
import org.hibernate.engine.jdbc.env.spi.LobCreatorBuilder;
|
||||
import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport;
|
||||
|
@ -36,10 +36,14 @@ import org.hibernate.exception.internal.StandardSQLExceptionConverter;
|
|||
import org.hibernate.service.ServiceRegistry;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JdbcEnvironmentImpl implements JdbcEnvironment {
|
||||
private static final Logger log = Logger.getLogger( JdbcEnvironmentImpl.class );
|
||||
|
||||
private final Dialect dialect;
|
||||
|
||||
private final SqlExceptionHelper sqlExceptionHelper;
|
||||
|
@ -51,7 +55,6 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment {
|
|||
private final LobCreatorBuilderImpl lobCreatorBuilder;
|
||||
|
||||
private final LinkedHashSet<TypeInfo> typeInfoSet = new LinkedHashSet<TypeInfo>();
|
||||
private final Set<String> reservedWords = new TreeSet<String>( String.CASE_INSENSITIVE_ORDER );
|
||||
|
||||
/**
|
||||
* Constructor form used when the JDBC {@link java.sql.DatabaseMetaData} is not available.
|
||||
|
@ -62,6 +65,8 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment {
|
|||
public JdbcEnvironmentImpl(ServiceRegistryImplementor serviceRegistry, Dialect dialect) {
|
||||
this.dialect = dialect;
|
||||
|
||||
final ConfigurationService cfgService = serviceRegistry.getService( ConfigurationService.class );
|
||||
|
||||
NameQualifierSupport nameQualifierSupport = dialect.getNameQualifierSupport();
|
||||
if ( nameQualifierSupport == null ) {
|
||||
// assume both catalogs and schemas are supported
|
||||
|
@ -71,39 +76,43 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment {
|
|||
this.sqlExceptionHelper = buildSqlExceptionHelper( dialect );
|
||||
this.extractedMetaDataSupport = new ExtractedDatabaseMetaDataImpl.Builder( this ).build();
|
||||
|
||||
reservedWords.addAll( dialect.determineKeywordsForAutoQuoting( Collections.<String>emptySet() ) );
|
||||
final IdentifierHelperBuilder identifierHelperBuilder = IdentifierHelperBuilder.from( this );
|
||||
identifierHelperBuilder.setGloballyQuoteIdentifiers( globalQuoting( cfgService ) );
|
||||
identifierHelperBuilder.setNameQualifierSupport( nameQualifierSupport );
|
||||
|
||||
final boolean globallyQuoteIdentifiers = serviceRegistry.getService( ConfigurationService.class )
|
||||
.getSetting( AvailableSettings.GLOBALLY_QUOTED_IDENTIFIERS, StandardConverters.BOOLEAN, false );
|
||||
|
||||
// a simple impl that works on H2
|
||||
this.identifierHelper = new NormalizingIdentifierHelperImpl(
|
||||
this,
|
||||
nameQualifierSupport,
|
||||
globallyQuoteIdentifiers,
|
||||
true, // storesMixedCaseQuotedIdentifiers
|
||||
false, // storesLowerCaseQuotedIdentifiers
|
||||
false, // storesUpperCaseQuotedIdentifiers
|
||||
false, // storesMixedCaseIdentifiers
|
||||
true, // storesUpperCaseIdentifiers
|
||||
false // storesLowerCaseIdentifiers
|
||||
);
|
||||
IdentifierHelper identifierHelper = null;
|
||||
try {
|
||||
identifierHelper = dialect.buildIdentifierHelper( identifierHelperBuilder, null );
|
||||
}
|
||||
catch (SQLException sqle) {
|
||||
// should never ever happen
|
||||
log.debug( "There was a problem accessing DatabaseMetaData in building the JdbcEnvironment", sqle );
|
||||
}
|
||||
if ( identifierHelper == null ) {
|
||||
identifierHelper = identifierHelperBuilder.build();
|
||||
}
|
||||
this.identifierHelper = identifierHelper;
|
||||
|
||||
this.currentCatalog = identifierHelper.toIdentifier(
|
||||
serviceRegistry.getService( ConfigurationService.class )
|
||||
.getSetting( AvailableSettings.DEFAULT_CATALOG, StandardConverters.STRING )
|
||||
cfgService.getSetting( AvailableSettings.DEFAULT_CATALOG, StandardConverters.STRING )
|
||||
);
|
||||
this.currentSchema = Identifier.toIdentifier(
|
||||
serviceRegistry.getService( ConfigurationService.class )
|
||||
.getSetting( AvailableSettings.DEFAULT_SCHEMA, StandardConverters.STRING )
|
||||
cfgService.getSetting( AvailableSettings.DEFAULT_SCHEMA, StandardConverters.STRING )
|
||||
);
|
||||
|
||||
// again, a simple impl that works on H2
|
||||
this.qualifiedObjectNameFormatter = new QualifiedObjectNameFormatterStandardImpl( nameQualifierSupport );
|
||||
|
||||
this.lobCreatorBuilder = LobCreatorBuilderImpl.makeLobCreatorBuilder();
|
||||
}
|
||||
|
||||
private static boolean globalQuoting(ConfigurationService cfgService) {
|
||||
return cfgService.getSetting(
|
||||
AvailableSettings.GLOBALLY_QUOTED_IDENTIFIERS,
|
||||
StandardConverters.BOOLEAN,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor form used from testing
|
||||
*
|
||||
|
@ -123,22 +132,20 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment {
|
|||
nameQualifierSupport = determineNameQualifierSupport( databaseMetaData );
|
||||
}
|
||||
|
||||
reservedWords.addAll( dialect.determineKeywordsForAutoQuoting( extractedMetaDataSupport.getExtraKeywords() ) );
|
||||
|
||||
final boolean globallyQuoteIdentifiers = false;
|
||||
|
||||
// a simple impl that works on H2
|
||||
this.identifierHelper = new NormalizingIdentifierHelperImpl(
|
||||
this,
|
||||
nameQualifierSupport,
|
||||
globallyQuoteIdentifiers,
|
||||
true, // storesMixedCaseQuotedIdentifiers
|
||||
false, // storesLowerCaseQuotedIdentifiers
|
||||
false, // storesUpperCaseQuotedIdentifiers
|
||||
false, // storesMixedCaseIdentifiers
|
||||
true, // storesUpperCaseIdentifiers
|
||||
false // storesLowerCaseIdentifiers
|
||||
);
|
||||
final IdentifierHelperBuilder identifierHelperBuilder = IdentifierHelperBuilder.from( this );
|
||||
identifierHelperBuilder.setNameQualifierSupport( nameQualifierSupport );
|
||||
IdentifierHelper identifierHelper = null;
|
||||
try {
|
||||
identifierHelper = dialect.buildIdentifierHelper( identifierHelperBuilder, databaseMetaData );
|
||||
}
|
||||
catch (SQLException sqle) {
|
||||
// should never ever happen
|
||||
log.debug( "There was a problem accessing DatabaseMetaData in building the JdbcEnvironment", sqle );
|
||||
}
|
||||
if ( identifierHelper == null ) {
|
||||
identifierHelper = identifierHelperBuilder.build();
|
||||
}
|
||||
this.identifierHelper = identifierHelper;
|
||||
|
||||
this.currentCatalog = null;
|
||||
this.currentSchema = null;
|
||||
|
@ -184,6 +191,8 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment {
|
|||
DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
this.dialect = dialect;
|
||||
|
||||
final ConfigurationService cfgService = serviceRegistry.getService( ConfigurationService.class );
|
||||
|
||||
this.sqlExceptionHelper = buildSqlExceptionHelper( dialect );
|
||||
|
||||
this.extractedMetaDataSupport = new ExtractedDatabaseMetaDataImpl.Builder( this )
|
||||
|
@ -196,22 +205,21 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment {
|
|||
nameQualifierSupport = determineNameQualifierSupport( databaseMetaData );
|
||||
}
|
||||
|
||||
reservedWords.addAll( dialect.determineKeywordsForAutoQuoting( extractedMetaDataSupport.getExtraKeywords() ) );
|
||||
|
||||
final boolean globallyQuoteIdentifiers = serviceRegistry.getService( ConfigurationService.class )
|
||||
.getSetting( AvailableSettings.GLOBALLY_QUOTED_IDENTIFIERS, StandardConverters.BOOLEAN, false );
|
||||
|
||||
this.identifierHelper = new NormalizingIdentifierHelperImpl(
|
||||
this,
|
||||
nameQualifierSupport,
|
||||
globallyQuoteIdentifiers,
|
||||
databaseMetaData.storesMixedCaseQuotedIdentifiers(),
|
||||
databaseMetaData.storesLowerCaseQuotedIdentifiers(),
|
||||
databaseMetaData.storesUpperCaseQuotedIdentifiers(),
|
||||
databaseMetaData.storesMixedCaseIdentifiers(),
|
||||
databaseMetaData.storesUpperCaseIdentifiers(),
|
||||
databaseMetaData.storesLowerCaseIdentifiers()
|
||||
);
|
||||
final IdentifierHelperBuilder identifierHelperBuilder = IdentifierHelperBuilder.from( this );
|
||||
identifierHelperBuilder.setGloballyQuoteIdentifiers( globalQuoting( cfgService ) );
|
||||
identifierHelperBuilder.setNameQualifierSupport( nameQualifierSupport );
|
||||
IdentifierHelper identifierHelper = null;
|
||||
try {
|
||||
identifierHelper = dialect.buildIdentifierHelper( identifierHelperBuilder, databaseMetaData );
|
||||
}
|
||||
catch (SQLException sqle) {
|
||||
// should never ever happen
|
||||
log.debug( "There was a problem accessing DatabaseMetaData in building the JdbcEnvironment", sqle );
|
||||
}
|
||||
if ( identifierHelper == null ) {
|
||||
identifierHelper = identifierHelperBuilder.build();
|
||||
}
|
||||
this.identifierHelper = identifierHelper;
|
||||
|
||||
// and that current-catalog and current-schema happen after it
|
||||
this.currentCatalog = identifierHelper.toIdentifier( extractedMetaDataSupport.getConnectionCatalogName() );
|
||||
|
@ -225,7 +233,7 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment {
|
|||
this.typeInfoSet.addAll( TypeInfo.extractTypeInfo( databaseMetaData ) );
|
||||
|
||||
this.lobCreatorBuilder = LobCreatorBuilderImpl.makeLobCreatorBuilder(
|
||||
serviceRegistry.getService( ConfigurationService.class ).getSettings(),
|
||||
cfgService.getSettings(),
|
||||
databaseMetaData.getConnection()
|
||||
);
|
||||
}
|
||||
|
@ -307,11 +315,6 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment {
|
|||
return identifierHelper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReservedWord(String word) {
|
||||
return reservedWords.contains( word );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlExceptionHelper getSqlExceptionHelper() {
|
||||
return sqlExceptionHelper;
|
||||
|
|
|
@ -7,8 +7,11 @@
|
|||
package org.hibernate.engine.jdbc.env.internal;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.hibernate.boot.model.naming.Identifier;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy;
|
||||
import org.hibernate.engine.jdbc.env.spi.IdentifierHelper;
|
||||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||
import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport;
|
||||
|
@ -25,59 +28,31 @@ public class NormalizingIdentifierHelperImpl implements IdentifierHelper {
|
|||
|
||||
private final NameQualifierSupport nameQualifierSupport;
|
||||
private final boolean globallyQuoteIdentifiers;
|
||||
|
||||
private final boolean storesMixedCaseQuotedIdentifiers;
|
||||
private final boolean storesLowerCaseQuotedIdentifiers;
|
||||
private final boolean storesUpperCaseQuotedIdentifiers;
|
||||
private final boolean storesMixedCaseIdentifiers;
|
||||
private final boolean storesUpperCaseIdentifiers;
|
||||
private final boolean storesLowerCaseIdentifiers;
|
||||
private final Set<String> reservedWords = new TreeSet<String>( String.CASE_INSENSITIVE_ORDER );
|
||||
private final IdentifierCaseStrategy unquotedCaseStrategy;
|
||||
private final IdentifierCaseStrategy quotedCaseStrategy;
|
||||
|
||||
public NormalizingIdentifierHelperImpl(
|
||||
JdbcEnvironment jdbcEnvironment,
|
||||
NameQualifierSupport nameQualifierSupport,
|
||||
boolean globallyQuoteIdentifiers,
|
||||
boolean storesMixedCaseQuotedIdentifiers,
|
||||
boolean storesLowerCaseQuotedIdentifiers,
|
||||
boolean storesUpperCaseQuotedIdentifiers,
|
||||
boolean storesMixedCaseIdentifiers,
|
||||
boolean storesUpperCaseIdentifiers,
|
||||
boolean storesLowerCaseIdentifiers) {
|
||||
Set<String> reservedWords,
|
||||
IdentifierCaseStrategy unquotedCaseStrategy,
|
||||
IdentifierCaseStrategy quotedCaseStrategy) {
|
||||
this.jdbcEnvironment = jdbcEnvironment;
|
||||
this.nameQualifierSupport = nameQualifierSupport;
|
||||
this.globallyQuoteIdentifiers = globallyQuoteIdentifiers;
|
||||
this.storesMixedCaseQuotedIdentifiers = storesMixedCaseQuotedIdentifiers;
|
||||
this.storesLowerCaseQuotedIdentifiers = storesLowerCaseQuotedIdentifiers;
|
||||
this.storesUpperCaseQuotedIdentifiers = storesUpperCaseQuotedIdentifiers;
|
||||
this.storesMixedCaseIdentifiers = storesMixedCaseIdentifiers;
|
||||
this.storesUpperCaseIdentifiers = storesUpperCaseIdentifiers;
|
||||
this.storesLowerCaseIdentifiers = storesLowerCaseIdentifiers;
|
||||
|
||||
if ( storesMixedCaseQuotedIdentifiers && storesLowerCaseQuotedIdentifiers && storesUpperCaseQuotedIdentifiers ) {
|
||||
log.warn( "JDBC Driver reports it stores quoted identifiers in mixed, upper and lower case" );
|
||||
}
|
||||
else if ( storesMixedCaseQuotedIdentifiers && storesUpperCaseQuotedIdentifiers ) {
|
||||
log.warn( "JDBC Driver reports it stores quoted identifiers in both mixed and upper case" );
|
||||
}
|
||||
else if ( storesMixedCaseQuotedIdentifiers && storesLowerCaseQuotedIdentifiers ) {
|
||||
log.warn( "JDBC Driver reports it stores quoted identifiers in both mixed and lower case" );
|
||||
}
|
||||
|
||||
if ( storesUpperCaseIdentifiers && storesLowerCaseIdentifiers ) {
|
||||
log.warn( "JDBC Driver reports it stores non-quoted identifiers in both upper and lower case" );
|
||||
}
|
||||
|
||||
if ( storesUpperCaseIdentifiers && storesUpperCaseQuotedIdentifiers ) {
|
||||
log.warn( "JDBC Driver reports it stores both quoted and non-quoted identifiers in upper case" );
|
||||
}
|
||||
|
||||
if ( storesLowerCaseIdentifiers && storesLowerCaseQuotedIdentifiers ) {
|
||||
log.warn( "JDBC Driver reports it stores both quoted and non-quoted identifiers in lower case" );
|
||||
if ( reservedWords != null ) {
|
||||
this.reservedWords.addAll( reservedWords );
|
||||
}
|
||||
this.unquotedCaseStrategy = unquotedCaseStrategy == null ? IdentifierCaseStrategy.UPPER : unquotedCaseStrategy;
|
||||
this.quotedCaseStrategy = quotedCaseStrategy == null ? IdentifierCaseStrategy.MIXED : quotedCaseStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Identifier normalizeQuoting(Identifier identifier) {
|
||||
log.tracef( "Normalizing identifier quoting [%s]", identifier );
|
||||
|
||||
if ( identifier == null ) {
|
||||
return null;
|
||||
}
|
||||
|
@ -87,10 +62,12 @@ public class NormalizingIdentifierHelperImpl implements IdentifierHelper {
|
|||
}
|
||||
|
||||
if ( globallyQuoteIdentifiers ) {
|
||||
log.tracef( "Forcing identifier [%s] to quoted for global quoting", identifier );
|
||||
return Identifier.toIdentifier( identifier.getText(), true );
|
||||
}
|
||||
|
||||
if ( jdbcEnvironment.isReservedWord( identifier.getText() ) ) {
|
||||
if ( isReservedWord( identifier.getText() ) ) {
|
||||
log.tracef( "Forcing identifier [%s] to quoted as recognized reserveed word", identifier );
|
||||
return Identifier.toIdentifier( identifier.getText(), true );
|
||||
}
|
||||
|
||||
|
@ -112,16 +89,18 @@ public class NormalizingIdentifierHelperImpl implements IdentifierHelper {
|
|||
return Identifier.toIdentifier( text, globallyQuoteIdentifiers );
|
||||
}
|
||||
|
||||
// In the DatabaseMetaData method params for catalog and schema name have the following meaning:
|
||||
// 1) <""> means to match things "without a catalog/schema"
|
||||
// 2) <null> means to not limit results based on this field
|
||||
//
|
||||
// todo : not sure how "without a catalog/schema" is interpreted. Current?
|
||||
@Override
|
||||
public boolean isReservedWord(String word) {
|
||||
return reservedWords.contains( word );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toMetaDataCatalogName(Identifier identifier) {
|
||||
log.tracef( "Normalizing identifier quoting for catalog name [%s]", identifier );
|
||||
|
||||
if ( !nameQualifierSupport.supportsCatalogs() ) {
|
||||
// null is used to tell DBMD to not limit results based on catalog.
|
||||
log.trace( "Environment does not support catalogs; returning null" );
|
||||
// null is used to tell DatabaseMetaData to not limit results based on catalog.
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -141,39 +120,48 @@ public class NormalizingIdentifierHelperImpl implements IdentifierHelper {
|
|||
}
|
||||
|
||||
if ( identifier.isQuoted() ) {
|
||||
if ( storesMixedCaseQuotedIdentifiers ) {
|
||||
return identifier.getText();
|
||||
}
|
||||
else if ( storesUpperCaseQuotedIdentifiers ) {
|
||||
return identifier.getText().toUpperCase( Locale.ENGLISH );
|
||||
}
|
||||
else if ( storesLowerCaseQuotedIdentifiers ) {
|
||||
return identifier.getText().toLowerCase( Locale.ENGLISH );
|
||||
}
|
||||
else {
|
||||
return identifier.getText();
|
||||
switch ( quotedCaseStrategy ) {
|
||||
case UPPER: {
|
||||
log.tracef( "Rendering quoted identifier [%s] in upper case for use in DatabaseMetaData", identifier );
|
||||
return identifier.getText().toUpperCase( Locale.ROOT );
|
||||
}
|
||||
case LOWER: {
|
||||
log.tracef( "Rendering quoted identifier [%s] in lower case for use in DatabaseMetaData", identifier );
|
||||
return identifier.getText().toLowerCase( Locale.ROOT );
|
||||
}
|
||||
default: {
|
||||
// default is mixed case
|
||||
log.tracef( "Rendering quoted identifier [%s] in mixed case for use in DatabaseMetaData", identifier );
|
||||
return identifier.getText();
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( storesMixedCaseIdentifiers ) {
|
||||
return identifier.getText();
|
||||
}
|
||||
else if ( storesUpperCaseIdentifiers ) {
|
||||
return identifier.getText().toUpperCase( Locale.ENGLISH );
|
||||
}
|
||||
else if ( storesLowerCaseIdentifiers ) {
|
||||
return identifier.getText().toLowerCase( Locale.ENGLISH );
|
||||
}
|
||||
else {
|
||||
return identifier.getText();
|
||||
switch ( unquotedCaseStrategy ) {
|
||||
case MIXED: {
|
||||
log.tracef( "Rendering unquoted identifier [%s] in mixed case for use in DatabaseMetaData", identifier );
|
||||
return identifier.getText();
|
||||
}
|
||||
case LOWER: {
|
||||
log.tracef( "Rendering unquoted identifier [%s] in lower case for use in DatabaseMetaData", identifier );
|
||||
return identifier.getText().toLowerCase( Locale.ROOT );
|
||||
}
|
||||
default: {
|
||||
// default is upper case
|
||||
log.tracef( "Rendering unquoted identifier [%s] in upper case for use in DatabaseMetaData", identifier );
|
||||
return identifier.getText().toUpperCase( Locale.ROOT );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toMetaDataSchemaName(Identifier identifier) {
|
||||
log.tracef( "Normalizing identifier quoting for schema name [%s]", identifier );
|
||||
|
||||
if ( !nameQualifierSupport.supportsSchemas() ) {
|
||||
// null is used to tell DBMD to not limit results based on schema.
|
||||
// null is used to tell DatabaseMetaData to not limit results based on schema.
|
||||
log.trace( "Environment does not support catalogs; returning null" );
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -189,6 +177,8 @@ public class NormalizingIdentifierHelperImpl implements IdentifierHelper {
|
|||
|
||||
@Override
|
||||
public String toMetaDataObjectName(Identifier identifier) {
|
||||
log.tracef( "Normalizing identifier quoting for object name [%s]", identifier );
|
||||
|
||||
if ( identifier == null ) {
|
||||
// if this method was called, the value is needed
|
||||
throw new IllegalArgumentException( "null was passed as an object name" );
|
||||
|
@ -211,32 +201,40 @@ public class NormalizingIdentifierHelperImpl implements IdentifierHelper {
|
|||
}
|
||||
|
||||
public Identifier toIdentifierFromMetaData(String text) {
|
||||
log.tracef( "Interpreting return value [%s] from DatabaseMetaData as identifier", text );
|
||||
|
||||
if ( globallyQuoteIdentifiers ) {
|
||||
log.trace( "Forcing DatabaseMetaData return value as quoted due to global quoting" );
|
||||
return Identifier.toIdentifier( text, true );
|
||||
}
|
||||
|
||||
if ( isReservedWord( text ) ) {
|
||||
// unequivocally it needs to be quoted...
|
||||
log.trace( "Forcing DatabaseMetaData return value as quoted as it was recognized as a reserved word" );
|
||||
return Identifier.toIdentifier( text, true );
|
||||
}
|
||||
|
||||
// lovely decipher of whether the incoming value represents a quoted identifier...
|
||||
final boolean isUpperCase = text.toUpperCase(Locale.ROOT).equals( text );
|
||||
final boolean isLowerCase = text.toLowerCase(Locale.ROOT).equals( text );
|
||||
final boolean isUpperCase = text.toUpperCase( Locale.ROOT ).equals( text );
|
||||
final boolean isLowerCase = text.toLowerCase( Locale.ROOT ).equals( text );
|
||||
final boolean isMixedCase = ! isLowerCase && ! isUpperCase;
|
||||
|
||||
if ( jdbcEnvironment.isReservedWord( text ) ) {
|
||||
// unequivocally it needs to be quoted...
|
||||
if ( quotedCaseStrategy == IdentifierCaseStrategy.MIXED && isMixedCase ) {
|
||||
log.trace( "Interpreting return value as quoted due to case strategy" );
|
||||
return Identifier.toIdentifier( text, true );
|
||||
}
|
||||
|
||||
if ( storesMixedCaseQuotedIdentifiers && isMixedCase ) {
|
||||
if ( quotedCaseStrategy == IdentifierCaseStrategy.LOWER && isLowerCase ) {
|
||||
log.trace( "Interpreting return value as quoted due to case strategy" );
|
||||
return Identifier.toIdentifier( text, true );
|
||||
}
|
||||
|
||||
if ( storesLowerCaseQuotedIdentifiers && isLowerCase ) {
|
||||
return Identifier.toIdentifier( text, true );
|
||||
}
|
||||
|
||||
if ( storesUpperCaseQuotedIdentifiers && isUpperCase ) {
|
||||
if ( quotedCaseStrategy == IdentifierCaseStrategy.UPPER && isUpperCase ) {
|
||||
log.trace( "Interpreting return value as quoted due to case strategy" );
|
||||
return Identifier.toIdentifier( text, true );
|
||||
}
|
||||
|
||||
log.trace( "Interpreting return value as unquoted due to case strategy" );
|
||||
return Identifier.toIdentifier( text );
|
||||
}
|
||||
|
||||
|
|
|
@ -25,21 +25,21 @@ public interface ExtractedDatabaseMetaData {
|
|||
*
|
||||
* @return The JDBC environment
|
||||
*/
|
||||
public JdbcEnvironment getJdbcEnvironment();
|
||||
JdbcEnvironment getJdbcEnvironment();
|
||||
|
||||
/**
|
||||
* Retrieve the name of the catalog in effect when we connected to the database.
|
||||
*
|
||||
* @return The catalog name
|
||||
*/
|
||||
public String getConnectionCatalogName();
|
||||
String getConnectionCatalogName();
|
||||
|
||||
/**
|
||||
* Retrieve the name of the schema in effect when we connected to the database.
|
||||
*
|
||||
* @return The schema name
|
||||
*/
|
||||
public String getConnectionSchemaName();
|
||||
String getConnectionSchemaName();
|
||||
|
||||
/**
|
||||
* Set of type info reported by the driver.
|
||||
|
@ -48,7 +48,7 @@ public interface ExtractedDatabaseMetaData {
|
|||
*
|
||||
* @see java.sql.DatabaseMetaData#getTypeInfo()
|
||||
*/
|
||||
public LinkedHashSet<TypeInfo> getTypeInfoSet();
|
||||
LinkedHashSet<TypeInfo> getTypeInfoSet();
|
||||
|
||||
/**
|
||||
* Get the list of extra keywords (beyond standard SQL92 keywords) reported by the driver.
|
||||
|
@ -57,7 +57,7 @@ public interface ExtractedDatabaseMetaData {
|
|||
*
|
||||
* @see java.sql.DatabaseMetaData#getSQLKeywords()
|
||||
*/
|
||||
public Set<String> getExtraKeywords();
|
||||
Set<String> getExtraKeywords();
|
||||
|
||||
/**
|
||||
* Does the driver report supporting named parameters?
|
||||
|
@ -65,7 +65,7 @@ public interface ExtractedDatabaseMetaData {
|
|||
* @return {@code true} indicates the driver reported true; {@code false} indicates the driver reported false
|
||||
* or that the driver could not be asked.
|
||||
*/
|
||||
public boolean supportsNamedParameters();
|
||||
boolean supportsNamedParameters();
|
||||
|
||||
/**
|
||||
* Does the driver report supporting REF_CURSORs?
|
||||
|
@ -73,7 +73,7 @@ public interface ExtractedDatabaseMetaData {
|
|||
* @return {@code true} indicates the driver reported true; {@code false} indicates the driver reported false
|
||||
* or that the driver could not be asked.
|
||||
*/
|
||||
public boolean supportsRefCursors();
|
||||
boolean supportsRefCursors();
|
||||
|
||||
/**
|
||||
* Did the driver report to supporting scrollable result sets?
|
||||
|
@ -82,7 +82,7 @@ public interface ExtractedDatabaseMetaData {
|
|||
*
|
||||
* @see java.sql.DatabaseMetaData#supportsResultSetType
|
||||
*/
|
||||
public boolean supportsScrollableResults();
|
||||
boolean supportsScrollableResults();
|
||||
|
||||
/**
|
||||
* Did the driver report to supporting retrieval of generated keys?
|
||||
|
@ -91,7 +91,7 @@ public interface ExtractedDatabaseMetaData {
|
|||
*
|
||||
* @see java.sql.DatabaseMetaData#supportsGetGeneratedKeys
|
||||
*/
|
||||
public boolean supportsGetGeneratedKeys();
|
||||
boolean supportsGetGeneratedKeys();
|
||||
|
||||
/**
|
||||
* Did the driver report to supporting batched updates?
|
||||
|
@ -100,7 +100,7 @@ public interface ExtractedDatabaseMetaData {
|
|||
*
|
||||
* @see java.sql.DatabaseMetaData#supportsBatchUpdates
|
||||
*/
|
||||
public boolean supportsBatchUpdates();
|
||||
boolean supportsBatchUpdates();
|
||||
|
||||
/**
|
||||
* Did the driver report to support performing DDL within transactions?
|
||||
|
@ -109,7 +109,7 @@ public interface ExtractedDatabaseMetaData {
|
|||
*
|
||||
* @see java.sql.DatabaseMetaData#dataDefinitionIgnoredInTransactions
|
||||
*/
|
||||
public boolean supportsDataDefinitionInTransaction();
|
||||
boolean supportsDataDefinitionInTransaction();
|
||||
|
||||
/**
|
||||
* Did the driver report to DDL statements performed within a transaction performing an implicit commit of the
|
||||
|
@ -120,7 +120,7 @@ public interface ExtractedDatabaseMetaData {
|
|||
*
|
||||
* @see java.sql.DatabaseMetaData#dataDefinitionCausesTransactionCommit()
|
||||
*/
|
||||
public boolean doesDataDefinitionCauseTransactionCommit();
|
||||
boolean doesDataDefinitionCauseTransactionCommit();
|
||||
|
||||
/**
|
||||
* Retrieve the type of codes the driver says it uses for {@code SQLState}. They might follow either
|
||||
|
@ -130,7 +130,7 @@ public interface ExtractedDatabaseMetaData {
|
|||
*
|
||||
* @see java.sql.DatabaseMetaData#getSQLStateType()
|
||||
*/
|
||||
public SQLStateType getSqlStateType();
|
||||
SQLStateType getSqlStateType();
|
||||
|
||||
/**
|
||||
* Did the driver report that updates to a LOB locator affect a copy of the LOB?
|
||||
|
@ -139,5 +139,5 @@ public interface ExtractedDatabaseMetaData {
|
|||
*
|
||||
* @see java.sql.DatabaseMetaData#locatorsUpdateCopy()
|
||||
*/
|
||||
public boolean doesLobLocatorUpdateCopy();
|
||||
boolean doesLobLocatorUpdateCopy();
|
||||
}
|
||||
|
|
36
hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/IdentifierCaseStrategy.java
vendored
Normal file
36
hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/IdentifierCaseStrategy.java
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.engine.jdbc.env.spi;
|
||||
|
||||
/**
|
||||
* An enumeration of the way DatabaseMetaData might store and return identifiers
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public enum IdentifierCaseStrategy {
|
||||
/**
|
||||
* The identifier is stored in mixed case.
|
||||
*
|
||||
* @see java.sql.DatabaseMetaData#storesMixedCaseIdentifiers()
|
||||
* @see java.sql.DatabaseMetaData#storesMixedCaseQuotedIdentifiers()
|
||||
*/
|
||||
MIXED,
|
||||
/**
|
||||
* The identifier is stored in upper case.
|
||||
*
|
||||
* @see java.sql.DatabaseMetaData#storesUpperCaseIdentifiers()
|
||||
* @see java.sql.DatabaseMetaData#storesUpperCaseQuotedIdentifiers()
|
||||
*/
|
||||
UPPER,
|
||||
/**
|
||||
* The identifier is stored in lower case.
|
||||
*
|
||||
* @see java.sql.DatabaseMetaData#storesLowerCaseIdentifiers()
|
||||
* @see java.sql.DatabaseMetaData#storesLowerCaseQuotedIdentifiers()
|
||||
*/
|
||||
LOWER
|
||||
}
|
|
@ -22,7 +22,7 @@ public interface IdentifierHelper {
|
|||
*
|
||||
* @return The quoting-normalized Identifier.
|
||||
*/
|
||||
public Identifier normalizeQuoting(Identifier identifier);
|
||||
Identifier normalizeQuoting(Identifier identifier);
|
||||
|
||||
/**
|
||||
* Generate an Identifier instance from its simple name as obtained from mapping
|
||||
|
@ -35,7 +35,7 @@ public interface IdentifierHelper {
|
|||
*
|
||||
* @return The identifier form of the name.
|
||||
*/
|
||||
public Identifier toIdentifier(String text);
|
||||
Identifier toIdentifier(String text);
|
||||
|
||||
/**
|
||||
* Generate an Identifier instance from its simple name as obtained from mapping
|
||||
|
@ -50,7 +50,7 @@ public interface IdentifierHelper {
|
|||
*
|
||||
* @return The identifier form of the name.
|
||||
*/
|
||||
public Identifier toIdentifier(String text, boolean quoted);
|
||||
Identifier toIdentifier(String text, boolean quoted);
|
||||
|
||||
/**
|
||||
* Needed to account for certain fields ({@link javax.persistence.Column#columnDefinition()} comes to mind)
|
||||
|
@ -61,7 +61,16 @@ public interface IdentifierHelper {
|
|||
*
|
||||
* @return The identifier form
|
||||
*/
|
||||
public Identifier applyGlobalQuoting(String text);
|
||||
Identifier applyGlobalQuoting(String text);
|
||||
|
||||
/**
|
||||
* Check whether the given word represents a reserved word.
|
||||
*
|
||||
* @param word The word to check
|
||||
*
|
||||
* @return {@code true} if the given word represents a reserved word; {@code false} otherwise.
|
||||
*/
|
||||
boolean isReservedWord(String word);
|
||||
|
||||
/**
|
||||
* Render the Identifier representation of a catalog name into the String form needed
|
||||
|
@ -71,7 +80,7 @@ public interface IdentifierHelper {
|
|||
*
|
||||
* @return The String representation of the given catalog name
|
||||
*/
|
||||
public String toMetaDataCatalogName(Identifier catalogIdentifier);
|
||||
String toMetaDataCatalogName(Identifier catalogIdentifier);
|
||||
|
||||
/**
|
||||
* Render the Identifier representation of a schema name into the String form needed
|
||||
|
@ -81,7 +90,7 @@ public interface IdentifierHelper {
|
|||
*
|
||||
* @return The String representation of the given schema name
|
||||
*/
|
||||
public String toMetaDataSchemaName(Identifier schemaIdentifier);
|
||||
String toMetaDataSchemaName(Identifier schemaIdentifier);
|
||||
|
||||
/**
|
||||
* Render the Identifier representation of an object name (table, sequence, etc) into the
|
||||
|
@ -91,7 +100,7 @@ public interface IdentifierHelper {
|
|||
*
|
||||
* @return The String representation of the given object name
|
||||
*/
|
||||
public String toMetaDataObjectName(Identifier identifier);
|
||||
String toMetaDataObjectName(Identifier identifier);
|
||||
|
||||
/**
|
||||
* Parse an Identifier representation from the String representation of a catalog name
|
||||
|
@ -101,7 +110,7 @@ public interface IdentifierHelper {
|
|||
*
|
||||
* @return The parsed Identifier representation of the given catalog name
|
||||
*/
|
||||
public Identifier fromMetaDataCatalogName(String catalogName);
|
||||
Identifier fromMetaDataCatalogName(String catalogName);
|
||||
|
||||
/**
|
||||
* Parse an Identifier representation from the String representation of a schema name
|
||||
|
@ -111,7 +120,7 @@ public interface IdentifierHelper {
|
|||
*
|
||||
* @return The parsed Identifier representation of the given schema name
|
||||
*/
|
||||
public Identifier fromMetaDataSchemaName(String schemaName);
|
||||
Identifier fromMetaDataSchemaName(String schemaName);
|
||||
|
||||
/**
|
||||
* Parse an Identifier representation from the String representation of an object name
|
||||
|
@ -121,5 +130,5 @@ public interface IdentifierHelper {
|
|||
*
|
||||
* @return The parsed Identifier representation of the given object name
|
||||
*/
|
||||
public Identifier fromMetaDataObjectName(String name);
|
||||
Identifier fromMetaDataObjectName(String name);
|
||||
}
|
||||
|
|
194
hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/IdentifierHelperBuilder.java
vendored
Normal file
194
hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/IdentifierHelperBuilder.java
vendored
Normal file
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.engine.jdbc.env.spi;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.hibernate.engine.jdbc.env.internal.NormalizingIdentifierHelperImpl;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* Builder for IdentifierHelper instances. Mainly here to allow progressive
|
||||
* building of the immutable (after instantiation) IdentifierHelper.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class IdentifierHelperBuilder {
|
||||
private static final Logger log = Logger.getLogger( IdentifierHelperBuilder.class );
|
||||
|
||||
private final JdbcEnvironment jdbcEnvironment;
|
||||
|
||||
private NameQualifierSupport nameQualifierSupport = NameQualifierSupport.BOTH;
|
||||
|
||||
private Set<String> reservedWords = new TreeSet<String>( String.CASE_INSENSITIVE_ORDER );
|
||||
private boolean globallyQuoteIdentifiers = false;
|
||||
private IdentifierCaseStrategy unquotedCaseStrategy = IdentifierCaseStrategy.UPPER;
|
||||
private IdentifierCaseStrategy quotedCaseStrategy = IdentifierCaseStrategy.MIXED;
|
||||
|
||||
public static IdentifierHelperBuilder from(JdbcEnvironment jdbcEnvironment) {
|
||||
return new IdentifierHelperBuilder( jdbcEnvironment );
|
||||
}
|
||||
|
||||
private IdentifierHelperBuilder(JdbcEnvironment jdbcEnvironment) {
|
||||
this.jdbcEnvironment = jdbcEnvironment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies any reserved words reported via {@link DatabaseMetaData#getSQLKeywords()}
|
||||
*
|
||||
* @param metaData The metadata to get reserved words from
|
||||
*
|
||||
* @throws SQLException Any access to DatabaseMetaData can case SQLException; just re-throw.
|
||||
*/
|
||||
public void applyReservedWords(DatabaseMetaData metaData) throws SQLException {
|
||||
if ( metaData == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.reservedWords.addAll( parseKeywords( metaData.getSQLKeywords() ) );
|
||||
}
|
||||
|
||||
private static List<String> parseKeywords(String extraKeywordsString) {
|
||||
if ( StringHelper.isEmpty( extraKeywordsString ) ) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return StringHelper.parseCommaSeparatedString( extraKeywordsString );
|
||||
}
|
||||
|
||||
public void applyIdentifierCasing(DatabaseMetaData metaData) throws SQLException {
|
||||
if ( metaData == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int unquotedAffirmatives = ArrayHelper.countTrue(
|
||||
metaData.storesLowerCaseIdentifiers(),
|
||||
metaData.storesUpperCaseIdentifiers(),
|
||||
metaData.storesMixedCaseIdentifiers()
|
||||
);
|
||||
|
||||
if ( unquotedAffirmatives == 0 ) {
|
||||
log.debug( "JDBC driver metadata reported database stores unquoted identifiers in neither upper, lower nor mixed case" );
|
||||
}
|
||||
else {
|
||||
// NOTE : still "dodgy" if more than one is true
|
||||
if ( unquotedAffirmatives > 1 ) {
|
||||
log.debug( "JDBC driver metadata reported database stores unquoted identifiers in more than one case" );
|
||||
}
|
||||
|
||||
if ( metaData.storesUpperCaseIdentifiers() ) {
|
||||
this.unquotedCaseStrategy = IdentifierCaseStrategy.UPPER;
|
||||
}
|
||||
else if ( metaData.storesLowerCaseIdentifiers() ) {
|
||||
this.unquotedCaseStrategy = IdentifierCaseStrategy.LOWER;
|
||||
}
|
||||
else {
|
||||
this.unquotedCaseStrategy = IdentifierCaseStrategy.MIXED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
final int quotedAffirmatives = ArrayHelper.countTrue(
|
||||
metaData.storesLowerCaseQuotedIdentifiers(),
|
||||
metaData.storesUpperCaseQuotedIdentifiers(),
|
||||
metaData.storesMixedCaseQuotedIdentifiers()
|
||||
);
|
||||
|
||||
if ( quotedAffirmatives == 0 ) {
|
||||
log.debug( "JDBC driver metadata reported database stores quoted identifiers in neither upper, lower nor mixed case" );
|
||||
}
|
||||
else {
|
||||
// NOTE : still "dodgy" if more than one is true
|
||||
if ( quotedAffirmatives > 1 ) {
|
||||
log.debug( "JDBC driver metadata reported database stores quoted identifiers in more than one case" );
|
||||
}
|
||||
|
||||
if ( metaData.storesMixedCaseQuotedIdentifiers() ) {
|
||||
this.quotedCaseStrategy = IdentifierCaseStrategy.MIXED;
|
||||
}
|
||||
else if ( metaData.storesLowerCaseQuotedIdentifiers() ) {
|
||||
this.quotedCaseStrategy = IdentifierCaseStrategy.LOWER;
|
||||
}
|
||||
else {
|
||||
this.quotedCaseStrategy = IdentifierCaseStrategy.UPPER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isGloballyQuoteIdentifiers() {
|
||||
return globallyQuoteIdentifiers;
|
||||
}
|
||||
|
||||
public void setGloballyQuoteIdentifiers(boolean globallyQuoteIdentifiers) {
|
||||
this.globallyQuoteIdentifiers = globallyQuoteIdentifiers;
|
||||
}
|
||||
|
||||
public NameQualifierSupport getNameQualifierSupport() {
|
||||
return nameQualifierSupport;
|
||||
}
|
||||
|
||||
public void setNameQualifierSupport(NameQualifierSupport nameQualifierSupport) {
|
||||
this.nameQualifierSupport = nameQualifierSupport == null ? NameQualifierSupport.BOTH : nameQualifierSupport;
|
||||
}
|
||||
|
||||
public IdentifierCaseStrategy getUnquotedCaseStrategy() {
|
||||
return unquotedCaseStrategy;
|
||||
}
|
||||
|
||||
public void setUnquotedCaseStrategy(IdentifierCaseStrategy unquotedCaseStrategy) {
|
||||
this.unquotedCaseStrategy = unquotedCaseStrategy;
|
||||
}
|
||||
|
||||
public IdentifierCaseStrategy getQuotedCaseStrategy() {
|
||||
return quotedCaseStrategy;
|
||||
}
|
||||
|
||||
public void setQuotedCaseStrategy(IdentifierCaseStrategy quotedCaseStrategy) {
|
||||
this.quotedCaseStrategy = quotedCaseStrategy;
|
||||
}
|
||||
|
||||
public void clearReservedWords() {
|
||||
this.reservedWords.clear();
|
||||
}
|
||||
|
||||
public void applyReservedWords(Set<String> words) {
|
||||
this.reservedWords.addAll( words );
|
||||
}
|
||||
|
||||
public void setReservedWords(Set<String> words) {
|
||||
clearReservedWords();
|
||||
applyReservedWords( words );
|
||||
}
|
||||
|
||||
public IdentifierHelper build() {
|
||||
if ( unquotedCaseStrategy == quotedCaseStrategy ) {
|
||||
log.debugf(
|
||||
"IdentifierCaseStrategy for both quoted and unquoted identifiers was set " +
|
||||
"to the same strategy [%s]; that will likely lead to problems in schema update " +
|
||||
"and validation if using quoted identifiers",
|
||||
unquotedCaseStrategy.name()
|
||||
);
|
||||
}
|
||||
|
||||
return new NormalizingIdentifierHelperImpl(
|
||||
jdbcEnvironment,
|
||||
nameQualifierSupport,
|
||||
globallyQuoteIdentifiers,
|
||||
reservedWords,
|
||||
unquotedCaseStrategy,
|
||||
quotedCaseStrategy
|
||||
);
|
||||
}
|
||||
}
|
|
@ -24,7 +24,7 @@ public interface JdbcEnvironment extends Service {
|
|||
*
|
||||
* @return The dialect.
|
||||
*/
|
||||
public Dialect getDialect();
|
||||
Dialect getDialect();
|
||||
|
||||
/**
|
||||
* Access to the bits of information we pulled off the JDBC {@link java.sql.DatabaseMetaData} (that did not get
|
||||
|
@ -32,7 +32,7 @@ public interface JdbcEnvironment extends Service {
|
|||
*
|
||||
* @return The values extracted from JDBC DatabaseMetaData
|
||||
*/
|
||||
public ExtractedDatabaseMetaData getExtractedDatabaseMetaData();
|
||||
ExtractedDatabaseMetaData getExtractedDatabaseMetaData();
|
||||
|
||||
/**
|
||||
* Get the current database catalog. Typically will come from either {@link java.sql.Connection#getCatalog()}
|
||||
|
@ -40,7 +40,7 @@ public interface JdbcEnvironment extends Service {
|
|||
*
|
||||
* @return The current catalog.
|
||||
*/
|
||||
public Identifier getCurrentCatalog();
|
||||
Identifier getCurrentCatalog();
|
||||
|
||||
/**
|
||||
* Get the current database catalog. Typically will come from either
|
||||
|
@ -49,14 +49,14 @@ public interface JdbcEnvironment extends Service {
|
|||
*
|
||||
* @return The current schema
|
||||
*/
|
||||
public Identifier getCurrentSchema();
|
||||
Identifier getCurrentSchema();
|
||||
|
||||
/**
|
||||
* Obtain support for formatting qualified object names.
|
||||
*
|
||||
* @return Qualified name support.
|
||||
*/
|
||||
public QualifiedObjectNameFormatter getQualifiedObjectNameFormatter();
|
||||
QualifiedObjectNameFormatter getQualifiedObjectNameFormatter();
|
||||
|
||||
/**
|
||||
* Obtain the helper for dealing with identifiers in this environment.
|
||||
|
@ -66,30 +66,21 @@ public interface JdbcEnvironment extends Service {
|
|||
*
|
||||
* @return The identifier helper.
|
||||
*/
|
||||
public IdentifierHelper getIdentifierHelper();
|
||||
|
||||
/**
|
||||
* Check whether the given word represents a reserved word.
|
||||
*
|
||||
* @param word The word to check
|
||||
*
|
||||
* @return {@code true} if the given word represents a reserved word; {@code false} otherwise.
|
||||
*/
|
||||
public boolean isReservedWord(String word);
|
||||
IdentifierHelper getIdentifierHelper();
|
||||
|
||||
/**
|
||||
* Obtain the helper for dealing with JDBC {@link java.sql.SQLException} faults.
|
||||
*
|
||||
* @return This environment's helper.
|
||||
*/
|
||||
public SqlExceptionHelper getSqlExceptionHelper();
|
||||
SqlExceptionHelper getSqlExceptionHelper();
|
||||
|
||||
/**
|
||||
* Retrieve the delegate for building {@link org.hibernate.engine.jdbc.LobCreator} instances.
|
||||
*
|
||||
* @return The LobCreator builder.
|
||||
*/
|
||||
public LobCreatorBuilder getLobCreatorBuilder();
|
||||
LobCreatorBuilder getLobCreatorBuilder();
|
||||
|
||||
/**
|
||||
* Find type information for the type identified by the given "JDBC type code".
|
||||
|
@ -98,5 +89,5 @@ public interface JdbcEnvironment extends Service {
|
|||
*
|
||||
* @return The corresponding type info.
|
||||
*/
|
||||
public TypeInfo getTypeInfoForJdbcCode(int jdbcTypeCode);
|
||||
TypeInfo getTypeInfoForJdbcCode(int jdbcTypeCode);
|
||||
}
|
||||
|
|
|
@ -12,10 +12,38 @@ import org.hibernate.boot.model.relational.QualifiedTableName;
|
|||
import org.hibernate.dialect.Dialect;
|
||||
|
||||
/**
|
||||
* Contract for rendering qualified object names for use in queries, etc.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface QualifiedObjectNameFormatter {
|
||||
public String format(QualifiedTableName qualifiedTableName, Dialect dialect);
|
||||
public String format(QualifiedSequenceName qualifiedSequenceName, Dialect dialect);
|
||||
public String format(QualifiedName qualifiedName, Dialect dialect);
|
||||
/**
|
||||
* Render a formatted a table name
|
||||
*
|
||||
* @param qualifiedTableName The table name
|
||||
* @param dialect The dialect
|
||||
*
|
||||
* @return The formatted name,
|
||||
*/
|
||||
String format(QualifiedTableName qualifiedTableName, Dialect dialect);
|
||||
|
||||
/**
|
||||
* Render a formatted sequence name
|
||||
*
|
||||
* @param qualifiedSequenceName The sequence name
|
||||
* @param dialect The dialect
|
||||
*
|
||||
* @return The formatted name
|
||||
*/
|
||||
String format(QualifiedSequenceName qualifiedSequenceName, Dialect dialect);
|
||||
|
||||
/**
|
||||
* Render a formatted non-table and non-sequence qualified name
|
||||
*
|
||||
* @param qualifiedName The name
|
||||
* @param dialect The dialect
|
||||
*
|
||||
* @return The formatted name
|
||||
*/
|
||||
String format(QualifiedName qualifiedName, Dialect dialect);
|
||||
}
|
||||
|
|
|
@ -13,8 +13,11 @@ import java.io.Serializable;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.BitSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
public final class StringHelper {
|
||||
|
@ -796,4 +799,8 @@ public final class StringHelper {
|
|||
public static String nullIfEmpty(String value) {
|
||||
return isEmpty( value ) ? null : value;
|
||||
}
|
||||
|
||||
public static List<String> parseCommaSeparatedString(String incomingString) {
|
||||
return Arrays.asList( incomingString.split( "\\s*,\\s*" ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -208,7 +208,7 @@ public final class ArrayHelper {
|
|||
return true;
|
||||
}
|
||||
|
||||
public static boolean isAllTrue(boolean[] array) {
|
||||
public static boolean isAllTrue(boolean... array) {
|
||||
for ( boolean anArray : array ) {
|
||||
if ( !anArray ) {
|
||||
return false;
|
||||
|
@ -217,7 +217,7 @@ public final class ArrayHelper {
|
|||
return true;
|
||||
}
|
||||
|
||||
public static int countTrue(boolean[] array) {
|
||||
public static int countTrue(boolean... array) {
|
||||
int result = 0;
|
||||
for ( boolean anArray : array ) {
|
||||
if ( anArray ) {
|
||||
|
@ -235,7 +235,7 @@ public final class ArrayHelper {
|
|||
return result;
|
||||
}*/
|
||||
|
||||
public static boolean isAllFalse(boolean[] array) {
|
||||
public static boolean isAllFalse(boolean... array) {
|
||||
for ( boolean anArray : array ) {
|
||||
if ( anArray ) {
|
||||
return false;
|
||||
|
|
|
@ -43,13 +43,9 @@ public class TestKeywordRecognition extends BaseUnitTestCase {
|
|||
public void testAnsiSqlKeyword() {
|
||||
// END is ANSI SQL keyword
|
||||
|
||||
// keywords are kept defined in upper case in here...
|
||||
assertTrue( AnsiSqlKeywords.INSTANCE.sql2003().contains( "END" ) );
|
||||
|
||||
// But JdbcEnvironment uses a case-insensitive Set to store them...
|
||||
JdbcEnvironment jdbcEnvironment = serviceRegistry.getService( JdbcEnvironment.class );
|
||||
assertTrue( jdbcEnvironment.isReservedWord( "end" ) );
|
||||
assertTrue( jdbcEnvironment.isReservedWord( "END" ) );
|
||||
assertTrue( jdbcEnvironment.getIdentifierHelper().isReservedWord( "end" ) );
|
||||
assertTrue( jdbcEnvironment.getIdentifierHelper().isReservedWord( "END" ) );
|
||||
|
||||
Identifier identifier = jdbcEnvironment.getIdentifierHelper().toIdentifier( "end" );
|
||||
assertTrue( identifier.isQuoted() );
|
||||
|
|
Loading…
Reference in New Issue