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

git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18158 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
Steve Ebersole 2009-12-08 13:14:47 +00:00
parent 25343680c9
commit 6b9e796074
11 changed files with 145 additions and 71 deletions

View File

@ -444,6 +444,9 @@ public class BinderHelper {
( (org.hibernate.mapping.Column) id.getColumnIterator().next() ).getName() ( (org.hibernate.mapping.Column) id.getColumnIterator().next() ).getName()
); );
} }
// 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 ( !isDefault( generatorName ) ) { if ( !isDefault( generatorName ) ) {
//we have a named generator //we have a named generator
IdGenerator gen = mappings.getGenerator( generatorName, localGenerators ); IdGenerator gen = mappings.getGenerator( generatorName, localGenerators );

View File

@ -189,9 +189,15 @@ public class Ejb3Column {
} }
protected void initMappingColumn( protected void initMappingColumn(
String columnName, String propertyName, int length, int precision, int scale, boolean nullable, String columnName,
String sqlType, boolean unique, boolean applyNamingStrategy String propertyName,
) { int length,
int precision,
int scale,
boolean nullable,
String sqlType,
boolean unique,
boolean applyNamingStrategy) {
if ( StringHelper.isNotEmpty( formulaString ) ) { if ( StringHelper.isNotEmpty( formulaString ) ) {
this.formula = new Formula(); this.formula = new Formula();
this.formula.setFormula( formulaString ); this.formula.setFormula( formulaString );
@ -218,16 +224,25 @@ public class Ejb3Column {
if ( applyNamingStrategy ) { if ( applyNamingStrategy ) {
if ( StringHelper.isEmpty( columnName ) ) { if ( StringHelper.isEmpty( columnName ) ) {
if ( propertyName != null ) { if ( propertyName != null ) {
mappingColumn.setName( mappings.getNamingStrategy().propertyToColumnName( propertyName ) ); mappingColumn.setName(
mappings.getObjectNameNormalizer().normalizeIdentifierQuoting(
mappings.getNamingStrategy().propertyToColumnName( propertyName )
)
);
} }
//Do nothing otherwise //Do nothing otherwise
} }
else { else {
mappingColumn.setName( mappings.getNamingStrategy().columnName( columnName ) ); columnName = mappings.getObjectNameNormalizer().normalizeIdentifierQuoting( columnName );
columnName = mappings.getNamingStrategy().columnName( columnName );
columnName = mappings.getObjectNameNormalizer().normalizeIdentifierQuoting( columnName );
mappingColumn.setName( columnName );
} }
} }
else { else {
if ( StringHelper.isNotEmpty( columnName ) ) mappingColumn.setName( columnName ); if ( StringHelper.isNotEmpty( columnName ) ) {
mappingColumn.setName( mappings.getObjectNameNormalizer().normalizeIdentifierQuoting( columnName ) );
}
} }
} }
@ -383,31 +398,38 @@ public class Ejb3Column {
log.debug( "Column(s) overridden for property {}", inferredData.getPropertyName() ); log.debug( "Column(s) overridden for property {}", inferredData.getPropertyName() );
} }
if ( actualCols == null ) { if ( actualCols == null ) {
columns = buildImplicitColumn( inferredData, columns = buildImplicitColumn(
inferredData,
suffixForDefaultColumnName, suffixForDefaultColumnName,
secondaryTables, secondaryTables,
propertyHolder, propertyHolder,
nullability, nullability,
mappings ); mappings
);
} }
else { else {
final int length = actualCols.length; final int length = actualCols.length;
columns = new Ejb3Column[length]; columns = new Ejb3Column[length];
for (int index = 0; index < length; index++) { for (int index = 0; index < length; index++) {
final ObjectNameNormalizer nameNormalizer = mappings.getObjectNameNormalizer();
javax.persistence.Column col = actualCols[index]; javax.persistence.Column col = actualCols[index];
String sqlType = col.columnDefinition().equals( "" ) ? null : col.columnDefinition(); final String sqlType = col.columnDefinition().equals( "" )
? null
: nameNormalizer.normalizeIdentifierQuoting( col.columnDefinition() );
final String tableName = nameNormalizer.normalizeIdentifierQuoting( col.table() );
final String columnName = nameNormalizer.normalizeIdentifierQuoting( col.name() );
Ejb3Column column = new Ejb3Column(); Ejb3Column column = new Ejb3Column();
column.setImplicit( false ); column.setImplicit( false );
column.setSqlType( sqlType ); column.setSqlType( sqlType );
column.setLength( col.length() ); column.setLength( col.length() );
column.setPrecision( col.precision() ); column.setPrecision( col.precision() );
column.setScale( col.scale() ); column.setScale( col.scale() );
column.setLogicalColumnName( col.name() ); if ( StringHelper.isEmpty( columnName ) && ! StringHelper.isEmpty( suffixForDefaultColumnName ) ) {
//support for explicit property name + suffix
if ( StringHelper.isEmpty( column.getLogicalColumnName() )
&& ! StringHelper.isEmpty( suffixForDefaultColumnName ) ) {
column.setLogicalColumnName( inferredData.getPropertyName() + suffixForDefaultColumnName ); column.setLogicalColumnName( inferredData.getPropertyName() + suffixForDefaultColumnName );
} }
else {
column.setLogicalColumnName( columnName );
}
column.setPropertyName( column.setPropertyName(
BinderHelper.getRelativePath( propertyHolder, inferredData.getPropertyName() ) BinderHelper.getRelativePath( propertyHolder, inferredData.getPropertyName() )
@ -418,7 +440,7 @@ public class Ejb3Column {
column.setUnique( col.unique() ); column.setUnique( col.unique() );
column.setInsertable( col.insertable() ); column.setInsertable( col.insertable() );
column.setUpdatable( col.updatable() ); column.setUpdatable( col.updatable() );
column.setSecondaryTableName( col.table() ); column.setSecondaryTableName( tableName );
column.setPropertyHolder( propertyHolder ); column.setPropertyHolder( propertyHolder );
column.setJoins( secondaryTables ); column.setJoins( secondaryTables );
column.setMappings( mappings ); column.setMappings( mappings );
@ -436,12 +458,11 @@ public class Ejb3Column {
Map<String, Join> secondaryTables, Map<String, Join> secondaryTables,
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
Nullability nullability, Nullability nullability,
ExtendedMappings mappings ExtendedMappings mappings) {
) {
Ejb3Column[] columns;
columns = new Ejb3Column[1];
Ejb3Column column = new Ejb3Column(); Ejb3Column column = new Ejb3Column();
column.setImplicit( false ); Ejb3Column[] columns = new Ejb3Column[1];
columns[0] = column;
//not following the spec but more clean //not following the spec but more clean
if ( nullability != Nullability.FORCED_NULL if ( nullability != Nullability.FORCED_NULL
&& inferredData.getClassOrElement().isPrimitive() && inferredData.getClassOrElement().isPrimitive()
@ -466,7 +487,6 @@ public class Ejb3Column {
column.setImplicit( true ); column.setImplicit( true );
} }
column.bind(); column.bind();
columns[0] = column;
return columns; return columns;
} }

View File

@ -332,8 +332,14 @@ public class Ejb3JoinColumn extends Ejb3Column {
columnDefinition = joinAnn.columnDefinition(); columnDefinition = joinAnn.columnDefinition();
referencedColumnName = joinAnn.referencedColumnName(); referencedColumnName = joinAnn.referencedColumnName();
} }
String sqlType = "".equals( columnDefinition ) ? null : columnDefinition;
String name = "".equals( colName ) ? defaultName : colName; String sqlType = "".equals( columnDefinition )
? null
: mappings.getObjectNameNormalizer().normalizeIdentifierQuoting( columnDefinition );
String name = "".equals( colName )
? defaultName
: colName;
name = mappings.getObjectNameNormalizer().normalizeIdentifierQuoting( name );
return new Ejb3JoinColumn( return new Ejb3JoinColumn(
sqlType, sqlType,
name, false, false, name, false, false,
@ -344,6 +350,7 @@ public class Ejb3JoinColumn extends Ejb3Column {
); );
} }
else { else {
defaultName = mappings.getObjectNameNormalizer().normalizeIdentifierQuoting( defaultName );
return new Ejb3JoinColumn( return new Ejb3JoinColumn(
(String) null, defaultName, (String) null, defaultName,
false, false, true, true, null, (String) null, false, false, true, true, null, (String) null,

View File

@ -48,7 +48,6 @@ import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property; import org.hibernate.mapping.Property;
import org.hibernate.mapping.ToOne; import org.hibernate.mapping.ToOne;
import org.hibernate.mapping.Value; import org.hibernate.mapping.Value;
import org.hibernate.util.CollectionHelper;
import org.hibernate.util.StringHelper; import org.hibernate.util.StringHelper;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -78,9 +77,8 @@ public class ResultsetMappingSecondPass implements QuerySecondPass {
for (EntityResult entity : ann.entities()) { for (EntityResult entity : ann.entities()) {
//TODO parameterize lock mode? //TODO parameterize lock mode?
List properties = new ArrayList(); List<FieldResult> properties = new ArrayList<FieldResult>();
List propertyNames = new ArrayList(); List<String> propertyNames = new ArrayList<String>();
Map propertyresults = new HashMap();
for (FieldResult field : entity.fields()) { for (FieldResult field : entity.fields()) {
//use an ArrayList cause we might have several columns per root property //use an ArrayList cause we might have several columns per root property
String name = field.name(); String name = field.name();
@ -120,18 +118,16 @@ public class ResultsetMappingSecondPass implements QuerySecondPass {
} }
} }
Set uniqueReturnProperty = new HashSet(); Set<String> uniqueReturnProperty = new HashSet<String>();
Iterator iterator = properties.iterator(); Map<String, ArrayList<String>> propertyResultsTmp = new HashMap<String, ArrayList<String>>();
while ( iterator.hasNext() ) { for ( Object property : properties ) {
FieldResult propertyresult = (FieldResult) iterator.next(); final FieldResult propertyresult = ( FieldResult ) property;
String name = propertyresult.name(); final String name = propertyresult.name();
if ( "class".equals( name ) ) { if ( "class".equals( name ) ) {
throw new MappingException( throw new MappingException(
"class is not a valid property name to use in a @FieldResult, use @Entity(discriminatorColumn) instead" "class is not a valid property name to use in a @FieldResult, use @Entity(discriminatorColumn) instead"
); );
} }
ArrayList allResultColumns = new ArrayList();
allResultColumns.add( propertyresult.column() );
if ( uniqueReturnProperty.contains( name ) ) { if ( uniqueReturnProperty.contains( name ) ) {
throw new MappingException( throw new MappingException(
@ -140,38 +136,56 @@ public class ResultsetMappingSecondPass implements QuerySecondPass {
); );
} }
uniqueReturnProperty.add( name ); uniqueReturnProperty.add( name );
final String quotingNormalizedColumnName = mappings.getObjectNameNormalizer()
.normalizeIdentifierQuoting( propertyresult.column() );
String key = StringHelper.root( name ); String key = StringHelper.root( name );
ArrayList intermediateResults = (ArrayList) propertyresults.get( key ); ArrayList<String> intermediateResults = propertyResultsTmp.get( key );
if ( intermediateResults == null ) { if ( intermediateResults == null ) {
propertyresults.put( key, allResultColumns ); intermediateResults = new ArrayList<String>();
propertyResultsTmp.put( key, intermediateResults );
} }
else { intermediateResults.add( quotingNormalizedColumnName );
intermediateResults.addAll( allResultColumns );
}
}
Iterator entries = propertyresults.entrySet().iterator();
while ( entries.hasNext() ) {
Map.Entry entry = (Map.Entry) entries.next();
if ( entry.getValue() instanceof ArrayList ) {
ArrayList list = (ArrayList) entry.getValue();
entry.setValue( list.toArray( new String[list.size()] ) );
} }
Map<String, String[]> propertyResults = new HashMap<String,String[]>();
for ( Map.Entry<String, ArrayList<String>> entry : propertyResultsTmp.entrySet() ) {
propertyResults.put(
entry.getKey(),
entry.getValue().toArray( new String[ entry.getValue().size() ] )
);
} }
if ( !BinderHelper.isDefault( entity.discriminatorColumn() ) ) { if ( !BinderHelper.isDefault( entity.discriminatorColumn() ) ) {
propertyresults.put( "class", new String[] { entity.discriminatorColumn() } ); final String quotingNormalizedName = mappings.getObjectNameNormalizer().normalizeIdentifierQuoting(
entity.discriminatorColumn()
);
propertyResults.put( "class", new String[] { quotingNormalizedName } );
} }
propertyresults = propertyresults.isEmpty() ? CollectionHelper.EMPTY_MAP : propertyresults; if ( propertyResults.isEmpty() ) {
NativeSQLQueryRootReturn result = propertyResults = java.util.Collections.emptyMap();
new NativeSQLQueryRootReturn( }
"alias" + entityAliasIndex++, entity.entityClass().getName(), propertyresults, LockMode.READ
NativeSQLQueryRootReturn result = new NativeSQLQueryRootReturn(
"alias" + entityAliasIndex++,
entity.entityClass().getName(),
propertyResults,
LockMode.READ
); );
definition.addQueryReturn( result ); definition.addQueryReturn( result );
} }
for (ColumnResult column : ann.columns()) { for ( ColumnResult column : ann.columns() ) {
definition.addQueryReturn( new NativeSQLQueryScalarReturn( column.name(), null ) ); definition.addQueryReturn(
new NativeSQLQueryScalarReturn(
mappings.getObjectNameNormalizer().normalizeIdentifierQuoting(
column.name()
),
null
)
);
} }
if ( isDefault ) { if ( isDefault ) {
@ -182,6 +196,7 @@ public class ResultsetMappingSecondPass implements QuerySecondPass {
} }
} }
@SuppressWarnings({ "unchecked" })
private List getFollowers(Iterator parentPropIter, String reducedName, String name) { private List getFollowers(Iterator parentPropIter, String reducedName, String name) {
boolean hasFollowers = false; boolean hasFollowers = false;
List followers = new ArrayList(); List followers = new ArrayList();

View File

@ -1,10 +1,10 @@
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
* Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as * Copyright (c) 2009 by Red Hat Inc and/or its affiliates or by
* indicated by the @author tags or express copyright attribution * third-party contributors as indicated by either @author tags or express
* statements applied by the authors. All third-party contributions are * copyright attribution statements applied by the authors. All
* distributed under license by Red Hat Middleware LLC. * third-party contributions are distributed under license by Red Hat Inc.
* *
* This copyrighted material is made available to anyone wishing to use, modify, * 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 * copy, or redistribute it subject to the terms and conditions of the GNU
@ -20,7 +20,6 @@
* Free Software Foundation, Inc. * Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor * 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA * Boston, MA 02110-1301 USA
*
*/ */
package org.hibernate; package org.hibernate;

View File

@ -2451,12 +2451,14 @@ public class Configuration implements Serializable {
String name, String name,
String subselect, String subselect,
boolean isAbstract) { boolean isAbstract) {
name = getObjectNameNormalizer().normalizeIdentifierQuoting( name );
schema = getObjectNameNormalizer().normalizeIdentifierQuoting( schema );
catalog = getObjectNameNormalizer().normalizeIdentifierQuoting( catalog );
String key = subselect == null ? Table.qualify( catalog, schema, name ) : subselect; String key = subselect == null ? Table.qualify( catalog, schema, name ) : subselect;
Table table = ( Table ) tables.get( key ); Table table = ( Table ) tables.get( key );
if ( table == null ) { if ( table == null ) {
schema = getObjectNameNormalizer().normalizeIdentifierQuoting( schema );
catalog = getObjectNameNormalizer().normalizeIdentifierQuoting( catalog );
table = new Table(); table = new Table();
table.setAbstract( isAbstract ); table.setAbstract( isAbstract );
table.setName( name ); table.setName( name );
@ -2481,14 +2483,15 @@ public class Configuration implements Serializable {
boolean isAbstract, boolean isAbstract,
String subselect, String subselect,
Table includedTable) throws DuplicateMappingException { Table includedTable) throws DuplicateMappingException {
name = getObjectNameNormalizer().normalizeIdentifierQuoting( name );
schema = getObjectNameNormalizer().normalizeIdentifierQuoting( schema );
catalog = getObjectNameNormalizer().normalizeIdentifierQuoting( catalog );
String key = subselect == null ? Table.qualify(catalog, schema, name) : subselect; String key = subselect == null ? Table.qualify(catalog, schema, name) : subselect;
if ( tables.containsKey( key ) ) { if ( tables.containsKey( key ) ) {
throw new DuplicateMappingException( "table", name ); throw new DuplicateMappingException( "table", name );
} }
schema = getObjectNameNormalizer().normalizeIdentifierQuoting( schema );
catalog = getObjectNameNormalizer().normalizeIdentifierQuoting( catalog );
Table table = new DenormalizedTable( includedTable ); Table table = new DenormalizedTable( includedTable );
table.setAbstract( isAbstract ); table.setAbstract( isAbstract );
table.setName( name ); table.setName( name );

View File

@ -100,8 +100,12 @@ public abstract class Constraint implements RelationalModel, Serializable {
public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema) { public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema) {
if ( isGenerated( dialect ) ) { if ( isGenerated( dialect ) ) {
return "alter table " + getTable() return new StringBuffer()
.getQualifiedName( dialect, defaultCatalog, defaultSchema ) + " drop constraint " + getName(); .append( "alter table " )
.append( getTable().getQualifiedName( dialect, defaultCatalog, defaultSchema ) )
.append( " drop constraint " )
.append( dialect.quote( getName() ) )
.toString();
} }
else { else {
return null; return null;

View File

@ -39,21 +39,28 @@ public class UniqueKey extends Constraint {
public String sqlConstraintString(Dialect dialect) { public String sqlConstraintString(Dialect dialect) {
StringBuffer buf = new StringBuffer( "unique (" ); StringBuffer buf = new StringBuffer( "unique (" );
boolean hadNullableColumn = false;
Iterator iter = getColumnIterator(); Iterator iter = getColumnIterator();
boolean nullable = false;
while ( iter.hasNext() ) { while ( iter.hasNext() ) {
Column column = (Column) iter.next(); Column column = (Column) iter.next();
if ( !nullable && column.isNullable() ) nullable = true; if ( !hadNullableColumn && column.isNullable() ) {
hadNullableColumn = true;
}
buf.append( column.getQuotedName( dialect ) ); buf.append( column.getQuotedName( dialect ) );
if ( iter.hasNext() ) buf.append( ", " ); if ( iter.hasNext() ) {
buf.append( ", " );
}
} }
//do not add unique constraint on DB not supporting unique and nullable columns //do not add unique constraint on DB not supporting unique and nullable columns
return !nullable || dialect.supportsNotNullUnique() ? return !hadNullableColumn || dialect.supportsNotNullUnique() ?
buf.append( ')' ).toString() : buf.append( ')' ).toString() :
null; null;
} }
public String sqlConstraintString(Dialect dialect, String constraintName, String defaultCatalog, public String sqlConstraintString(
Dialect dialect,
String constraintName,
String defaultCatalog,
String defaultSchema) { String defaultSchema) {
StringBuffer buf = new StringBuffer( StringBuffer buf = new StringBuffer(
dialect.getAddPrimaryKeyConstraintString( constraintName ) dialect.getAddPrimaryKeyConstraintString( constraintName )

View File

@ -188,6 +188,9 @@ public class Ejb3Configuration implements Serializable, Referenceable {
this.setProperty( Environment.DATASOURCE, metadata.getNonJtaDatasource() ); this.setProperty( Environment.DATASOURCE, metadata.getNonJtaDatasource() );
} }
defineTransactionType( metadata.getTransactionType(), workingVars ); defineTransactionType( metadata.getTransactionType(), workingVars );
if ( metadata.isUseQuotedIdentifiers() ) {
this.setProperty( Environment.GLOBALLY_QUOTED_IDENTIFIERS, "true" );
}
if ( metadata.getClasses().size() > 0 ) { if ( metadata.getClasses().size() > 0 ) {
workingVars.put( HibernatePersistence.CLASS_NAMES, metadata.getClasses() ); workingVars.put( HibernatePersistence.CLASS_NAMES, metadata.getClasses() );
} }

View File

@ -43,6 +43,7 @@ public class PersistenceMetadata {
private String jtaDatasource; private String jtaDatasource;
private String provider; private String provider;
private PersistenceUnitTransactionType transactionType; private PersistenceUnitTransactionType transactionType;
private boolean useQuotedIdentifiers = false; // the spec (erroneously?) calls this delimited-identifiers
private List<String> classes = new ArrayList<String>(); private List<String> classes = new ArrayList<String>();
private List<String> packages = new ArrayList<String>(); private List<String> packages = new ArrayList<String>();
private List<String> mappingFiles = new ArrayList<String>(); private List<String> mappingFiles = new ArrayList<String>();
@ -94,6 +95,14 @@ public class PersistenceMetadata {
this.provider = provider; this.provider = provider;
} }
public boolean isUseQuotedIdentifiers() {
return useQuotedIdentifiers;
}
public void setUseQuotedIdentifiers(boolean useQuotedIdentifiers) {
this.useQuotedIdentifiers = useQuotedIdentifiers;
}
public List<String> getClasses() { public List<String> getClasses() {
return classes; return classes;
} }
@ -162,6 +171,7 @@ public class PersistenceMetadata {
.append("\tnonJtaDataSource: ").append(nonJtaDatasource).append("\n") .append("\tnonJtaDataSource: ").append(nonJtaDatasource).append("\n")
.append("\ttransactionType: ").append(transactionType).append("\n") .append("\ttransactionType: ").append(transactionType).append("\n")
.append("\tprovider: ").append(provider).append("\n") .append("\tprovider: ").append(provider).append("\n")
.append("\tuseQuotedIdentifiers: ").append(useQuotedIdentifiers).append("\n")
.append("\tclasses[\n"); .append("\tclasses[\n");
if (classes != null) { if (classes != null) {
for (String elt : classes) { for (String elt : classes) {

View File

@ -209,6 +209,9 @@ public final class PersistenceXmlLoader {
else if ( tag.equals( "exclude-unlisted-classes" ) ) { else if ( tag.equals( "exclude-unlisted-classes" ) ) {
metadata.setExcludeUnlistedClasses( true ); metadata.setExcludeUnlistedClasses( true );
} }
else if ( tag.equals( "delimited-identifiers" ) ) {
metadata.setUseQuotedIdentifiers( true );
}
else if ( tag.equals( "properties" ) ) { else if ( tag.equals( "properties" ) ) {
NodeList props = element.getChildNodes(); NodeList props = element.getChildNodes();
for ( int j = 0; j < props.getLength() ; j++ ) { for ( int j = 0; j < props.getLength() ; j++ ) {