diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java index 0a06bba2b6..963ace4ad1 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java @@ -2495,7 +2495,7 @@ public abstract class Dialect implements ConversionContext { // DDL support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ private StandardTableExporter tableExporter = new StandardTableExporter( this ); - private StandardSequenceExporter sequenceExporter = new StandardSequenceExporter( this ); + protected StandardSequenceExporter sequenceExporter = new StandardSequenceExporter( this ); private StandardIndexExporter indexExporter = new StandardIndexExporter( this ); private StandardForeignKeyExporter foreignKeyExporter = new StandardForeignKeyExporter( this ); private StandardUniqueKeyExporter uniqueKeyExporter = new StandardUniqueKeyExporter( this ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java index dd62f20e51..3aac78deb2 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java @@ -7,6 +7,8 @@ package org.hibernate.dialect; import org.hibernate.*; +import org.hibernate.boot.Metadata; +import org.hibernate.boot.model.relational.QualifiedSequenceName; import org.hibernate.dialect.function.CommonFunctionFactory; import org.hibernate.dialect.function.SQLServerFormatEmulation; import org.hibernate.dialect.identity.IdentityColumnSupport; @@ -39,6 +41,7 @@ import org.hibernate.sql.ast.SqlAstTranslatorFactory; import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory; import org.hibernate.sql.ast.tree.Statement; import org.hibernate.sql.exec.spi.JdbcOperation; +import org.hibernate.tool.schema.internal.StandardSequenceExporter; import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptor; import org.hibernate.type.descriptor.jdbc.SmallIntTypeDescriptor; @@ -86,6 +89,10 @@ public class SQLServerDialect extends AbstractTransactSQLDialect { registerColumnType( Types.TIMESTAMP_WITH_TIMEZONE, "datetimeoffset($p)" ); } + if(getVersion() >= 11) { + sequenceExporter = new SqlServerSequenceExporter( this ); + } + registerColumnType( Types.VARCHAR, 8000, "varchar($l)" ); registerColumnType( Types.NVARCHAR, 4000, "nvarchar($l)" ); registerColumnType( Types.VARBINARY, 8000, "varbinary($l)" ); @@ -780,4 +787,22 @@ public class SQLServerDialect extends AbstractTransactSQLDialect { return NameQualifierSupport.BOTH; } + private class SqlServerSequenceExporter extends StandardSequenceExporter { + + public SqlServerSequenceExporter(Dialect dialect) { + super( dialect ); + } + + @Override + protected String getFormattedSequenceName(QualifiedSequenceName name, Metadata metadata) { + if ( name.getCatalogName() != null ) { + // SQL Server does not allow the catalog in the sequence name. + // See https://docs.microsoft.com/en-us/sql/t-sql/statements/create-sequence-transact-sql?view=sql-server-ver15&viewFallbackFrom=sql-server-ver12 + // Keeping the catalog in the name does not break on ORM, but it fails using Vert.X for Reactive. + name = new QualifiedSequenceName( null, name.getSchemaName(), name.getObjectName() ); + } + return super.getFormattedSequenceName( name, metadata ); + } + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardSequenceExporter.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardSequenceExporter.java index d1b79e4718..cb04d29b55 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardSequenceExporter.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardSequenceExporter.java @@ -7,6 +7,7 @@ package org.hibernate.tool.schema.internal; import org.hibernate.boot.Metadata; +import org.hibernate.boot.model.relational.QualifiedSequenceName; import org.hibernate.boot.model.relational.Sequence; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; @@ -24,12 +25,8 @@ public class StandardSequenceExporter implements Exporter { @Override public String[] getSqlCreateStrings(Sequence sequence, Metadata metadata) { - final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment(); - return dialect.getSequenceSupport().getCreateSequenceStrings( - jdbcEnvironment.getQualifiedObjectNameFormatter().format( - sequence.getName(), - jdbcEnvironment.getDialect() - ), + return dialect.getCreateSequenceStrings( + getFormattedSequenceName( sequence.getName(), metadata ), sequence.getInitialValue(), sequence.getIncrementSize() ); @@ -37,12 +34,16 @@ public class StandardSequenceExporter implements Exporter { @Override public String[] getSqlDropStrings(Sequence sequence, Metadata metadata) { + return dialect.getDropSequenceStrings( + getFormattedSequenceName( sequence.getName(), metadata ) + ); + } + + protected String getFormattedSequenceName(QualifiedSequenceName name, Metadata metadata) { final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment(); - return dialect.getSequenceSupport().getDropSequenceStrings( - jdbcEnvironment.getQualifiedObjectNameFormatter().format( - sequence.getName(), - jdbcEnvironment.getDialect() - ) + return jdbcEnvironment.getQualifiedObjectNameFormatter().format( + name, + jdbcEnvironment.getDialect() ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaExportSqlServerWithSequenceDefaultSchemaCatalog.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaExportSqlServerWithSequenceDefaultSchemaCatalog.java new file mode 100644 index 0000000000..12630dadb3 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaExportSqlServerWithSequenceDefaultSchemaCatalog.java @@ -0,0 +1,94 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.schemaupdate; + +import java.util.EnumSet; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.cfg.Environment; +import org.hibernate.dialect.SQLServer2012Dialect; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.tool.hbm2ddl.SchemaExport; +import org.hibernate.tool.schema.TargetType; + +import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.CustomRunner; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +/** + * @author Andrea Boriero + */ +@TestForIssue(jiraKey = "HHH-14835") +@RunWith(CustomRunner.class) +@RequiresDialect(SQLServer2012Dialect.class) +public class SchemaExportSqlServerWithSequenceDefaultSchemaCatalog { + protected ServiceRegistry serviceRegistry; + protected MetadataImplementor metadata; + + @Test + public void shouldCreateIndex() { + SchemaExport schemaExport = new SchemaExport(); + schemaExport.create( EnumSet.of( TargetType.DATABASE, TargetType.STDOUT ), metadata ); + assertThat( schemaExport.getExceptions().size(), is( 0 ) ); + } + + @Before + public void setUp() { + serviceRegistry = new StandardServiceRegistryBuilder() + .applySetting( Environment.DEFAULT_SCHEMA, "dbo" ) + .applySetting( Environment.DEFAULT_CATALOG, "hibernate_orm_test" ) + .build(); + metadata = (MetadataImplementor) new MetadataSources( serviceRegistry ) + .addAnnotatedClass( MyEntity.class ) + .buildMetadata(); + + System.out.println( "********* Starting SchemaExport for START-UP *************************" ); + new SchemaExport().create( EnumSet.of( TargetType.DATABASE, TargetType.STDOUT ), metadata ); + System.out.println( "********* Completed SchemaExport for START-UP *************************" ); + } + + + @After + public void tearDown() { + System.out.println( "********* Starting SchemaExport (drop) for TEAR-DOWN *************************" ); + new SchemaExport().drop( EnumSet.of( TargetType.DATABASE, TargetType.STDOUT ), metadata ); + System.out.println( "********* Completed SchemaExport (drop) for TEAR-DOWN *************************" ); + + StandardServiceRegistryBuilder.destroy( serviceRegistry ); + serviceRegistry = null; + } + + + @Entity + @Table(name = "MyEntity") + public static class MyEntity { + private int id; + + @Id + @GeneratedValue + public int getId() { + return this.id; + } + + public void setId(final int id) { + this.id = id; + } + } +}