HHH-6174 Adding support for o.h.a.Index

This commit is contained in:
Hardy Ferentschik 2011-05-05 15:44:05 +02:00
parent 328d72e1cd
commit 101aa09e36
4 changed files with 1605 additions and 1432 deletions

View File

@ -23,10 +23,6 @@
*/
package org.hibernate.internal;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@ -37,6 +33,10 @@ import java.sql.SQLWarning;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Set;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import org.jboss.logging.BasicLogger;
import org.jboss.logging.Cause;
@ -47,10 +47,10 @@ import org.jboss.logging.MessageLogger;
import org.hibernate.HibernateException;
import org.hibernate.cache.CacheException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.loading.internal.CollectionLoadContext;
import org.hibernate.engine.loading.internal.EntityLoadContext;
import org.hibernate.engine.spi.CollectionKey;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.id.IntegralDataTypeHolder;
import org.hibernate.service.jdbc.dialect.internal.AbstractDialectResolver;
import org.hibernate.service.jndi.JndiException;
@ -81,7 +81,8 @@ public interface CoreMessageLogger extends BasicLogger {
void autoCommitMode(boolean autocommit);
@LogMessage(level = WARN)
@Message( value = "JTASessionContext being used with JDBCTransactionFactory; auto-flush will not operate correctly with getCurrentSession()", id = 8 )
@Message(value = "JTASessionContext being used with JDBCTransactionFactory; auto-flush will not operate correctly with getCurrentSession()",
id = 8)
void autoFlushWillNotWork();
@LogMessage(level = INFO)
@ -93,7 +94,8 @@ public interface CoreMessageLogger extends BasicLogger {
void bytecodeProvider(String provider);
@LogMessage(level = WARN)
@Message( value = "c3p0 properties were encountered, but the %s provider class was not found on the classpath; these properties are going to be ignored.", id = 22 )
@Message(value = "c3p0 properties were encountered, but the %s provider class was not found on the classpath; these properties are going to be ignored.",
id = 22)
void c3p0ProviderClassNotFound(String c3p0ProviderClassName);
@LogMessage(level = WARN)
@ -202,7 +204,8 @@ public interface CoreMessageLogger extends BasicLogger {
void deprecatedForceDescriminatorAnnotation();
@LogMessage(level = WARN)
@Message( value = "The Oracle9Dialect dialect has been deprecated; use either Oracle9iDialect or Oracle10gDialect instead", id = 63 )
@Message(value = "The Oracle9Dialect dialect has been deprecated; use either Oracle9iDialect or Oracle10gDialect instead",
id = 63)
void deprecatedOracle9Dialect();
@LogMessage(level = WARN)
@ -272,7 +275,8 @@ public interface CoreMessageLogger extends BasicLogger {
void entityManagerClosedBySomeoneElse(String autoCloseSession);
@LogMessage(level = WARN)
@Message( value = "Entity [%s] is abstract-class/interface explicitly mapped as non-abstract; be sure to supply entity-names", id = 84 )
@Message(value = "Entity [%s] is abstract-class/interface explicitly mapped as non-abstract; be sure to supply entity-names",
id = 84)
void entityMappedAsNonAbstract(String name);
@LogMessage(level = INFO)
@ -356,7 +360,8 @@ public interface CoreMessageLogger extends BasicLogger {
void forcingContainerResourceCleanup();
@LogMessage(level = INFO)
@Message( value = "Forcing table use for sequence-style generator due to pooled optimizer selection where db does not support pooled sequences", id = 107 )
@Message(value = "Forcing table use for sequence-style generator due to pooled optimizer selection where db does not support pooled sequences",
id = 107)
void forcingTableUse();
@LogMessage(level = INFO)
@ -447,7 +452,8 @@ public interface CoreMessageLogger extends BasicLogger {
void invalidArrayElementType(String message);
@LogMessage(level = WARN)
@Message( value = "Discriminator column has to be defined in the root entity, it will be ignored in subclass: %s", id = 133 )
@Message(value = "Discriminator column has to be defined in the root entity, it will be ignored in subclass: %s",
id = 133)
void invalidDiscriminatorAnnotation(String className);
@LogMessage(level = ERROR)
@ -468,7 +474,8 @@ public interface CoreMessageLogger extends BasicLogger {
void invalidPrimaryKeyJoinColumnAnnotation();
@LogMessage(level = WARN)
@Message( value = "Mixing inheritance strategy in a entity hierarchy is not allowed, ignoring sub strategy in: %s", id = 138 )
@Message(value = "Mixing inheritance strategy in a entity hierarchy is not allowed, ignoring sub strategy in: %s",
id = 138)
void invalidSubStrategy(String className);
@LogMessage(level = WARN)
@ -520,7 +527,8 @@ public interface CoreMessageLogger extends BasicLogger {
void lazyPropertyFetchingAvailable(String name);
@LogMessage(level = WARN)
@Message( value = "In CollectionLoadContext#endLoadingCollections, localLoadingCollectionKeys contained [%s], but no LoadingCollectionEntry was found in loadContexts", id = 159 )
@Message(value = "In CollectionLoadContext#endLoadingCollections, localLoadingCollectionKeys contained [%s], but no LoadingCollectionEntry was found in loadContexts",
id = 159)
void loadingCollectionKeyNotFound(CollectionKey collectionKey);
@LogMessage(level = WARN)
@ -549,7 +557,8 @@ public interface CoreMessageLogger extends BasicLogger {
int numberOfArguments);
@LogMessage(level = WARN)
@Message( value = "Class annotated @org.hibernate.annotations.Entity but not javax.persistence.Entity (most likely a user error): %s", id = 175 )
@Message(value = "Class annotated @org.hibernate.annotations.Entity but not javax.persistence.Entity (most likely a user error): %s",
id = 175)
void missingEntityAnnotation(String className);
@ -571,11 +580,13 @@ public interface CoreMessageLogger extends BasicLogger {
void needsLimit();
@LogMessage(level = WARN)
@Message( value = "No appropriate connection provider encountered, assuming application will be supplying connections", id = 181 )
@Message(value = "No appropriate connection provider encountered, assuming application will be supplying connections",
id = 181)
void noAppropriateConnectionProvider();
@LogMessage(level = INFO)
@Message( value = "No default (no-argument) constructor for class: %s (class must be instantiated by Interceptor)", id = 182 )
@Message(value = "No default (no-argument) constructor for class: %s (class must be instantiated by Interceptor)",
id = 182)
void noDefaultConstructor(String name);
@LogMessage(level = WARN)
@ -635,7 +646,8 @@ public interface CoreMessageLogger extends BasicLogger {
void persistenceProviderCallerDoesNotImplementEjb3SpecCorrectly();
@LogMessage(level = INFO)
@Message( value = "Pooled optimizer source reported [%s] as the initial value; use of 1 or greater highly recommended", id = 201 )
@Message(value = "Pooled optimizer source reported [%s] as the initial value; use of 1 or greater highly recommended",
id = 201)
void pooledOptimizerReportedInitialValue(IntegralDataTypeHolder value);
@LogMessage(level = ERROR)
@ -668,7 +680,8 @@ public interface CoreMessageLogger extends BasicLogger {
String actualProviderClassName);
@LogMessage(level = WARN)
@Message( value = "proxool properties were encountered, but the %s provider class was not found on the classpath; these properties are going to be ignored.", id = 209 )
@Message(value = "proxool properties were encountered, but the %s provider class was not found on the classpath; these properties are going to be ignored.",
id = 209)
void proxoolProviderClassNotFound(String proxoolProviderClassName);
@LogMessage(level = INFO)
@ -708,7 +721,8 @@ public interface CoreMessageLogger extends BasicLogger {
void readOnlyCacheConfiguredForMutableCollection(String name);
@LogMessage(level = WARN)
@Message( value = "Recognized obsolete hibernate namespace %s. Use namespace %s instead. Refer to Hibernate 3.6 Migration Guide!", id = 223 )
@Message(value = "Recognized obsolete hibernate namespace %s. Use namespace %s instead. Refer to Hibernate 3.6 Migration Guide!",
id = 223)
void recognizedObsoleteHibernateNamespace(String oldHibernateNamespace,
String hibernateNamespace);
@ -912,7 +926,8 @@ public interface CoreMessageLogger extends BasicLogger {
void unableToBuildEnhancementMetamodel(String className);
@LogMessage(level = INFO)
@Message( value = "Could not build SessionFactory using the MBean classpath - will try again using client classpath: %s", id = 280 )
@Message(value = "Could not build SessionFactory using the MBean classpath - will try again using client classpath: %s",
id = 280)
void unableToBuildSessionFactoryUsingMBeanClasspath(String message);
@LogMessage(level = WARN)
@ -1264,7 +1279,8 @@ public interface CoreMessageLogger extends BasicLogger {
String string);
@LogMessage(level = WARN)
@Message( value = "Exception switching from method: [%s] to a method using the column index. Reverting to using: [%<s]", id = 370 )
@Message(value = "Exception switching from method: [%s] to a method using the column index. Reverting to using: [%<s]",
id = 370)
void unableToSwitchToMethodUsingColumnIndex(Method method);
@LogMessage(level = ERROR)
@ -1353,7 +1369,8 @@ public interface CoreMessageLogger extends BasicLogger {
void unsupportedInitialValue(String propertyName);
@LogMessage(level = WARN)
@Message( value = "The %s.%s.%s version of H2 implements temporary table creation such that it commits current transaction; multi-table, bulk hql/jpaql will not work properly", id = 393 )
@Message(value = "The %s.%s.%s version of H2 implements temporary table creation such that it commits current transaction; multi-table, bulk hql/jpaql will not work properly",
id = 393)
void unsupportedMultiTableBulkHqlJpaql(int majorVersion,
int minorVersion,
int buildId);
@ -1415,7 +1432,8 @@ public interface CoreMessageLogger extends BasicLogger {
void usingTimestampWorkaround();
@LogMessage(level = WARN)
@Message( value = "Using %s which does not generate IETF RFC 4122 compliant UUID values; consider using %s instead", id = 409 )
@Message(value = "Using %s which does not generate IETF RFC 4122 compliant UUID values; consider using %s instead",
id = 409)
void usingUuidHexGenerator(String name,
String name2);
@ -1432,7 +1450,8 @@ public interface CoreMessageLogger extends BasicLogger {
void warningsCreatingTempTable(SQLWarning warning);
@LogMessage(level = INFO)
@Message( value = "Property hibernate.search.autoregister_listeners is set to false. No attempt will be made to register Hibernate Search event listeners.", id = 414 )
@Message(value = "Property hibernate.search.autoregister_listeners is set to false. No attempt will be made to register Hibernate Search event listeners.",
id = 414)
void willNotRegisterListeners();
@LogMessage(level = WARN)
@ -1449,7 +1468,8 @@ public interface CoreMessageLogger extends BasicLogger {
String name2);
@LogMessage(level = WARN)
@Message( value = "Resolved SqlTypeDescriptor is for a different SQL code. %s has sqlCode=%s; type override %s has sqlCode=%s", id = 419 )
@Message(value = "Resolved SqlTypeDescriptor is for a different SQL code. %s has sqlCode=%s; type override %s has sqlCode=%s",
id = 419)
void resolvedSqlTypeDescriptorForDifferentSqlCode(String name,
String valueOf,
String name2,
@ -1468,7 +1488,8 @@ public interface CoreMessageLogger extends BasicLogger {
void disablingContextualLOBCreationSinceConnectionNull();
@LogMessage(level = INFO)
@Message( value = "Disabling contextual LOB creation as JDBC driver reported JDBC version [%s] less than 4", id = 423 )
@Message(value = "Disabling contextual LOB creation as JDBC driver reported JDBC version [%s] less than 4",
id = 423)
void disablingContextualLOBCreationSinceOldJdbcVersion(int jdbcMajorVersion);
@LogMessage(level = INFO)
@ -1491,7 +1512,8 @@ public interface CoreMessageLogger extends BasicLogger {
String jtaPlatform);
@LogMessage(level = INFO)
@Message( value = "Encountered legacy TransactionManagerLookup specified; convert to newer %s contract specified via %s setting", id = 428 )
@Message(value = "Encountered legacy TransactionManagerLookup specified; convert to newer %s contract specified via %s setting",
id = 428)
void legacyTransactionManagerStrategy(String name,
String jtaPlatform);
@ -1500,10 +1522,15 @@ public interface CoreMessageLogger extends BasicLogger {
void entityIdentifierValueBindingExists(String name);
@LogMessage(level = WARN)
@Message( value = "The DerbyDialect dialect has been deprecated; use one of the version-specific dialects instead", id = 430 )
@Message(value = "The DerbyDialect dialect has been deprecated; use one of the version-specific dialects instead",
id = 430)
void deprecatedDerbyDialect();
@LogMessage(level = WARN)
@Message(value = "Unable to determine H2 database version, certain features may not work", id = 431)
void undeterminedH2Version();
@LogMessage(level = WARN)
@Message(value = "There were not column names specified for index %s on table %s", id = 432)
void noColumnsSpecifiedForIndex(String indexName, String tableName);
}

View File

@ -23,7 +23,6 @@
*/
package org.hibernate.metamodel.source.annotations;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@ -84,12 +83,24 @@ public class MappedAttribute implements Comparable<MappedAttribute> {
return isVersioned;
}
public final List<AnnotationInstance> annotations(DotName annotationDotName) {
/**
* Returns the annotation with the specified name or {@code null}
*
* @param annotationDotName The annotation to retrieve/check
*
* @return Returns the annotation with the specified name or {@code null}. Note, since these are the
* annotations defined on a single attribute there can never be more than one.
*/
public final AnnotationInstance annotations(DotName annotationDotName) {
if ( annotations.containsKey( annotationDotName ) ) {
return annotations.get( annotationDotName );
List<AnnotationInstance> instanceList = annotations.get( annotationDotName );
if ( instanceList.size() > 1 ) {
throw new AssertionFailure( "There cannot be more than one @" + annotationDotName.toString() + " annotation per mapped attribute" );
}
return instanceList.get( 0 );
}
else {
return Collections.emptyList();
return null;
}
}

View File

@ -0,0 +1,138 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.metamodel.source.annotations.global;
import java.util.Arrays;
import java.util.List;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.Index;
import org.jboss.logging.Logger;
import org.hibernate.AnnotationException;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.metamodel.relational.Column;
import org.hibernate.metamodel.relational.ObjectName;
import org.hibernate.metamodel.relational.Schema;
import org.hibernate.metamodel.relational.SimpleValue;
import org.hibernate.metamodel.relational.Table;
import org.hibernate.metamodel.source.annotations.HibernateDotNames;
import org.hibernate.metamodel.source.internal.MetadataImpl;
/**
* Binds table related information. This binder is called after the entities are bound.
*
* @author Hardy Ferentschik
*/
public class TableBinder {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class, TableBinder.class.getName()
);
private TableBinder() {
}
/**
* Binds {@link org.hibernate.annotations.Tables} and {@link org.hibernate.annotations.Table}
* annotations to the specified meta data instance.
*
* @param meta the global metadata
* @param index the annotation index repository
*/
public static void bind(MetadataImpl meta, Index index) {
// check @o.h.a.Tables
List<AnnotationInstance> tablesAnnotations = index.getAnnotations( HibernateDotNames.TABLES );
for ( AnnotationInstance tableAnnotation : tablesAnnotations ) {
AnnotationInstance tables[] = tableAnnotation.value().asNestedArray();
bindTablesAnnotation( meta, Arrays.asList( tables ) );
}
// check @o.h.a.Table
List<AnnotationInstance> tableAnnotations = index.getAnnotations( HibernateDotNames.TABLE );
bindTablesAnnotation( meta, tableAnnotations );
}
private static void bindTablesAnnotation(MetadataImpl meta, List<AnnotationInstance> tableAnnotations) {
for ( AnnotationInstance tableAnnotation : tableAnnotations ) {
String tableName = tableAnnotation.value( "appliesTo" ).asString();
ObjectName objectName = new ObjectName( tableName );
Schema schema = meta.getDatabase().getSchema( objectName.getSchema(), objectName.getCatalog() );
Table table = schema.getTable( objectName.getName() );
if ( table == null ) {
continue;
}
bindHibernateTableAnnotation( table, tableAnnotation );
}
}
private static void bindHibernateTableAnnotation(Table table, AnnotationInstance tableAnnotation) {
if ( tableAnnotation.value( "indexes" ) != null ) {
AnnotationInstance[] indexAnnotations = tableAnnotation.value( "indexes" ).asNestedArray();
for ( AnnotationInstance indexAnnotation : indexAnnotations ) {
bindIndexAnnotation( table, indexAnnotation );
}
}
if ( tableAnnotation.value( "comment" ) != null ) {
table.addComment( tableAnnotation.value( "comment" ).asString().trim() );
}
}
private static void bindIndexAnnotation(Table table, AnnotationInstance indexAnnotation) {
String indexName = indexAnnotation.value( "name" ).asString();
if ( indexAnnotation.value( "columnNames" ) == null ) {
LOG.noColumnsSpecifiedForIndex( indexName, table.toLoggableString() );
return;
}
org.hibernate.metamodel.relational.Index index = table.getOrCreateIndex( indexName );
String[] columnNames = indexAnnotation.value( "columnNames" ).asStringArray();
for ( String columnName : columnNames ) {
Column column = findColumn( table, columnName );
if ( column == null ) {
throw new AnnotationException(
"@Index references a unknown column: " + columnName
);
}
index.addColumn( column );
}
}
private static Column findColumn(Table table, String columnName) {
Column column = null;
for ( SimpleValue value : table.values() ) {
if ( value instanceof Column && ( (Column) value ).getName().equals( columnName ) ) {
column = (Column) value;
break;
}
}
return column;
}
}

View File

@ -32,7 +32,6 @@ import java.util.Set;
import org.jboss.jandex.AnnotationInstance;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.metamodel.binding.SimpleAttributeBinding;
import org.hibernate.metamodel.relational.Size;
@ -53,13 +52,14 @@ public class AttributeColumnRelationalState implements SimpleAttributeBinding.Co
private final String checkCondition;
private final String customWriteFragment;
private final String customReadFragment;
private final Set<String> indexes;
// todo - what about these annotations !?
private String defaultString;
private String sqlType;
private String comment;
private Set<String> uniqueKeys = new HashSet<String>();
private Set<String> indexes = new HashSet<String>();
public AttributeColumnRelationalState(MappedAttribute attribute, MetadataImpl meta) {
ColumnValues columnValues = attribute.getColumnValues();
@ -68,24 +68,14 @@ public class AttributeColumnRelationalState implements SimpleAttributeBinding.Co
unique = columnValues.isUnique();
nullable = columnValues.isNullable();
size = createSize( columnValues.getLength(), columnValues.getScale(), columnValues.getPrecision() );
List<AnnotationInstance> checkAnnotations = attribute.annotations( HibernateDotNames.CHECK );
if ( checkAnnotations.size() > 1 ) {
throw new AssertionFailure( "There cannot be more than one @Check annotation per mapped attribute" );
}
if ( checkAnnotations.size() == 1 ) {
checkCondition = checkAnnotations.get( 0 ).value( "constraints" ).toString();
}
else {
checkCondition = null;
}
checkCondition = parseCheckAnnotation( attribute );
indexes = parseIndexAnnotation( attribute );
String[] readWrite;
List<AnnotationInstance> columnTransformerAnnotations = getAllColumnTransformerAnnotations( attribute );
readWrite = createCustomReadWrite( columnTransformerAnnotations );
customReadFragment = readWrite[0];
customWriteFragment = readWrite[1];
}
@Override
@ -161,35 +151,23 @@ public class AttributeColumnRelationalState implements SimpleAttributeBinding.Co
return size;
}
private List<AnnotationInstance> getAllColumnTransformerAnnotations(MappedAttribute attribute) {
List<AnnotationInstance> allColumnTransformerAnnotations = new ArrayList<AnnotationInstance>();
// not quite sure about the usefulness of @ColumnTransformers (HF)
List<AnnotationInstance> columnTransformersAnnotations = attribute.annotations( HibernateDotNames.COLUMN_TRANSFORMERS );
if ( columnTransformersAnnotations.size() > 1 ) {
throw new AssertionFailure(
"There cannot be more than one @ColumnTransformers annotation per mapped attribute"
);
}
if ( columnTransformersAnnotations.size() == 1 ) {
AnnotationInstance columnTransformersAnnotations = attribute.annotations( HibernateDotNames.COLUMN_TRANSFORMERS );
if ( columnTransformersAnnotations != null ) {
AnnotationInstance[] annotationInstances = allColumnTransformerAnnotations.get( 0 ).value().asNestedArray();
allColumnTransformerAnnotations.addAll( Arrays.asList( annotationInstances ) );
}
List<AnnotationInstance> columnTransformerAnnotations = attribute.annotations( HibernateDotNames.COLUMN_TRANSFORMER );
if ( columnTransformerAnnotations.size() > 1 ) {
throw new AssertionFailure(
"There cannot be more than one @ColumnTransformer annotation per mapped attribute"
);
}
if ( columnTransformerAnnotations.size() == 1 ) {
allColumnTransformerAnnotations.add( columnTransformerAnnotations.get( 0 ) );
AnnotationInstance columnTransformerAnnotation = attribute.annotations( HibernateDotNames.COLUMN_TRANSFORMER );
if ( columnTransformerAnnotation != null ) {
allColumnTransformerAnnotations.add( columnTransformerAnnotation );
}
return allColumnTransformerAnnotations;
}
private String[] createCustomReadWrite(List<AnnotationInstance> columnTransformerAnnotations) {
String[] readWrite = new String[2];
@ -215,6 +193,25 @@ public class AttributeColumnRelationalState implements SimpleAttributeBinding.Co
}
return readWrite;
}
private String parseCheckAnnotation(MappedAttribute attribute) {
String checkCondition = null;
AnnotationInstance checkAnnotation = attribute.annotations( HibernateDotNames.CHECK );
if ( checkAnnotation != null ) {
checkCondition = checkAnnotation.value( "constraints" ).toString();
}
return checkCondition;
}
private Set<String> parseIndexAnnotation(MappedAttribute attribute) {
Set<String> indexNames = new HashSet<String>();
AnnotationInstance indexAnnotation = attribute.annotations( HibernateDotNames.INDEX );
if ( indexAnnotation != null ) {
String indexName = indexAnnotation.value( "name" ).toString();
indexNames.add( indexName );
}
return indexNames;
}
}