HHH-9848 - Allow disabling auto-quoting of database object names (tables, columns, etc)

This commit is contained in:
Steve Ebersole 2015-06-05 13:43:10 -05:00
parent 5b1da92498
commit 30b260f14f
9 changed files with 118 additions and 22 deletions

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.boot;
import java.sql.DatabaseMetaData;
import javax.persistence.AttributeConverter;
import javax.persistence.SharedCacheMode;
@ -23,6 +24,7 @@ import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cfg.AttributeConverterDefinition;
import org.hibernate.cfg.MetadataSourceType;
import org.hibernate.dialect.function.SQLFunction;
import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder;
import org.hibernate.type.BasicType;
import org.hibernate.usertype.CompositeUserType;
import org.hibernate.usertype.UserType;

View File

@ -540,6 +540,8 @@ public class MetadataBuilderImpl implements MetadataBuilder, TypeContributions {
private IdGeneratorInterpreterImpl idGenerationTypeInterpreter = new IdGeneratorInterpreterImpl();
private boolean autoQuoteKeywords;
// private PersistentAttributeMemberResolver persistentAttributeMemberResolver =
// StandardPersistentAttributeMemberResolver.INSTANCE;

View File

@ -18,24 +18,24 @@ import org.hibernate.cache.spi.access.AccessType;
* @since 5.0
*/
public interface MappingDefaults {
public static final String DEFAULT_IDENTIFIER_COLUMN_NAME = "id";
public static final String DEFAULT_TENANT_IDENTIFIER_COLUMN_NAME = "tenant_id";
public static final String DEFAULT_DISCRIMINATOR_COLUMN_NAME = "class";
public static final String DEFAULT_CASCADE_NAME = "none";
public static final String DEFAULT_PROPERTY_ACCESS_NAME = "property";
String DEFAULT_IDENTIFIER_COLUMN_NAME = "id";
String DEFAULT_TENANT_IDENTIFIER_COLUMN_NAME = "tenant_id";
String DEFAULT_DISCRIMINATOR_COLUMN_NAME = "class";
String DEFAULT_CASCADE_NAME = "none";
String DEFAULT_PROPERTY_ACCESS_NAME = "property";
/**
* Identifies the database schema name to use if none specified in the mapping.
*
* @return The implicit schema name; may be {@code null}
*/
public String getImplicitSchemaName();
String getImplicitSchemaName();
/**
* Identifies the database catalog name to use if none specified in the mapping.
*
* @return The implicit catalog name; may be {@code null}
*/
public String getImplicitCatalogName();
String getImplicitCatalogName();
/**
* Should all database identifiers encountered in this context be implicitly quoted?
@ -46,7 +46,7 @@ public interface MappingDefaults {
*
* @return {@code true}/{@code false}
*/
public boolean shouldImplicitlyQuoteIdentifiers();
boolean shouldImplicitlyQuoteIdentifiers();
/**
* Identifies the column name to use for the identifier column if none specified in
@ -54,7 +54,7 @@ public interface MappingDefaults {
*
* @return The implicit identifier column name
*/
public String getImplicitIdColumnName();
String getImplicitIdColumnName();
/**
* Identifies the column name to use for the tenant identifier column if none is
@ -62,7 +62,7 @@ public interface MappingDefaults {
*
* @return The implicit tenant identifier column name
*/
public String getImplicitTenantIdColumnName();
String getImplicitTenantIdColumnName();
/**
* Identifies the column name to use for the discriminator column if none specified
@ -70,7 +70,7 @@ public interface MappingDefaults {
*
* @return The implicit discriminator column name
*/
public String getImplicitDiscriminatorColumnName();
String getImplicitDiscriminatorColumnName();
/**
* Identifies the package name to use if none specified in the mapping. Really only
@ -78,21 +78,21 @@ public interface MappingDefaults {
*
* @return The implicit package name.
*/
public String getImplicitPackageName();
String getImplicitPackageName();
/**
* Is auto-importing of entity (short) names enabled?
*
* @return {@code true} if auto-importing is enabled; {@code false} otherwise.
*/
public boolean isAutoImportEnabled();
boolean isAutoImportEnabled();
/**
* Identifies the cascade style to apply to associations if none specified in the mapping.
*
* @return The implicit cascade style
*/
public String getImplicitCascadeStyleName();
String getImplicitCascadeStyleName();
/**
* Identifies the default {@link org.hibernate.property.access.spi.PropertyAccessStrategy} name to use if none specified in the
@ -102,7 +102,7 @@ public interface MappingDefaults {
*
* @see org.hibernate.property.access.spi.PropertyAccessStrategy
*/
public String getImplicitPropertyAccessorName();
String getImplicitPropertyAccessorName();
/**
* Identifies whether singular associations (many-to-one, one-to-one) are lazy
@ -110,19 +110,19 @@ public interface MappingDefaults {
*
* @return The implicit association laziness
*/
public boolean areEntitiesImplicitlyLazy();
boolean areEntitiesImplicitlyLazy();
/**
* Identifies whether plural attributes are lazy by default if not specified in the mapping.
*
* @return The implicit association laziness
*/
public boolean areCollectionsImplicitlyLazy();
boolean areCollectionsImplicitlyLazy();
/**
* The cache access type to use if none is specified
*
* @return The implicit cache access type.
*/
public AccessType getImplicitCacheAccessType();
AccessType getImplicitCacheAccessType();
}

View File

@ -746,9 +746,11 @@ public interface AvailableSettings {
*/
String LOG_SESSION_METRICS = "hibernate.session.events.log";
/**
* Defines a default {@link org.hibernate.SessionEventListener} to be applied to opened Sessions.
*/
String AUTO_SESSION_EVENTS_LISTENER = "hibernate.session.events.auto";
/**
* The deprecated name. Use {@link #SCANNER} or {@link #SCANNER_ARCHIVE_INTERPRETER} instead.
*/
@ -820,4 +822,12 @@ public interface AvailableSettings {
* annotations (combined with {@code orm.xml} mappings).
*/
String ARTIFACT_PROCESSING_ORDER = "hibernate.mapping.precedence";
/**
* Specifies whether to automatically quote any names that are deemed keywords. Auto-quoting
* is enabled by default. Set to false to disable.
*
* @since 5.0
*/
String KEYWORD_AUTO_QUOTING_ENABLED = "hibernate.auto_quote_keyword";
}

View File

@ -20,7 +20,6 @@ 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;
@ -78,6 +77,7 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment {
final IdentifierHelperBuilder identifierHelperBuilder = IdentifierHelperBuilder.from( this );
identifierHelperBuilder.setGloballyQuoteIdentifiers( globalQuoting( cfgService ) );
identifierHelperBuilder.setGloballyQuoteIdentifiers( autoQuoting( cfgService ) );
identifierHelperBuilder.setNameQualifierSupport( nameQualifierSupport );
IdentifierHelper identifierHelper = null;
@ -113,6 +113,14 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment {
);
}
private static boolean autoQuoting(ConfigurationService cfgService) {
return cfgService.getSetting(
AvailableSettings.KEYWORD_AUTO_QUOTING_ENABLED,
StandardConverters.BOOLEAN,
true
);
}
/**
* Constructor form used from testing
*
@ -207,6 +215,7 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment {
final IdentifierHelperBuilder identifierHelperBuilder = IdentifierHelperBuilder.from( this );
identifierHelperBuilder.setGloballyQuoteIdentifiers( globalQuoting( cfgService ) );
identifierHelperBuilder.setAutoQuoteKeywords( autoQuoting( cfgService ) );
identifierHelperBuilder.setNameQualifierSupport( nameQualifierSupport );
IdentifierHelper identifierHelper = null;
try {

View File

@ -28,6 +28,7 @@ public class NormalizingIdentifierHelperImpl implements IdentifierHelper {
private final NameQualifierSupport nameQualifierSupport;
private final boolean globallyQuoteIdentifiers;
private final boolean autoQuoteKeywords;
private final Set<String> reservedWords = new TreeSet<String>( String.CASE_INSENSITIVE_ORDER );
private final IdentifierCaseStrategy unquotedCaseStrategy;
private final IdentifierCaseStrategy quotedCaseStrategy;
@ -36,12 +37,14 @@ public class NormalizingIdentifierHelperImpl implements IdentifierHelper {
JdbcEnvironment jdbcEnvironment,
NameQualifierSupport nameQualifierSupport,
boolean globallyQuoteIdentifiers,
boolean autoQuoteKeywords,
Set<String> reservedWords,
IdentifierCaseStrategy unquotedCaseStrategy,
IdentifierCaseStrategy quotedCaseStrategy) {
this.jdbcEnvironment = jdbcEnvironment;
this.nameQualifierSupport = nameQualifierSupport;
this.globallyQuoteIdentifiers = globallyQuoteIdentifiers;
this.autoQuoteKeywords = autoQuoteKeywords;
if ( reservedWords != null ) {
this.reservedWords.addAll( reservedWords );
}
@ -66,7 +69,7 @@ public class NormalizingIdentifierHelperImpl implements IdentifierHelper {
return Identifier.toIdentifier( identifier.getText(), true );
}
if ( isReservedWord( identifier.getText() ) ) {
if ( autoQuoteKeywords && isReservedWord( identifier.getText() ) ) {
log.tracef( "Forcing identifier [%s] to quoted as recognized reserveed word", identifier );
return Identifier.toIdentifier( identifier.getText(), true );
}
@ -208,7 +211,7 @@ public class NormalizingIdentifierHelperImpl implements IdentifierHelper {
return Identifier.toIdentifier( text, true );
}
if ( isReservedWord( text ) ) {
if ( autoQuoteKeywords && 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 );

View File

@ -34,6 +34,7 @@ public class IdentifierHelperBuilder {
private Set<String> reservedWords = new TreeSet<String>( String.CASE_INSENSITIVE_ORDER );
private boolean globallyQuoteIdentifiers = false;
private boolean autoQuoteKeywords = true;
private IdentifierCaseStrategy unquotedCaseStrategy = IdentifierCaseStrategy.UPPER;
private IdentifierCaseStrategy quotedCaseStrategy = IdentifierCaseStrategy.MIXED;
@ -135,6 +136,10 @@ public class IdentifierHelperBuilder {
this.globallyQuoteIdentifiers = globallyQuoteIdentifiers;
}
public void setAutoQuoteKeywords(boolean autoQuoteKeywords) {
this.autoQuoteKeywords = autoQuoteKeywords;
}
public NameQualifierSupport getNameQualifierSupport() {
return nameQualifierSupport;
}
@ -186,6 +191,7 @@ public class IdentifierHelperBuilder {
jdbcEnvironment,
nameQualifierSupport,
globallyQuoteIdentifiers,
autoQuoteKeywords,
reservedWords,
unquotedCaseStrategy,
quotedCaseStrategy

View File

@ -0,0 +1,51 @@
/*
* 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.test.schemaupdate;
import java.util.Collections;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.testing.boot.ServiceRegistryTestingImpl;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import org.junit.Test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* @author Steve Ebersole
*/
public class IdentifierHelperTest extends BaseUnitTestCase {
@Test
public void testAutoQuotingDisabled() {
ServiceRegistry sr = ServiceRegistryTestingImpl.forUnitTesting(
Collections.singletonMap(
AvailableSettings.KEYWORD_AUTO_QUOTING_ENABLED,
// true is the default, but to be sure...
true
)
);
Identifier identifier = sr.getService( JdbcEnvironment.class ).getIdentifierHelper().toIdentifier( "select" );
assertTrue( identifier.isQuoted() );
StandardServiceRegistryBuilder.destroy( sr );
sr = ServiceRegistryTestingImpl.forUnitTesting(
Collections.singletonMap(
AvailableSettings.KEYWORD_AUTO_QUOTING_ENABLED,
false
)
);
identifier = sr.getService( JdbcEnvironment.class ).getIdentifierHelper().toIdentifier( "select" );
assertFalse( identifier.isQuoted() );
StandardServiceRegistryBuilder.destroy( sr );
}
}

View File

@ -45,6 +45,19 @@ public class ServiceRegistryTestingImpl
);
}
public static ServiceRegistryTestingImpl forUnitTesting(Map settings) {
return new ServiceRegistryTestingImpl(
true,
new BootstrapServiceRegistryBuilder().build(),
StandardServiceInitiators.LIST,
Arrays.asList(
dialectFactoryService(),
connectionProviderService()
),
settings
);
}
private static ProvidedService dialectFactoryService() {
return new ProvidedService<DialectFactory>( DialectFactory.class, new DialectFactoryTestingImpl() );
}