HHH-15517 Fix for temporary table prefixing the qualified table name instead of just table name

This commit is contained in:
Christian Beikov 2022-09-19 15:06:35 +02:00
parent 398702a111
commit 544c1e0c94
4 changed files with 60 additions and 11 deletions

View File

@ -213,7 +213,7 @@ public class Identifier implements Comparable<Identifier> {
*/ */
public String render(Dialect dialect) { public String render(Dialect dialect) {
return isQuoted return isQuoted
? dialect.openQuote() + getText() + dialect.closeQuote() ? dialect.toQuotedIdentifier( getText() )
: getText(); : getText();
} }

View File

@ -2360,6 +2360,22 @@ public abstract class Dialect implements ConversionContext {
return '"'; return '"';
} }
/**
* Apply dialect-specific quoting.
*
* @param name The value to be quoted.
* @return The quoted value.
* @see #openQuote()
* @see #closeQuote()
*/
public String toQuotedIdentifier(String name) {
if ( name == null ) {
return null;
}
return openQuote() + name + closeQuote();
}
/** /**
* Apply dialect-specific quoting. * Apply dialect-specific quoting.
* <p/> * <p/>

View File

@ -599,6 +599,20 @@ public class SybaseASEDialect extends SybaseDialect {
return sql + new ForUpdateFragment( this, aliasedLockOptions, keyColumnNames ).toFragmentString(); return sql + new ForUpdateFragment( this, aliasedLockOptions, keyColumnNames ).toFragmentString();
} }
@Override
public String toQuotedIdentifier(String name) {
if ( name == null || name.isEmpty() ) {
return name;
}
if ( name.charAt( 0 ) == '#' ) {
// Temporary tables must start with a '#' character,
// but Sybase doesn't support quoting of such identifiers,
// so we simply don't apply quoting in this case
return name;
}
return super.toQuotedIdentifier( name );
}
@Override @Override
public ViolatedConstraintNameExtractor getViolatedConstraintNameExtractor() { public ViolatedConstraintNameExtractor getViolatedConstraintNameExtractor() {
return EXTRACTOR; return EXTRACTOR;

View File

@ -14,6 +14,9 @@ import java.util.function.Function;
import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.relational.Exportable; import org.hibernate.boot.model.relational.Exportable;
import org.hibernate.boot.model.relational.QualifiedNameParser;
import org.hibernate.boot.model.relational.QualifiedTableName;
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.OptimizableGenerator; import org.hibernate.id.OptimizableGenerator;
@ -64,24 +67,38 @@ public class TemporaryTable implements Exportable, Contributable {
EntityMappingType entityDescriptor, EntityMappingType entityDescriptor,
Function<String, String> temporaryTableNameAdjuster, Function<String, String> temporaryTableNameAdjuster,
Dialect dialect, Dialect dialect,
SqlStringGenerationContext sqlStringGenerationContext,
Function<TemporaryTable, List<TemporaryTableColumn>> columnInitializer) { Function<TemporaryTable, List<TemporaryTableColumn>> columnInitializer) {
this.entityDescriptor = entityDescriptor; this.entityDescriptor = entityDescriptor;
// The table name might be a sub-query, which is inappropriate for a temporary table name // The table name might be a sub-query, which is inappropriate for a temporary table name
final String originalTableName = entityDescriptor.getEntityPersister().getSynchronizedQuerySpaces()[0]; final String originalTableName = entityDescriptor.getEntityPersister().getSynchronizedQuerySpaces()[0];
final String name; final QualifiedNameParser.NameParts nameParts = QualifiedNameParser.INSTANCE.parse( originalTableName );
if ( Identifier.isQuoted( originalTableName ) ) { final QualifiedNameParser.NameParts adjustedNameParts = QualifiedNameParser.INSTANCE.parse(
name = dialect.quote( temporaryTableNameAdjuster.apply( Identifier.unQuote( originalTableName ) ) ); temporaryTableNameAdjuster.apply( nameParts.getObjectName().getText() )
);
final String temporaryTableName = adjustedNameParts.getObjectName().getText();
final Identifier tableNameIdentifier;
if ( temporaryTableName.length() > dialect.getMaxIdentifierLength() ) {
tableNameIdentifier = new Identifier(
temporaryTableName.substring( 0, dialect.getMaxIdentifierLength() ),
nameParts.getObjectName().isQuoted()
);
} }
else { else {
name = temporaryTableNameAdjuster.apply( originalTableName ); tableNameIdentifier = new Identifier( temporaryTableName, nameParts.getObjectName().isQuoted() );
}
if ( name.length() > dialect.getMaxIdentifierLength() ) {
this.qualifiedTableName = name.substring( 0, dialect.getMaxIdentifierLength() );
}
else {
this.qualifiedTableName = name;
} }
this.qualifiedTableName = sqlStringGenerationContext.format(
new QualifiedTableName(
adjustedNameParts.getCatalogName() != null
? adjustedNameParts.getCatalogName()
: nameParts.getCatalogName(),
adjustedNameParts.getSchemaName() != null
? adjustedNameParts.getSchemaName()
: nameParts.getSchemaName(),
tableNameIdentifier
)
);
this.dialect = dialect; this.dialect = dialect;
if ( dialect.getSupportedTemporaryTableKind() == TemporaryTableKind.PERSISTENT ) { if ( dialect.getSupportedTemporaryTableKind() == TemporaryTableKind.PERSISTENT ) {
final TypeConfiguration typeConfiguration = entityDescriptor.getEntityPersister() final TypeConfiguration typeConfiguration = entityDescriptor.getEntityPersister()
@ -123,6 +140,7 @@ public class TemporaryTable implements Exportable, Contributable {
entityDescriptor, entityDescriptor,
temporaryTableNameAdjuster, temporaryTableNameAdjuster,
dialect, dialect,
runtimeModelCreationContext.getSessionFactory().getSqlStringGenerationContext(),
temporaryTable -> { temporaryTable -> {
final List<TemporaryTableColumn> columns = new ArrayList<>(); final List<TemporaryTableColumn> columns = new ArrayList<>();
final PersistentClass entityBinding = runtimeModelCreationContext.getBootModel() final PersistentClass entityBinding = runtimeModelCreationContext.getBootModel()
@ -211,6 +229,7 @@ public class TemporaryTable implements Exportable, Contributable {
entityDescriptor, entityDescriptor,
temporaryTableNameAdjuster, temporaryTableNameAdjuster,
dialect, dialect,
runtimeModelCreationContext.getSessionFactory().getSqlStringGenerationContext(),
temporaryTable -> { temporaryTable -> {
final List<TemporaryTableColumn> columns = new ArrayList<>(); final List<TemporaryTableColumn> columns = new ArrayList<>();
final PersistentClass entityBinding = runtimeModelCreationContext.getBootModel() final PersistentClass entityBinding = runtimeModelCreationContext.getBootModel()