HHH-4553 - Hibernate doesn't support official JPA2 escape char for table name

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18148 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Steve Ebersole 2009-12-06 22:20:58 +00:00
parent ecb103cf55
commit a2bf14ae7c
23 changed files with 880 additions and 217 deletions

View File

@ -395,6 +395,7 @@ public final class AnnotationBinder {
idGen.addParam( org.hibernate.id.SequenceGenerator.SEQUENCE, seqGen.sequenceName() );
}
//FIXME: work on initialValue() through SequenceGenerator.PARAMETERS
// steve : or just use o.h.id.enhanced.SequenceStyleGenerator
if ( seqGen.initialValue() != 1 ) {
log.warn(
"Hibernate does not support SequenceGenerator.initialValue()"
@ -485,7 +486,7 @@ public final class AnnotationBinder {
String table = ""; //might be no @Table annotation on the annotated class
String catalog = "";
String discrimValue = null;
List<String[]> uniqueConstraints = new ArrayList<String[]>();
List<UniqueConstraintHolder> uniqueConstraints = new ArrayList<UniqueConstraintHolder>();
Ejb3DiscriminatorColumn discriminatorColumn = null;
Ejb3JoinColumn[] inheritanceJoinedColumns = null;
@ -494,7 +495,7 @@ public final class AnnotationBinder {
table = tabAnn.name();
schema = tabAnn.schema();
catalog = tabAnn.catalog();
uniqueConstraints = TableBinder.buildUniqueConstraints( tabAnn.uniqueConstraints() );
uniqueConstraints = TableBinder.buildUniqueConstraintHolders( tabAnn.uniqueConstraints() );
}
final boolean hasJoinedColumns = inheritanceState.hasParents
&& InheritanceType.JOINED.equals( inheritanceState.type );

View File

@ -85,6 +85,7 @@ import org.hibernate.mapping.UniqueKey;
import org.hibernate.util.JoinedIterator;
import org.hibernate.util.ReflectHelper;
import org.hibernate.util.StringHelper;
import org.hibernate.util.CollectionHelper;
/**
* Similar to the {@link Configuration} object but handles EJB3 and Hibernate
@ -121,7 +122,8 @@ public class AnnotationConfiguration extends Configuration {
private Set<String> defaultSqlResulSetMappingNames;
private Set<String> defaultNamedGenerators;
private Map<String, Properties> generatorTables;
private Map<Table, List<String[]>> tableUniqueConstraints;
private Map<Table, List<UniqueConstraintHolder>> uniqueConstraintHoldersByTable;
// private Map<Table, List<String[]>> tableUniqueConstraints;
private Map<String, String> mappedByResolver;
private Map<String, String> propertyRefResolver;
private Map<String, AnyMetaDef> anyMetaDefs;
@ -249,7 +251,7 @@ public class AnnotationConfiguration extends Configuration {
defaultNamedNativeQueryNames = new HashSet<String>();
defaultSqlResulSetMappingNames = new HashSet<String>();
defaultNamedGenerators = new HashSet<String>();
tableUniqueConstraints = new HashMap<Table, List<String[]>>();
uniqueConstraintHoldersByTable = new HashMap<Table, List<UniqueConstraintHolder>>();
mappedByResolver = new HashMap<String, String>();
propertyRefResolver = new HashMap<String, String>();
annotatedClasses = new ArrayList<XClass>();
@ -358,19 +360,19 @@ public class AnnotationConfiguration extends Configuration {
//the exception was not recoverable after all
throw ( RuntimeException ) e.getCause();
}
Iterator tables = tableUniqueConstraints.entrySet().iterator();
Table table;
Map.Entry entry;
String keyName;
int uniqueIndexPerTable;
Iterator<Map.Entry<Table,List<UniqueConstraintHolder>>> tables = uniqueConstraintHoldersByTable.entrySet().iterator();
while ( tables.hasNext() ) {
entry = ( Map.Entry ) tables.next();
table = ( Table ) entry.getKey();
List<String[]> uniqueConstraints = ( List<String[]> ) entry.getValue();
uniqueIndexPerTable = 0;
for ( String[] columnNames : uniqueConstraints ) {
keyName = "key" + uniqueIndexPerTable++;
buildUniqueKeyFromColumnNames( columnNames, table, keyName );
final Map.Entry<Table,List<UniqueConstraintHolder>> entry = tables.next();
final Table table = entry.getKey();
final List<UniqueConstraintHolder> uniqueConstraints = entry.getValue();
int uniqueIndexPerTable = 0;
for ( UniqueConstraintHolder holder : uniqueConstraints ) {
uniqueIndexPerTable++;
final String keyName = StringHelper.isEmpty( holder.getName() )
? "key" + uniqueIndexPerTable
: holder.getName();
buildUniqueKeyFromColumnNames( table, keyName, holder.getColumns() );
}
}
applyConstraintsToDDL();
@ -621,23 +623,26 @@ public class AnnotationConfiguration extends Configuration {
}
}
private void buildUniqueKeyFromColumnNames(String[] columnNames, Table table, String keyName) {
private void buildUniqueKeyFromColumnNames(Table table, String keyName, String[] columnNames) {
ExtendedMappings mappings = createExtendedMappings();
keyName = mappings.getObjectNameNormalizer().normalizeIdentifierQuoting( keyName );
UniqueKey uc;
int size = columnNames.length;
Column[] columns = new Column[size];
Set<Column> unbound = new HashSet<Column>();
Set<Column> unboundNoLogical = new HashSet<Column>();
ExtendedMappings mappings = createExtendedMappings();
for ( int index = 0; index < size; index++ ) {
String columnName;
final String logicalColumnName = mappings.getObjectNameNormalizer()
.normalizeIdentifierQuoting( columnNames[index] );
try {
columnName = mappings.getPhysicalColumnName( columnNames[index], table );
final String columnName = mappings.getPhysicalColumnName( logicalColumnName, table );
columns[index] = new Column( columnName );
unbound.add( columns[index] );
//column equals and hashcode is based on column name
}
catch ( MappingException e ) {
unboundNoLogical.add( new Column( columnNames[index] ) );
unboundNoLogical.add( new Column( logicalColumnName ) );
}
}
for ( Column column : columns ) {
@ -1258,17 +1263,69 @@ public class AnnotationConfiguration extends Configuration {
return type;
}
/**
* {@inheritDoc}
*/
public Map<Table, List<String[]>> getTableUniqueConstraints() {
return tableUniqueConstraints;
final Map<Table, List<String[]>> deprecatedStructure = new HashMap<Table, List<String[]>>(
CollectionHelper.determineProperSizing( getUniqueConstraintHoldersByTable() ),
CollectionHelper.LOAD_FACTOR
);
for ( Map.Entry<Table, List<UniqueConstraintHolder>> entry : getUniqueConstraintHoldersByTable().entrySet() ) {
List<String[]> columnsPerConstraint = new ArrayList<String[]>(
CollectionHelper.determineProperSizing( entry.getValue().size() )
);
deprecatedStructure.put( entry.getKey(), columnsPerConstraint );
for ( UniqueConstraintHolder holder : entry.getValue() ) {
columnsPerConstraint.add( holder.getColumns() );
}
}
return deprecatedStructure;
}
/**
* {@inheritDoc}
*/
public Map<Table, List<UniqueConstraintHolder>> getUniqueConstraintHoldersByTable() {
return uniqueConstraintHoldersByTable;
}
/**
* {@inheritDoc}
*/
@SuppressWarnings({ "unchecked" })
public void addUniqueConstraints(Table table, List uniqueConstraints) {
List oldConstraints = tableUniqueConstraints.get( table );
if ( oldConstraints == null ) {
oldConstraints = new ArrayList();
tableUniqueConstraints.put( table, oldConstraints );
List<UniqueConstraintHolder> constraintHolders = new ArrayList<UniqueConstraintHolder>(
CollectionHelper.determineProperSizing( uniqueConstraints.size() )
);
int keyNameBase = determineCurrentNumberOfUniqueConstraintHolders( table );
for ( String[] columns : (List<String[]>)uniqueConstraints ) {
final String keyName = "key" + keyNameBase++;
constraintHolders.add(
new UniqueConstraintHolder().setName( keyName ).setColumns( columns )
);
}
oldConstraints.addAll( uniqueConstraints );
addUniqueConstraintHolders( table, constraintHolders );
}
private int determineCurrentNumberOfUniqueConstraintHolders(Table table) {
List currentHolders = getUniqueConstraintHoldersByTable().get( table );
return currentHolders == null
? 0
: currentHolders.size();
}
/**
* {@inheritDoc}
*/
public void addUniqueConstraintHolders(Table table, List<UniqueConstraintHolder> uniqueConstraintHolders) {
List<UniqueConstraintHolder> holderList = getUniqueConstraintHoldersByTable().get( table );
if ( holderList == null ) {
holderList = new ArrayList<UniqueConstraintHolder>();
getUniqueConstraintHoldersByTable().put( table, holderList );
}
holderList.addAll( uniqueConstraintHolders );
}
public void addMappedBy(String entityName, String propertyName, String inversePropertyName) {

View File

@ -27,8 +27,6 @@ import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.persistence.MappedSuperclass;
import org.hibernate.AnnotationException;
import org.hibernate.MappingException;
import org.hibernate.annotations.AnyMetaDef;
@ -134,10 +132,22 @@ public interface ExtendedMappings extends Mappings {
*/
public AnnotatedClassType addClassType(XClass clazz);
/**
* @deprecated Use {@link #getUniqueConstraintHoldersByTable} instead
*/
@SuppressWarnings({ "JavaDoc" })
public Map<Table, List<String[]>> getTableUniqueConstraints();
public Map<Table, List<UniqueConstraintHolder>> getUniqueConstraintHoldersByTable();
/**
* @deprecated Use {@link #addUniqueConstraintHolders} instead
*/
@SuppressWarnings({ "JavaDoc" })
public void addUniqueConstraints(Table table, List uniqueConstraints);
public void addUniqueConstraintHolders(Table table, List<UniqueConstraintHolder> uniqueConstraintHolders);
public void addMappedBy(String entityName, String propertyName, String inversePropertyName);
public String getFromMappedBy(String entityName, String propertyName);

View File

@ -0,0 +1,55 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by
* third-party contributors as indicated by either @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.cfg;
/**
* {@link javax.persistence.UniqueConstraint} annotations are handled via second pass. I do not
* understand the reasons why at this time, so here I use a holder object to hold the information
* needed to create the unique constraint. The ability to name it is new, and so the code used to
* simply keep this as a String array (the column names).
*
* @author Steve Ebersole
*/
public class UniqueConstraintHolder {
private String name;
private String[] columns;
public String getName() {
return name;
}
public UniqueConstraintHolder setName(String name) {
this.name = name;
return this;
}
public String[] getColumns() {
return columns;
}
public UniqueConstraintHolder setColumns(String[] columns) {
this.columns = columns;
return this;
}
}

View File

@ -23,7 +23,6 @@
*/
package org.hibernate.cfg.annotations;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@ -34,7 +33,6 @@ import javax.persistence.JoinTable;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.SecondaryTable;
import javax.persistence.SecondaryTables;
import javax.persistence.UniqueConstraint;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
@ -68,6 +66,10 @@ import org.hibernate.cfg.Ejb3JoinColumn;
import org.hibernate.cfg.ExtendedMappings;
import org.hibernate.cfg.InheritanceState;
import org.hibernate.cfg.PropertyHolder;
import org.hibernate.cfg.ObjectNameSource;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.cfg.UniqueConstraintHolder;
import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.FilterDefinition;
import org.hibernate.engine.Versioning;
@ -81,6 +83,7 @@ import org.hibernate.mapping.TableOwner;
import org.hibernate.mapping.Value;
import org.hibernate.util.ReflectHelper;
import org.hibernate.util.StringHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -292,9 +295,7 @@ public class EntityBinder {
}
if ( !inheritanceState.hasParents ) {
Iterator<Map.Entry<String, String>> iter = filters.entrySet().iterator();
while ( iter.hasNext() ) {
Map.Entry<String, String> filter = iter.next();
for ( Map.Entry<String, String> filter : filters.entrySet() ) {
String filterName = filter.getKey();
String cond = filter.getValue();
if ( BinderHelper.isDefault( cond ) ) {
@ -386,6 +387,7 @@ public class EntityBinder {
}
}
@SuppressWarnings({ "unchecked" })
public void setProxy(Proxy proxy) {
if ( proxy != null ) {
lazy = proxy.lazy();
@ -415,29 +417,58 @@ public class EntityBinder {
}
}
private String getClassTableName(String tableName) {
if ( StringHelper.isEmpty( tableName ) ) {
return mappings.getNamingStrategy().classToTableName( name );
private static class EntityTableObjectNameSource implements ObjectNameSource {
private final String explicitName;
private final String logicalName;
private EntityTableObjectNameSource(String explicitName, String entityName) {
this.explicitName = explicitName;
this.logicalName = StringHelper.isNotEmpty( explicitName )
? explicitName
: StringHelper.unqualify( entityName );
}
else {
return mappings.getNamingStrategy().tableName( tableName );
public String getExplicitName() {
return explicitName;
}
public String getLogicalName() {
return logicalName;
}
}
private static class EntityTableNamingStrategyHelper implements ObjectNameNormalizer.NamingStrategyHelper {
private final String entityName;
private EntityTableNamingStrategyHelper(String entityName) {
this.entityName = entityName;
}
public String determineImplicitName(NamingStrategy strategy) {
return strategy.classToTableName( entityName );
}
public String handleExplicitName(NamingStrategy strategy, String name) {
return strategy.tableName( name );
}
}
public void bindTable(
String schema, String catalog,
String tableName, List uniqueConstraints,
String constraints, Table denormalizedSuperclassTable
) {
String logicalName = StringHelper.isNotEmpty( tableName ) ?
tableName :
StringHelper.unqualify( name );
Table table = TableBinder.fillTable(
schema, catalog,
getClassTableName( tableName ),
logicalName,
persistentClass.isAbstract(), uniqueConstraints, constraints,
denormalizedSuperclassTable, mappings
String tableName, List<UniqueConstraintHolder> uniqueConstraints,
String constraints, Table denormalizedSuperclassTable) {
EntityTableObjectNameSource tableNameContext = new EntityTableObjectNameSource( tableName, name );
EntityTableNamingStrategyHelper namingStrategyHelper = new EntityTableNamingStrategyHelper( name );
final Table table = TableBinder.buildAndFillTable(
schema,
catalog,
tableNameContext,
namingStrategyHelper,
persistentClass.isAbstract(),
uniqueConstraints,
constraints,
denormalizedSuperclassTable,
mappings
);
if ( persistentClass instanceof TableOwner ) {
@ -592,68 +623,89 @@ public class EntityBinder {
return addJoin( null, joinTable, holder, noDelayInPkColumnCreation );
}
/**
* A non null propertyHolder means than we process the Pk creation without delay
*/
private static class SecondaryTableNameSource implements ObjectNameSource {
// always has an explicit name
private final String explicitName;
private SecondaryTableNameSource(String explicitName) {
this.explicitName = explicitName;
}
public String getExplicitName() {
return explicitName;
}
public String getLogicalName() {
return explicitName;
}
}
private static class SecondaryTableNamingStrategyHelper implements ObjectNameNormalizer.NamingStrategyHelper {
public String determineImplicitName(NamingStrategy strategy) {
// todo : throw an error?
return null;
}
public String handleExplicitName(NamingStrategy strategy, String name) {
return strategy.tableName( name );
}
}
private static SecondaryTableNamingStrategyHelper SEC_TBL_NS_HELPER = new SecondaryTableNamingStrategyHelper();
private Join addJoin(
SecondaryTable secondaryTable, JoinTable joinTable, PropertyHolder propertyHolder,
boolean noDelayInPkColumnCreation
) {
SecondaryTable secondaryTable,
JoinTable joinTable,
PropertyHolder propertyHolder,
boolean noDelayInPkColumnCreation) {
// A non null propertyHolder means than we process the Pk creation without delay
Join join = new Join();
join.setPersistentClass( persistentClass );
String schema;
String catalog;
String table;
String realTable;
UniqueConstraint[] uniqueConstraintsAnn;
final String schema;
final String catalog;
final SecondaryTableNameSource secondaryTableNameContext;
final Object joinColumns;
final List<UniqueConstraintHolder> uniqueConstraintHolders;
if ( secondaryTable != null ) {
schema = secondaryTable.schema();
catalog = secondaryTable.catalog();
table = secondaryTable.name();
realTable = mappings.getNamingStrategy().tableName( table ); //always an explicit table name
uniqueConstraintsAnn = secondaryTable.uniqueConstraints();
secondaryTableNameContext = new SecondaryTableNameSource( secondaryTable.name() );
joinColumns = secondaryTable.pkJoinColumns();
uniqueConstraintHolders = TableBinder.buildUniqueConstraintHolders( secondaryTable.uniqueConstraints() );
}
else if ( joinTable != null ) {
schema = joinTable.schema();
catalog = joinTable.catalog();
table = joinTable.name();
realTable = mappings.getNamingStrategy().tableName( table ); //always an explicit table name
uniqueConstraintsAnn = joinTable.uniqueConstraints();
secondaryTableNameContext = new SecondaryTableNameSource( joinTable.name() );
joinColumns = joinTable.joinColumns();
uniqueConstraintHolders = TableBinder.buildUniqueConstraintHolders( joinTable.uniqueConstraints() );
}
else {
throw new AssertionFailure( "Both JoinTable and SecondaryTable are null" );
}
List uniqueConstraints = new ArrayList( uniqueConstraintsAnn == null ?
0 :
uniqueConstraintsAnn.length );
if ( uniqueConstraintsAnn != null && uniqueConstraintsAnn.length != 0 ) {
for (UniqueConstraint uc : uniqueConstraintsAnn) {
uniqueConstraints.add( uc.columnNames() );
}
}
Table tableMapping = TableBinder.fillTable(
final Table table = TableBinder.buildAndFillTable(
schema,
catalog,
realTable,
table, false, uniqueConstraints, null, null, mappings
secondaryTableNameContext,
SEC_TBL_NS_HELPER,
false,
uniqueConstraintHolders,
null,
null,
mappings
);
//no check constraints available on joins
join.setTable( tableMapping );
join.setTable( table );
//somehow keep joins() for later.
//Has to do the work later because it needs persistentClass id!
Object joinColumns = null;
//get the appropriate pk columns
if ( secondaryTable != null ) {
joinColumns = secondaryTable.pkJoinColumns();
}
else if ( joinTable != null ) {
joinColumns = joinTable.joinColumns();
}
log.info(
"Adding secondary table to entity {} -> {}", persistentClass.getEntityName(), join.getTable().getName()
);
org.hibernate.annotations.Table matchingTable = findMatchingComplimentTableAnnotation( join );
if ( matchingTable != null ) {
join.setSequentialSelect( FetchMode.JOIN != matchingTable.fetch() );
@ -689,8 +741,8 @@ public class EntityBinder {
createPrimaryColumnsToSecondaryTable( joinColumns, propertyHolder, join );
}
else {
secondaryTables.put( realTable, join );
secondaryTableJoins.put( realTable, joinColumns );
secondaryTables.put( table.getQuotedName(), join );
secondaryTableJoins.put( table.getQuotedName(), joinColumns );
}
return join;
}

View File

@ -32,10 +32,15 @@ import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.annotations.Index;
import org.hibernate.util.StringHelper;
import org.hibernate.util.CollectionHelper;
import org.hibernate.cfg.BinderHelper;
import org.hibernate.cfg.Ejb3JoinColumn;
import org.hibernate.cfg.ExtendedMappings;
import org.hibernate.cfg.IndexOrUniqueKeySecondPass;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.cfg.ObjectNameSource;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.cfg.UniqueConstraintHolder;
import org.hibernate.mapping.Collection;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.DependantValue;
@ -62,7 +67,8 @@ public class TableBinder {
private String catalog;
private String name;
private boolean isAbstract;
private List<String[]> uniqueConstraints;
private List<UniqueConstraintHolder> uniqueConstraints;
// private List<String[]> uniqueConstraints;
String constraints;
Table denormalizedSuperTable;
ExtendedMappings mappings;
@ -93,7 +99,7 @@ public class TableBinder {
}
public void setUniqueConstraints(UniqueConstraint[] uniqueConstraints) {
this.uniqueConstraints = TableBinder.buildUniqueConstraints( uniqueConstraints );
this.uniqueConstraints = TableBinder.buildUniqueConstraintHolders( uniqueConstraints );
}
public void setConstraints(String constraints) {
@ -108,45 +114,150 @@ public class TableBinder {
this.mappings = mappings;
}
private static class AssociationTableNameSource implements ObjectNameSource {
private final String explicitName;
private final String logicalName;
private AssociationTableNameSource(String explicitName, String logicalName) {
this.explicitName = explicitName;
this.logicalName = logicalName;
}
public String getExplicitName() {
return explicitName;
}
public String getLogicalName() {
return logicalName;
}
}
// only bind association table currently
public Table bind() {
//logicalName only accurate for assoc table...
String unquotedOwnerTable = StringHelper.unquote( ownerEntityTable );
String unquotedAssocTable = StringHelper.unquote( associatedEntityTable );
final String unquotedOwnerTable = StringHelper.unquote( ownerEntityTable );
final String unquotedAssocTable = StringHelper.unquote( associatedEntityTable );
String logicalName = mappings.getNamingStrategy()
.logicalCollectionTableName(
name,
final ObjectNameSource nameSource = buildNameContext( unquotedOwnerTable, unquotedAssocTable );
final boolean ownerEntityTableQuoted = StringHelper.isQuoted( ownerEntityTable );
final boolean associatedEntityTableQuoted = StringHelper.isQuoted( associatedEntityTable );
final ObjectNameNormalizer.NamingStrategyHelper namingStrategyHelper = new ObjectNameNormalizer.NamingStrategyHelper() {
public String determineImplicitName(NamingStrategy strategy) {
final String strategyResult = strategy.collectionTableName(
ownerEntity,
unquotedOwnerTable,
associatedEntity,
unquotedAssocTable,
propertyName );
if ( StringHelper.isQuoted( ownerEntityTable ) || StringHelper.isQuoted( associatedEntityTable ) ) {
logicalName = StringHelper.quote( logicalName );
}
String extendedName;
if ( name != null ) {
extendedName = mappings.getNamingStrategy().tableName( name );
}
else {
extendedName = mappings.getNamingStrategy()
.collectionTableName(
ownerEntity,
unquotedOwnerTable,
associatedEntity,
unquotedAssocTable,
propertyName
);
if ( StringHelper.isQuoted( ownerEntityTable ) || StringHelper.isQuoted( associatedEntityTable ) ) {
extendedName = StringHelper.quote( extendedName );
propertyName
);
return ownerEntityTableQuoted || associatedEntityTableQuoted
? StringHelper.quote( strategyResult )
: strategyResult;
}
}
return fillTable(
schema, catalog,
extendedName, logicalName, isAbstract, uniqueConstraints, constraints,
denormalizedSuperTable, mappings
public String handleExplicitName(NamingStrategy strategy, String name) {
return strategy.tableName( name );
}
};
return buildAndFillTable(
schema,
catalog,
nameSource,
namingStrategyHelper,
isAbstract,
uniqueConstraints,
constraints,
denormalizedSuperTable,
mappings
);
}
private ObjectNameSource buildNameContext(String unquotedOwnerTable, String unquotedAssocTable) {
String logicalName = mappings.getNamingStrategy().logicalCollectionTableName(
name,
unquotedOwnerTable,
unquotedAssocTable,
propertyName
);
if ( StringHelper.isQuoted( ownerEntityTable ) || StringHelper.isQuoted( associatedEntityTable ) ) {
logicalName = StringHelper.quote( logicalName );
}
return new AssociationTableNameSource( name, logicalName );
}
public static Table buildAndFillTable(
String schema,
String catalog,
ObjectNameSource nameSource,
ObjectNameNormalizer.NamingStrategyHelper namingStrategyHelper,
boolean isAbstract,
List<UniqueConstraintHolder> uniqueConstraints,
String constraints,
Table denormalizedSuperTable,
ExtendedMappings mappings) {
schema = BinderHelper.isDefault( schema ) ? mappings.getSchemaName() : schema;
catalog = BinderHelper.isDefault( catalog ) ? mappings.getCatalogName() : catalog;
String realTableName = mappings.getObjectNameNormalizer().normalizeDatabaseIdentifier(
nameSource.getExplicitName(),
namingStrategyHelper
);
final Table table;
if ( denormalizedSuperTable != null ) {
table = mappings.addDenormalizedTable(
schema,
catalog,
realTableName,
isAbstract,
null, // subselect
denormalizedSuperTable
);
}
else {
table = mappings.addTable(
schema,
catalog,
realTableName,
null, // subselect
isAbstract
);
}
if ( uniqueConstraints != null && uniqueConstraints.size() > 0 ) {
mappings.addUniqueConstraintHolders( table, uniqueConstraints );
}
if ( constraints != null ) table.addCheckConstraint( constraints );
// logicalName is null if we are in the second pass
final String logicalName = nameSource.getLogicalName();
if ( logicalName != null ) {
mappings.addTableBinding( schema, catalog, logicalName, realTableName, denormalizedSuperTable );
}
return table;
}
/**
*
* @param schema
* @param catalog
* @param realTableName
* @param logicalName
* @param isAbstract
* @param uniqueConstraints
* @param constraints
* @param denormalizedSuperTable
* @param mappings
* @return
*
* @deprecated Use {@link #buildAndFillTable} instead.
*/
@SuppressWarnings({ "JavaDoc" })
public static Table fillTable(
String schema, String catalog, String realTableName, String logicalName, boolean isAbstract,
List uniqueConstraints, String constraints, Table denormalizedSuperTable, ExtendedMappings mappings
@ -195,8 +306,9 @@ public class TableBinder {
associatedClass = destinationEntity;
}
else {
associatedClass = columns[0].getPropertyHolder() == null ? null : columns[0].getPropertyHolder()
.getPersistentClass();
associatedClass = columns[0].getPropertyHolder() == null
? null
: columns[0].getPropertyHolder().getPersistentClass();
}
final String mappedByProperty = columns[0].getMappedBy();
if ( StringHelper.isNotEmpty( mappedByProperty ) ) {
@ -235,7 +347,7 @@ public class TableBinder {
*/
Iterator idColumns;
if ( referencedEntity instanceof JoinedSubclass ) {
idColumns = ( (JoinedSubclass) referencedEntity ).getKey().getColumnIterator();
idColumns = referencedEntity.getKey().getColumnIterator();
}
else {
idColumns = referencedEntity.getIdentifier().getColumnIterator();
@ -345,7 +457,7 @@ public class TableBinder {
}
}
value.createForeignKey();
if ( unique == true ) {
if ( unique ) {
createUniqueConstraint( value );
}
}
@ -384,6 +496,10 @@ public class TableBinder {
}
}
/**
* @deprecated Use {@link #buildUniqueConstraintHolders} instead
*/
@SuppressWarnings({ "JavaDoc" })
public static List<String[]> buildUniqueConstraints(UniqueConstraint[] constraintsArray) {
List<String[]> result = new ArrayList<String[]>();
if ( constraintsArray.length != 0 ) {
@ -394,6 +510,32 @@ public class TableBinder {
return result;
}
/**
* Build a list of {@link org.hibernate.cfg.UniqueConstraintHolder} instances given a list of
* {@link UniqueConstraint} annotations.
*
* @param annotations The {@link UniqueConstraint} annotations.
*
* @return The built {@link org.hibernate.cfg.UniqueConstraintHolder} instances.
*/
public static List<UniqueConstraintHolder> buildUniqueConstraintHolders(UniqueConstraint[] annotations) {
List<UniqueConstraintHolder> result;
if ( annotations == null || annotations.length == 0 ) {
result = java.util.Collections.emptyList();
}
else {
result = new ArrayList<UniqueConstraintHolder>( CollectionHelper.determineProperSizing( annotations.length ) );
for ( UniqueConstraint uc : annotations ) {
result.add(
new UniqueConstraintHolder()
.setName( uc.name() )
.setColumns( uc.columnNames() )
);
}
}
return result;
}
public void setDefaultName(
String ownerEntity, String ownerEntityTable, String associatedEntity, String associatedEntityTable,
String propertyName

View File

@ -68,7 +68,6 @@ import org.hibernate.SessionFactory;
import org.hibernate.SessionFactoryObserver;
import org.hibernate.DuplicateMappingException;
import org.hibernate.tuple.entity.EntityTuplizerFactory;
import org.hibernate.tuple.component.ComponentTuplizerFactory;
import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.function.SQLFunction;
@ -2456,6 +2455,8 @@ public class Configuration implements Serializable {
Table table = ( Table ) tables.get( key );
if ( table == null ) {
schema = getObjectNameNormalizer().normalizeIdentifierQuoting( schema );
catalog = getObjectNameNormalizer().normalizeIdentifierQuoting( catalog );
table = new Table();
table.setAbstract( isAbstract );
table.setName( name );
@ -2485,6 +2486,9 @@ public class Configuration implements Serializable {
throw new DuplicateMappingException( "table", name );
}
schema = getObjectNameNormalizer().normalizeIdentifierQuoting( schema );
catalog = getObjectNameNormalizer().normalizeIdentifierQuoting( catalog );
Table table = new DenormalizedTable( includedTable );
table.setAbstract( isAbstract );
table.setName( name );
@ -2786,5 +2790,22 @@ public class Configuration implements Serializable {
public MappedSuperclass getMappedSuperclass(Class type) {
return (MappedSuperclass) mappedSuperclasses.get( type );
}
public ObjectNameNormalizer getObjectNameNormalizer() {
return normalizer;
}
}
final ObjectNameNormalizer normalizer = new ObjectNameNormalizerImpl();
final class ObjectNameNormalizerImpl extends ObjectNameNormalizer implements Serializable {
public boolean isUseQuotedIdentifiersGlobally() {
String setting = (String) properties.get( Environment.GLOBALLY_QUOTED_IDENTIFIERS );
return setting != null && Boolean.valueOf( setting ).booleanValue();
}
public NamingStrategy getNamingStrategy() {
return namingStrategy;
}
}
}

View File

@ -501,6 +501,11 @@ public final class Environment {
*/
public static final String JACC_CONTEXTID = "hibernate.jacc_context_id";
/**
* Should all database identifiers be quoted.
*/
public static final String GLOBALLY_QUOTED_IDENTIFIERS = "hibernate.globally_quoted_identifiers";
/**
* Enable nullability checking.
* Raises an exception if a property marked as not-null is null.

View File

@ -2045,15 +2045,24 @@ public final class HbmBinder {
// GENERATOR
Element subnode = node.element( "generator" );
if ( subnode != null ) {
model.setIdentifierGeneratorStrategy( subnode.attributeValue( "class" ) );
final String generatorClass = subnode.attributeValue( "class" );
model.setIdentifierGeneratorStrategy( generatorClass );
Properties params = new Properties();
// YUCK! but cannot think of a clean way to do this given the string-config based scheme
params.put( PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER, mappings.getObjectNameNormalizer() );
if ( mappings.getSchemaName() != null ) {
params.setProperty( PersistentIdentifierGenerator.SCHEMA, mappings.getSchemaName() );
params.setProperty(
PersistentIdentifierGenerator.SCHEMA,
mappings.getObjectNameNormalizer().normalizeIdentifierQuoting( mappings.getSchemaName() )
);
}
if ( mappings.getCatalogName() != null ) {
params.setProperty( PersistentIdentifierGenerator.CATALOG, mappings.getCatalogName() );
params.setProperty(
PersistentIdentifierGenerator.CATALOG,
mappings.getObjectNameNormalizer().normalizeIdentifierQuoting( mappings.getCatalogName() )
);
}
Iterator iter = subnode.elementIterator( "param" );

View File

@ -543,4 +543,11 @@ public interface Mappings {
* @return the MappedSuperclass
*/
org.hibernate.mapping.MappedSuperclass getMappedSuperclass(Class type);
/**
* Retrieve the database identifier normalizer for this context.
*
* @return The normalizer.
*/
public ObjectNameNormalizer getObjectNameNormalizer();
}

View File

@ -0,0 +1,132 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by
* third-party contributors as indicated by either @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.cfg;
import org.hibernate.util.StringHelper;
/**
* Provides centralized normalization of how database object names are handled.
*
* @author Steve Ebersole
*/
public abstract class ObjectNameNormalizer {
/**
* Helper contract for dealing with {@link NamingStrategy} in different situations.
*/
public static interface NamingStrategyHelper {
/**
* Called when the user supplied no explicit name/identifier for the given database object.
*
* @param strategy The naming strategy in effect
*
* @return The implicit name
*/
public String determineImplicitName(NamingStrategy strategy);
/**
* Called when the user has supplied an explicit name for the database object.
*
* @param strategy The naming strategy in effect
* @param name The {@link ObjectNameNormalizer#normalizeIdentifierQuoting normalized} explicit object name.
*
* @return The strategy-handled name.
*/
public String handleExplicitName(NamingStrategy strategy, String name);
}
/**
* Performs the actual contract of normalizing a database name.
*
* @param explicitName The name the user explicitly gave for the database object.
* @param helper The {@link NamingStrategy} helper.
*
* @return The normalized identifier.
*/
public String normalizeDatabaseIdentifier(final String explicitName, NamingStrategyHelper helper) {
// apply naming strategy
if ( StringHelper.isEmpty( explicitName ) ) {
// No explicit name given, so allow the naming strategy the chance
// to determine it based on the corresponding mapped java name
final String objectName = helper.determineImplicitName( getNamingStrategy() );
// Conceivable that the naming strategy could return a quoted identifier, or
// that user enabled <delimited-identifiers/>
return normalizeIdentifierQuoting( objectName );
}
else {
// An explicit name was given:
// in some cases we allow the naming strategy to "fine tune" these, but first
// handle any quoting for consistent handling in naming strategies
String objectName = normalizeIdentifierQuoting( explicitName );
objectName = helper.handleExplicitName( getNamingStrategy(), objectName );
return normalizeIdentifierQuoting( objectName );
}
}
/**
* Allow normalizing of just the quoting aspect of identifiers. This is useful for
* schema and catalog in terms of initially making this public.
* <p/>
* This implements the rules set forth in JPA 2 (section "2.13 Naming of Database Objects") which
* states that the double-quote (") is the character which should be used to denote a <tt>quoted
* identifier</tt>. Here, we handle recognizing that and converting it to the more elegant
* bactick (`) approach used in Hibernate.. Additionally we account for applying what JPA2 terms
*
*
* @param identifier The identifier to be quoting-normalized.
* @return The identifier accounting for any quoting that need be applied.
*/
public String normalizeIdentifierQuoting(String identifier) {
if ( identifier == null ) {
return null;
}
// Convert the JPA2 specific quoting character (double quote) to Hibernate's (back tick)
if ( identifier.startsWith( "\"" ) && identifier.endsWith( "\"" ) ) {
return '`' + identifier.substring( 1, identifier.length() - 1 ) + '`';
}
// If the user has requested "global" use of quoted identifiers, quote this identifier (using back ticks)
// if not already
if ( isUseQuotedIdentifiersGlobally() && ! ( identifier.startsWith( "`" ) && identifier.endsWith( "`" ) ) ) {
return '`' + identifier + '`';
}
return identifier;
}
/**
* Retrieve whether the user requested that all database identifiers be quoted.
*
* @return True if the user requested that all database identifiers be quoted, false otherwise.
*/
protected abstract boolean isUseQuotedIdentifiersGlobally();
/**
* Get the current {@link NamingStrategy}.
*
* @return The current {@link NamingStrategy}.
*/
protected abstract NamingStrategy getNamingStrategy();
}

View File

@ -0,0 +1,46 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by
* third-party contributors as indicated by either @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.cfg;
/**
* Source for database object names (identifiers).
*
* @author Steve Ebersole
*/
public interface ObjectNameSource {
/**
* Retrieve the name explicitly provided by the user.
*
* @return The explicit name.
*/
public String getExplicitName();
/**
* Retrieve the logical name for this object. Usually this is the name under which
* the "thing" is registered with the {@link Mappings}.
*
* @return The logical name.
*/
public String getLogicalName();
}

View File

@ -169,6 +169,11 @@ public class DerbyDialect extends DB2Dialect {
return sb.toString();
}
public boolean supportsVariableLimit() {
// we bind the limit and offset values directly into the sql...
return false;
}
private boolean hasForUpdateClause(int forUpdateIndex) {
return forUpdateIndex >= 0;
}

View File

@ -1466,17 +1466,21 @@ qu *
* By default, the incoming value is checked to see if its first character
* is the back-tick (`). If so, the dialect specific quoting is applied.
*
* @param column The value to be quoted.
* @param name The value to be quoted.
* @return The quoted (or unmodified, if not starting with back-tick) value.
* @see #openQuote()
* @see #closeQuote()
*/
public final String quote(String column) {
if ( column.charAt( 0 ) == '`' ) {
return openQuote() + column.substring( 1, column.length() - 1 ) + closeQuote();
public final String quote(String name) {
if ( name == null ) {
return null;
}
if ( name.charAt( 0 ) == '`' ) {
return openQuote() + name.substring( 1, name.length() - 1 ) + closeQuote();
}
else {
return column;
return name;
}
}

View File

@ -34,6 +34,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.exception.JDBCExceptionHelper;
@ -61,38 +62,55 @@ public class IncrementGenerator implements IdentifierGenerator, Configurable {
private String sql;
private Class returnClass;
public synchronized Serializable generate(SessionImplementor session, Object object)
throws HibernateException {
if (sql!=null) {
public synchronized Serializable generate(SessionImplementor session, Object object) throws HibernateException {
if ( sql != null ) {
getNext( session );
}
return IdentifierGeneratorHelper.createNumber(next++, returnClass);
return IdentifierGeneratorHelper.createNumber( next++, returnClass );
}
public void configure(Type type, Properties params, Dialect dialect)
throws MappingException {
String tableList = params.getProperty("tables");
if (tableList==null) tableList = params.getProperty(PersistentIdentifierGenerator.TABLES);
String[] tables = StringHelper.split(", ", tableList);
String column = params.getProperty("column");
if (column==null) column = params.getProperty(PersistentIdentifierGenerator.PK);
String schema = params.getProperty(PersistentIdentifierGenerator.SCHEMA);
String catalog = params.getProperty(PersistentIdentifierGenerator.CATALOG);
public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
returnClass = type.getReturnedClass();
ObjectNameNormalizer normalizer =
( ObjectNameNormalizer ) params.get( PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER );
String column = params.getProperty( "column" );
if ( column == null ) {
column = params.getProperty( PersistentIdentifierGenerator.PK );
}
column = dialect.quote( normalizer.normalizeIdentifierQuoting( column ) );
String tableList = params.getProperty( "tables" );
if ( tableList == null ) {
tableList = params.getProperty( PersistentIdentifierGenerator.TABLES );
}
String[] tables = StringHelper.split( ", ", tableList );
final String schema = dialect.quote(
normalizer.normalizeIdentifierQuoting(
params.getProperty( PersistentIdentifierGenerator.SCHEMA )
)
);
final String catalog = dialect.quote(
normalizer.normalizeIdentifierQuoting(
params.getProperty( PersistentIdentifierGenerator.CATALOG )
)
);
StringBuffer buf = new StringBuffer();
for ( int i=0; i<tables.length; i++ ) {
if (tables.length>1) {
buf.append("select ").append(column).append(" from ");
for ( int i=0; i < tables.length; i++ ) {
final String tableName = dialect.quote( normalizer.normalizeIdentifierQuoting( tables[i] ) );
if ( tables.length > 1 ) {
buf.append( "select " ).append( column ).append( " from " );
}
buf.append( Table.qualify( catalog, schema, tableName ) );
if ( i < tables.length-1 ) {
buf.append( " union " );
}
buf.append( Table.qualify( catalog, schema, tables[i] ) );
if ( i<tables.length-1) buf.append(" union ");
}
if (tables.length>1) {
buf.insert(0, "( ").append(" ) ids_");
if ( tables.length > 1 ) {
buf.insert( 0, "( " ).append( " ) ids_" );
column = "ids_." + column;
}
@ -100,9 +118,7 @@ public class IncrementGenerator implements IdentifierGenerator, Configurable {
}
private void getNext( SessionImplementor session ) {
log.debug("fetching initial value: " + sql);
log.debug( "fetching initial value: " + sql );
try {
PreparedStatement st = session.getBatcher().prepareSelectStatement(sql);
try {
@ -133,7 +149,7 @@ public class IncrementGenerator implements IdentifierGenerator, Configurable {
sqle,
"could not fetch initial value for increment generator",
sql
);
);
}
}

View File

@ -37,6 +37,7 @@ import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.jdbc.util.FormatStyle;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionImplementor;
@ -221,22 +222,41 @@ public class MultipleHiLoPerTableGenerator
}
public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
tableName = PropertiesHelper.getString(ID_TABLE, params, DEFAULT_TABLE);
pkColumnName = PropertiesHelper.getString(PK_COLUMN_NAME, params, DEFAULT_PK_COLUMN);
valueColumnName = PropertiesHelper.getString(VALUE_COLUMN_NAME, params, DEFAULT_VALUE_COLUMN);
String schemaName = params.getProperty(SCHEMA);
String catalogName = params.getProperty(CATALOG);
keySize = PropertiesHelper.getInt(PK_LENGTH_NAME, params, DEFAULT_PK_LENGTH);
String keyValue = PropertiesHelper.getString(PK_VALUE_NAME, params, params.getProperty(TABLE) );
ObjectNameNormalizer normalizer = ( ObjectNameNormalizer ) params.get( IDENTIFIER_NORMALIZER );
if ( tableName.indexOf( '.' )<0 ) {
tableName = normalizer.normalizeIdentifierQuoting( PropertiesHelper.getString( ID_TABLE, params, DEFAULT_TABLE ) );
if ( tableName.indexOf( '.' ) < 0 ) {
tableName = dialect.quote( tableName );
final String schemaName = dialect.quote(
normalizer.normalizeIdentifierQuoting( params.getProperty( SCHEMA ) )
);
final String catalogName = dialect.quote(
normalizer.normalizeIdentifierQuoting( params.getProperty( CATALOG ) )
);
tableName = Table.qualify( catalogName, schemaName, tableName );
}
else {
// if already qualified there is not much we can do in a portable manner so we pass it
// through and assume the user has set up the name correctly.
}
pkColumnName = dialect.quote(
normalizer.normalizeIdentifierQuoting(
PropertiesHelper.getString( PK_COLUMN_NAME, params, DEFAULT_PK_COLUMN )
)
);
valueColumnName = dialect.quote(
normalizer.normalizeIdentifierQuoting(
PropertiesHelper.getString( VALUE_COLUMN_NAME, params, DEFAULT_VALUE_COLUMN )
)
);
keySize = PropertiesHelper.getInt(PK_LENGTH_NAME, params, DEFAULT_PK_LENGTH);
String keyValue = PropertiesHelper.getString(PK_VALUE_NAME, params, params.getProperty(TABLE) );
query = "select " +
valueColumnName +
" from " +
dialect.appendLockHint(LockMode.UPGRADE, tableName) +
dialect.appendLockHint( LockMode.PESSIMISTIC_WRITE, tableName ) +
" where " + pkColumnName + " = '" + keyValue + "'" +
dialect.getForUpdateString();

View File

@ -68,6 +68,11 @@ public interface PersistentIdentifierGenerator extends IdentifierGenerator {
*/
public static final String CATALOG = "catalog";
/**
* The key under whcih to find the {@link org.hibernate.cfg.ObjectNameNormalizer} in the config param map.
*/
public static final String IDENTIFIER_NORMALIZER = "identifier_normalizer";
/**
* The SQL required to create the underlying database objects.
*

View File

@ -34,6 +34,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.exception.JDBCExceptionHelper;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionImplementor;
@ -53,8 +54,8 @@ import org.hibernate.util.PropertiesHelper;
* @see TableHiLoGenerator
* @author Gavin King
*/
public class SequenceGenerator implements PersistentIdentifierGenerator, Configurable {
private static final Logger log = LoggerFactory.getLogger(SequenceGenerator.class);
/**
* The sequence parameter
@ -72,20 +73,29 @@ public class SequenceGenerator implements PersistentIdentifierGenerator, Configu
private Type identifierType;
private String sql;
private static final Logger log = LoggerFactory.getLogger(SequenceGenerator.class);
public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
sequenceName = PropertiesHelper.getString(SEQUENCE, params, "hibernate_sequence");
parameters = params.getProperty(PARAMETERS);
String schemaName = params.getProperty(SCHEMA);
String catalogName = params.getProperty(CATALOG);
ObjectNameNormalizer normalizer = ( ObjectNameNormalizer ) params.get( IDENTIFIER_NORMALIZER );
sequenceName = normalizer.normalizeIdentifierQuoting(
PropertiesHelper.getString( SEQUENCE, params, "hibernate_sequence" )
);
parameters = params.getProperty( PARAMETERS );
if (sequenceName.indexOf( '.' ) < 0) {
sequenceName = Table.qualify( catalogName, schemaName, sequenceName );
if ( sequenceName.indexOf( '.' ) < 0 ) {
final String schemaName = normalizer.normalizeIdentifierQuoting( params.getProperty( SCHEMA ) );
final String catalogName = normalizer.normalizeIdentifierQuoting( params.getProperty( CATALOG ) );
sequenceName = Table.qualify(
dialect.quote( catalogName ),
dialect.quote( schemaName ),
dialect.quote( sequenceName )
);
}
else {
// if already qualified there is not much we can do in a portable manner so we pass it
// through and assume the user has set up the name correctly.
}
this.identifierType = type;
sql = dialect.getSequenceNextValString(sequenceName);
sql = dialect.getSequenceNextValString( sequenceName );
}
public Serializable generate(SessionImplementor session, Object obj)

View File

@ -36,6 +36,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.jdbc.util.FormatStyle;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.SessionImplementor;
@ -88,20 +89,33 @@ public class TableGenerator extends TransactionHelper
private String update;
public void configure(Type type, Properties params, Dialect dialect) {
ObjectNameNormalizer normalizer = ( ObjectNameNormalizer ) params.get( IDENTIFIER_NORMALIZER );
tableName = PropertiesHelper.getString(TABLE, params, DEFAULT_TABLE_NAME);
columnName = PropertiesHelper.getString(COLUMN, params, DEFAULT_COLUMN_NAME);
String schemaName = params.getProperty(SCHEMA);
String catalogName = params.getProperty(CATALOG);
if ( tableName.indexOf( '.' )<0 ) {
tableName = Table.qualify( catalogName, schemaName, tableName );
tableName = PropertiesHelper.getString( TABLE, params, DEFAULT_TABLE_NAME );
if ( tableName.indexOf( '.' ) < 0 ) {
final String schemaName = normalizer.normalizeIdentifierQuoting( params.getProperty( SCHEMA ) );
final String catalogName = normalizer.normalizeIdentifierQuoting( params.getProperty( CATALOG ) );
tableName = Table.qualify(
dialect.quote( catalogName ),
dialect.quote( schemaName ),
dialect.quote( tableName )
);
}
else {
// if already qualified there is not much we can do in a portable manner so we pass it
// through and assume the user has set up the name correctly.
}
columnName = dialect.quote(
normalizer.normalizeIdentifierQuoting(
PropertiesHelper.getString( COLUMN, params, DEFAULT_COLUMN_NAME )
)
);
query = "select " +
columnName +
" from " +
dialect.appendLockHint(LockMode.UPGRADE, tableName) +
dialect.appendLockHint(LockMode.PESSIMISTIC_WRITE, tableName) +
dialect.getForUpdateString();
update = "update " +

View File

@ -34,6 +34,7 @@ import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.id.Configurable;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.mapping.Table;
import org.hibernate.util.PropertiesHelper;
@ -160,7 +161,7 @@ public class SequenceStyleGenerator implements PersistentIdentifierGenerator, Co
this.identifierType = type;
boolean forceTableUse = PropertiesHelper.getBoolean( FORCE_TBL_PARAM, params, false );
final String sequenceName = determineSequenceName( params );
final String sequenceName = determineSequenceName( params, dialect );
final int initialValue = determineInitialValue( params );
int incrementSize = determineIncrementSize( params );
@ -190,14 +191,25 @@ public class SequenceStyleGenerator implements PersistentIdentifierGenerator, Co
* Called during {@link #configure configuration}.
*
* @param params The params supplied in the generator config (plus some standard useful extras).
* @param dialect The dialect in effect
* @return The sequence name
*/
protected String determineSequenceName(Properties params) {
protected String determineSequenceName(Properties params, Dialect dialect) {
ObjectNameNormalizer normalizer = ( ObjectNameNormalizer ) params.get( IDENTIFIER_NORMALIZER );
String sequenceName = PropertiesHelper.getString( SEQUENCE_PARAM, params, DEF_SEQUENCE_NAME );
if ( sequenceName.indexOf( '.' ) < 0 ) {
sequenceName = normalizer.normalizeIdentifierQuoting( sequenceName );
String schemaName = params.getProperty( SCHEMA );
String catalogName = params.getProperty( CATALOG );
sequenceName = Table.qualify( catalogName, schemaName, sequenceName );
sequenceName = Table.qualify(
dialect.quote( catalogName ),
dialect.quote( schemaName ),
dialect.quote( sequenceName )
);
}
else {
// if already qualified there is not much we can do in a portable manner so we pass it
// through and assume the user has set up the name correctly.
}
return sequenceName;
}
@ -210,10 +222,13 @@ public class SequenceStyleGenerator implements PersistentIdentifierGenerator, Co
* physical table</b>.
*
* @param params The params supplied in the generator config (plus some standard useful extras).
* @param dialect The dialect in effect.
* @return The value column name
*/
protected String determineValueColumnName(Properties params) {
return PropertiesHelper.getString( VALUE_COLUMN_PARAM, params, DEF_VALUE_COLUMN );
protected String determineValueColumnName(Properties params, Dialect dialect) {
ObjectNameNormalizer normalizer = ( ObjectNameNormalizer ) params.get( IDENTIFIER_NORMALIZER );
String name = PropertiesHelper.getString( VALUE_COLUMN_PARAM, params, DEF_VALUE_COLUMN );
return dialect.quote( normalizer.normalizeIdentifierQuoting( name ) );
}
/**
@ -296,7 +311,7 @@ public class SequenceStyleGenerator implements PersistentIdentifierGenerator, Co
return new SequenceStructure( dialect, sequenceName, initialValue, incrementSize );
}
else {
String valueColumnName = determineValueColumnName( params );
String valueColumnName = determineValueColumnName( params, dialect );
return new TableStructure( dialect, sequenceName, valueColumnName, initialValue, incrementSize );
}
}

View File

@ -46,8 +46,8 @@ import org.hibernate.type.Type;
import org.hibernate.dialect.Dialect;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.jdbc.util.FormatStyle;
import org.hibernate.mapping.Table;
import org.hibernate.util.PropertiesHelper;
@ -287,9 +287,9 @@ public class TableGenerator extends TransactionHelper implements PersistentIdent
public void configure(Type type, Properties params, Dialect dialect) throws MappingException {
identifierType = type;
tableName = determneGeneratorTableName( params );
segmentColumnName = determineSegmentColumnName( params );
valueColumnName = determineValueColumnName( params );
tableName = determneGeneratorTableName( params, dialect );
segmentColumnName = determineSegmentColumnName( params, dialect );
valueColumnName = determineValueColumnName( params, dialect );
segmentValue = determineSegmentValue( params );
@ -313,16 +313,27 @@ public class TableGenerator extends TransactionHelper implements PersistentIdent
*
* @see #getTableName()
* @param params The params supplied in the generator config (plus some standard useful extras).
* @param dialect The dialect in effect
* @return The table name to use.
*/
protected String determneGeneratorTableName(Properties params) {
protected String determneGeneratorTableName(Properties params, Dialect dialect) {
String name = PropertiesHelper.getString( TABLE_PARAM, params, DEF_TABLE );
boolean isGivenNameUnqualified = name.indexOf( '.' ) < 0;
if ( isGivenNameUnqualified ) {
ObjectNameNormalizer normalizer = ( ObjectNameNormalizer ) params.get( IDENTIFIER_NORMALIZER );
name = normalizer.normalizeIdentifierQuoting( name );
// if the given name is un-qualified we may neen to qualify it
String schemaName = params.getProperty( SCHEMA );
String catalogName = params.getProperty( CATALOG );
name = Table.qualify( catalogName, schemaName, name );
String schemaName = normalizer.normalizeIdentifierQuoting( params.getProperty( SCHEMA ) );
String catalogName = normalizer.normalizeIdentifierQuoting( params.getProperty( CATALOG ) );
name = Table.qualify(
dialect.quote( catalogName ),
dialect.quote( schemaName ),
dialect.quote( name)
);
}
else {
// if already qualified there is not much we can do in a portable manner so we pass it
// through and assume the user has set up the name correctly.
}
return name;
}
@ -335,10 +346,13 @@ public class TableGenerator extends TransactionHelper implements PersistentIdent
*
* @see #getSegmentColumnName()
* @param params The params supplied in the generator config (plus some standard useful extras).
* @param dialect The dialect in effect
* @return The name of the segment column
*/
protected String determineSegmentColumnName(Properties params) {
return PropertiesHelper.getString( SEGMENT_COLUMN_PARAM, params, DEF_SEGMENT_COLUMN );
protected String determineSegmentColumnName(Properties params, Dialect dialect) {
ObjectNameNormalizer normalizer = ( ObjectNameNormalizer ) params.get( IDENTIFIER_NORMALIZER );
String name = PropertiesHelper.getString( SEGMENT_COLUMN_PARAM, params, DEF_SEGMENT_COLUMN );
return dialect.quote( normalizer.normalizeIdentifierQuoting( name ) );
}
/**
@ -348,10 +362,13 @@ public class TableGenerator extends TransactionHelper implements PersistentIdent
*
* @see #getValueColumnName()
* @param params The params supplied in the generator config (plus some standard useful extras).
* @param dialect The dialect in effect
* @return The name of the value column
*/
protected String determineValueColumnName(Properties params) {
return PropertiesHelper.getString( VALUE_COLUMN_PARAM, params, DEF_VALUE_COLUMN );
protected String determineValueColumnName(Properties params, Dialect dialect) {
ObjectNameNormalizer normalizer = ( ObjectNameNormalizer ) params.get( IDENTIFIER_NORMALIZER );
String name = PropertiesHelper.getString( VALUE_COLUMN_PARAM, params, DEF_VALUE_COLUMN );
return dialect.quote( normalizer.normalizeIdentifierQuoting( name ) );
}
/**

View File

@ -69,7 +69,7 @@ public class TableStructure extends TransactionHelper implements DatabaseStructu
this.valueColumnName = valueColumnName;
selectQuery = "select " + valueColumnName + " as id_val" +
" from " + dialect.appendLockHint( LockMode.UPGRADE, tableName ) +
" from " + dialect.appendLockHint( LockMode.PESSIMISTIC_WRITE, tableName ) +
dialect.getForUpdateString();
updateQuery = "update " + tableName +

View File

@ -11,8 +11,11 @@ import org.hibernate.id.enhanced.SequenceStyleGenerator;
import org.hibernate.id.enhanced.SequenceStructure;
import org.hibernate.id.enhanced.OptimizerFactory;
import org.hibernate.id.enhanced.TableStructure;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.Hibernate;
import org.hibernate.MappingException;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.cfg.NamingStrategy;
/**
* Tests that SequenceStyleGenerator configures itself as expected
@ -34,7 +37,7 @@ public class SequenceStyleConfigUnitTest extends UnitTestCase {
*/
public void testDefaultedSequenceBackedConfiguration() {
Dialect dialect = new SequenceDialect();
Properties props = new Properties();
Properties props = buildGeneratorPropertiesBase();
SequenceStyleGenerator generator = new SequenceStyleGenerator();
generator.configure( Hibernate.LONG, props, dialect );
@ -43,12 +46,29 @@ public class SequenceStyleConfigUnitTest extends UnitTestCase {
assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() );
}
private Properties buildGeneratorPropertiesBase() {
Properties props = new Properties();
props.put(
PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER,
new ObjectNameNormalizer() {
protected boolean isUseQuotedIdentifiersGlobally() {
return false;
}
protected NamingStrategy getNamingStrategy() {
return null;
}
}
);
return props;
}
/**
* Test all params defaulted with a dialect which does not support sequences
*/
public void testDefaultedTableBackedConfiguration() {
Dialect dialect = new TableDialect();
Properties props = new Properties();
Properties props = buildGeneratorPropertiesBase();
SequenceStyleGenerator generator = new SequenceStyleGenerator();
generator.configure( Hibernate.LONG, props, dialect );
@ -63,7 +83,7 @@ public class SequenceStyleConfigUnitTest extends UnitTestCase {
* dialect supporting pooled sequences (pooled) and not (hilo)
*/
public void testDefaultOptimizerBasedOnIncrementBackedBySequence() {
Properties props = new Properties();
Properties props = buildGeneratorPropertiesBase();
props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "10" );
// for dialects which do not support pooled sequences, we default to pooled+table
@ -89,7 +109,7 @@ public class SequenceStyleConfigUnitTest extends UnitTestCase {
* pooled.
*/
public void testDefaultOptimizerBasedOnIncrementBackedByTable() {
Properties props = new Properties();
Properties props = buildGeneratorPropertiesBase();
props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "10" );
Dialect dialect = new TableDialect();
SequenceStyleGenerator generator = new SequenceStyleGenerator();
@ -104,7 +124,7 @@ public class SequenceStyleConfigUnitTest extends UnitTestCase {
*/
public void testForceTableUse() {
Dialect dialect = new SequenceDialect();
Properties props = new Properties();
Properties props = buildGeneratorPropertiesBase();
props.setProperty( SequenceStyleGenerator.FORCE_TBL_PARAM, "true" );
SequenceStyleGenerator generator = new SequenceStyleGenerator();
generator.configure( Hibernate.LONG, props, dialect );
@ -121,7 +141,7 @@ public class SequenceStyleConfigUnitTest extends UnitTestCase {
final Dialect dialect = new SequenceDialect();
// optimizer=none w/ increment > 1 => should honor optimizer
Properties props = new Properties();
Properties props = buildGeneratorPropertiesBase();
props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.NONE );
props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" );
SequenceStyleGenerator generator = new SequenceStyleGenerator();
@ -132,7 +152,7 @@ public class SequenceStyleConfigUnitTest extends UnitTestCase {
assertEquals( 1, generator.getDatabaseStructure().getIncrementSize() );
// optimizer=hilo w/ increment > 1 => hilo
props = new Properties();
props = buildGeneratorPropertiesBase();
props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.HILO );
props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" );
generator = new SequenceStyleGenerator();
@ -143,7 +163,7 @@ public class SequenceStyleConfigUnitTest extends UnitTestCase {
assertEquals( 20, generator.getDatabaseStructure().getIncrementSize() );
// optimizer=pooled w/ increment > 1 => hilo
props = new Properties();
props = buildGeneratorPropertiesBase();
props.setProperty( SequenceStyleGenerator.OPT_PARAM, OptimizerFactory.POOL );
props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" );
generator = new SequenceStyleGenerator();