From dec331362ce8eda9aa66a7ba98971a302e8ca535 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Mon, 20 Sep 2021 22:02:02 -0700 Subject: [PATCH] HHH-14835 : More changes to support SchemaMigrator/SchemaValidator using Hibernate Reactive Changes required for sequences to be created with a default catalog --- .../dialect/SQLServer2012Dialect.java | 34 +++++++ .../internal/StandardSequenceExporter.java | 21 +++-- ...erverWithSequenceDefaultSchemaCatalog.java | 94 +++++++++++++++++++ 3 files changed, 139 insertions(+), 10 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaExportSqlServerWithSequenceDefaultSchemaCatalog.java diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java index e5a32322a2..b256724866 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java @@ -6,8 +6,14 @@ */ package org.hibernate.dialect; +import org.hibernate.boot.Metadata; +import org.hibernate.boot.model.relational.QualifiedSequenceName; +import org.hibernate.boot.model.relational.Sequence; import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.dialect.pagination.SQLServer2012LimitHandler; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.tool.schema.internal.StandardSequenceExporter; +import org.hibernate.tool.schema.spi.Exporter; /** * Microsoft SQL Server 2012 Dialect @@ -15,6 +21,11 @@ import org.hibernate.dialect.pagination.SQLServer2012LimitHandler; * @author Brett Meyer */ public class SQLServer2012Dialect extends SQLServer2008Dialect { + private final Exporter sequenceExporter; + + public SQLServer2012Dialect() { + sequenceExporter = new SqlServerSequenceExporter( this ); + } @Override public boolean supportsSequences() { @@ -26,6 +37,11 @@ public class SQLServer2012Dialect extends SQLServer2008Dialect { return true; } + @Override + public Exporter getSequenceExporter() { + return sequenceExporter; + } + @Override public String getCreateSequenceString(String sequenceName) { return "create sequence " + sequenceName; @@ -94,4 +110,22 @@ public class SQLServer2012Dialect extends SQLServer2008Dialect { protected LimitHandler getDefaultLimitHandler() { return new SQLServer2012LimitHandler(); } + + 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 9b97d5496d..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.getCreateSequenceStrings( - jdbcEnvironment.getQualifiedObjectNameFormatter().format( - sequence.getName(), - jdbcEnvironment.getDialect() - ), + 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) { - final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment(); return dialect.getDropSequenceStrings( - jdbcEnvironment.getQualifiedObjectNameFormatter().format( - sequence.getName(), - jdbcEnvironment.getDialect() - ) + getFormattedSequenceName( sequence.getName(), metadata ) + ); + } + + protected String getFormattedSequenceName(QualifiedSequenceName name, Metadata metadata) { + final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment(); + 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..b9044abc6f --- /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-XXX") +@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; + } + } +}