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 310d9615da6d..0186ada499a2 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java @@ -4614,7 +4614,10 @@ public void augmentRecognizedTableTypes(List tableTypesList) { } /** - * Does is dialect support {@code partition by}? + * Does is dialect support {@code partition by} in window + * functions? + * + * @apiNote This has nothing to do with table partitioning. * * @since 5.2 */ @@ -4624,10 +4627,14 @@ public boolean supportsPartitionBy() { /** * Does this dialect require that the columns listed in - * {@code partition by} also occur in the primary key? + * {@code partition by} also occur in the primary key, + * when defining table partitioning? + * + * @apiNote This has nothing to do with window functions. * * @since 7.1 */ + @Incubating public boolean addPartitionKeyToPrimaryKey() { return false; } 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 c043404902a0..806bb08543d1 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java @@ -676,6 +676,11 @@ public String getCurrentTimestampSelectString() { // Overridden informational metadata ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + @Override + public boolean addPartitionKeyToPrimaryKey() { + return true; + } + @Override public boolean supportsResultSetPositionQueryMethodsOnForwardOnlyCursor() { return false; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseDialect.java index 20e96ff0f048..9a9dd155c49b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseDialect.java @@ -579,6 +579,11 @@ public boolean supportsRowValueConstructorSyntaxInInList() { return false; } + @Override + public boolean addPartitionKeyToPrimaryKey() { + return true; + } + private static class JTDSSchemaNameResolver implements SchemaNameResolver { @Override public String resolveSchemaName(Connection connection, Dialect dialect) throws SQLException { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/Db2PartitionedTableTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/Db2PartitionedTableTest.java new file mode 100644 index 000000000000..8913e53010b0 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/Db2PartitionedTableTest.java @@ -0,0 +1,49 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.sql.partition; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import org.hibernate.annotations.PartitionKey; +import org.hibernate.dialect.DB2Dialect; +import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; +import org.hibernate.testing.orm.junit.Jpa; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@RequiresDialect(DB2Dialect.class) +@Jpa(annotatedClasses = Db2PartitionedTableTest.Partitioned.class) +class Db2PartitionedTableTest { + @Test void test(EntityManagerFactoryScope scope) { + scope.inTransaction( session -> { + Partitioned partitioned = new Partitioned(); + partitioned.id = 1L; + partitioned.pid = 500L; + session.persist( partitioned ); + } ); + scope.inTransaction( session -> { + Partitioned partitioned = session.find( Partitioned.class, 1L ); + assertNotNull( partitioned ); + partitioned.text = "updated"; + } ); + } + @Entity + @Table(name = "db2parts", + options = + """ + PARTITION BY RANGE (pid) ( + STARTING FROM (0) ENDING AT (1000), + ENDING AT (2000) + ) + """) + static class Partitioned { + @Id Long id; + @PartitionKey Long pid; + String text = ""; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/InformixPartitionedTableTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/InformixPartitionedTableTest.java new file mode 100644 index 000000000000..b73af471d6f3 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/InformixPartitionedTableTest.java @@ -0,0 +1,49 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.sql.partition; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import org.hibernate.annotations.PartitionKey; +import org.hibernate.community.dialect.InformixDialect; +import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; +import org.hibernate.testing.orm.junit.Jpa; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@RequiresDialect(InformixDialect.class) +@Jpa(annotatedClasses = InformixPartitionedTableTest.Partitioned.class) +class InformixPartitionedTableTest { + @Test void test(EntityManagerFactoryScope scope) { + scope.inTransaction( session -> { + Partitioned partitioned = new Partitioned(); + partitioned.id = 1L; + partitioned.pid = 500L; + session.persist( partitioned ); + } ); + scope.inTransaction( session -> { + Partitioned partitioned = session.find( Partitioned.class, 1L ); + assertNotNull( partitioned ); + partitioned.text = "updated"; + } ); + } + @Entity + @Table(name = "infoparts", + options = + """ + FRAGMENT BY RANGE (pid) + INTERVAL (1000) STORE IN (rootdbs) + PARTITION p1 VALUES < 1000 IN rootdbs, + PARTITION p2 VALUES < 2000 IN rootdbs + """) + static class Partitioned { + @Id Long id; + @PartitionKey Long pid; + String text = ""; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/MySQLPartitionedTableTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/MySQLPartitionedTableTest.java new file mode 100644 index 000000000000..5b95e1cfd6a3 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/MySQLPartitionedTableTest.java @@ -0,0 +1,51 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.sql.partition; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import org.hibernate.annotations.PartitionKey; +import org.hibernate.dialect.MariaDBDialect; +import org.hibernate.dialect.MySQLDialect; +import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; +import org.hibernate.testing.orm.junit.Jpa; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@RequiresDialect(MySQLDialect.class) +@RequiresDialect(MariaDBDialect.class) +@Jpa(annotatedClasses = MySQLPartitionedTableTest.Partitioned.class) +class MySQLPartitionedTableTest { + @Test void test(EntityManagerFactoryScope scope) { + scope.inTransaction( session -> { + Partitioned partitioned = new Partitioned(); + partitioned.id = 1L; + partitioned.pid = 500L; + session.persist( partitioned ); + } ); + scope.inTransaction( session -> { + Partitioned partitioned = session.find( Partitioned.class, 1L ); + assertNotNull( partitioned ); + partitioned.text = "updated"; + } ); + } + @Entity + @Table(name = "myparts", + options = + """ + PARTITION BY RANGE (pid) ( + PARTITION p1 VALUES LESS THAN (1000), + PARTITION p2 VALUES LESS THAN (2000) + ) + """) + static class Partitioned { + @Id Long id; + @PartitionKey Long pid; + String text = ""; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/OraclePartitionedTableTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/OraclePartitionedTableTest.java new file mode 100644 index 000000000000..4c8a71da7802 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/OraclePartitionedTableTest.java @@ -0,0 +1,49 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.sql.partition; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import org.hibernate.annotations.PartitionKey; +import org.hibernate.dialect.OracleDialect; +import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; +import org.hibernate.testing.orm.junit.Jpa; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@RequiresDialect(OracleDialect.class) +@Jpa(annotatedClasses = OraclePartitionedTableTest.Partitioned.class) +class OraclePartitionedTableTest { + @Test void test(EntityManagerFactoryScope scope) { + scope.inTransaction( session -> { + Partitioned partitioned = new Partitioned(); + partitioned.id = 1L; + partitioned.pid = 500L; + session.persist( partitioned ); + } ); + scope.inTransaction( session -> { + Partitioned partitioned = session.find( Partitioned.class, 1L ); + assertNotNull( partitioned ); + partitioned.text = "updated"; + } ); + } + @Entity + @Table(name = "oraparts", + options = + """ + PARTITION BY RANGE (pid) ( + PARTITION p1 VALUES LESS THAN (1000), + PARTITION p2 VALUES LESS THAN (2000) + ) + """) + static class Partitioned { + @Id Long id; + @PartitionKey Long pid; + String text = ""; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/PostgresPartitionedTableTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/PostgresPartitionedTableTest.java new file mode 100644 index 000000000000..3ea4f295c840 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/PostgresPartitionedTableTest.java @@ -0,0 +1,54 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.sql.partition; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import org.hibernate.annotations.PartitionKey; +import org.hibernate.cfg.SchemaToolingSettings; +import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; +import org.hibernate.testing.orm.junit.Jpa; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@RequiresDialect(PostgreSQLDialect.class) +@Jpa(annotatedClasses = PostgresPartitionedTableTest.Partitioned.class, + integrationSettings = { + @Setting(name = SchemaToolingSettings.JAKARTA_HBM2DDL_CREATE_SCRIPT_SOURCE, + value = "org/hibernate/orm/test/sql/partition/postgrespartitions-create.sql"), + @Setting(name = SchemaToolingSettings.JAKARTA_HBM2DDL_CREATE_SOURCE, + value = "metadata-then-script"), + @Setting(name = SchemaToolingSettings.JAKARTA_HBM2DDL_DROP_SCRIPT_SOURCE, + value = "org/hibernate/orm/test/sql/partition/postgrespartitions-drop.sql"), + @Setting(name = SchemaToolingSettings.JAKARTA_HBM2DDL_DROP_SOURCE, + value = "script-then-metadata")}) +class PostgresPartitionedTableTest { + @Test void test(EntityManagerFactoryScope scope) { + scope.inTransaction( session -> { + Partitioned partitioned = new Partitioned(); + partitioned.id = 1L; + partitioned.pid = 500L; + session.persist( partitioned ); + } ); + scope.inTransaction( session -> { + Partitioned partitioned = session.find( Partitioned.class, 1L ); + assertNotNull( partitioned ); + partitioned.text = "updated"; + } ); + } + @Entity + @Table(name = "pgparts", + options = "partition by range (pid)") + static class Partitioned { + @Id Long id; + @PartitionKey Long pid; + String text = ""; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/SQLServerPartitionedTableTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/SQLServerPartitionedTableTest.java new file mode 100644 index 000000000000..e89cc9887ffa --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/SQLServerPartitionedTableTest.java @@ -0,0 +1,54 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.sql.partition; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import org.hibernate.annotations.PartitionKey; +import org.hibernate.cfg.SchemaToolingSettings; +import org.hibernate.dialect.SQLServerDialect; +import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; +import org.hibernate.testing.orm.junit.Jpa; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@RequiresDialect(SQLServerDialect.class) +@Jpa(annotatedClasses = SQLServerPartitionedTableTest.Partitioned.class, + integrationSettings = { + @Setting(name = SchemaToolingSettings.JAKARTA_HBM2DDL_CREATE_SCRIPT_SOURCE, + value = "org/hibernate/orm/test/sql/partition/sqlserverpartitions-create.sql"), + @Setting(name = SchemaToolingSettings.JAKARTA_HBM2DDL_CREATE_SOURCE, + value = "script-then-metadata"), + @Setting(name = SchemaToolingSettings.JAKARTA_HBM2DDL_DROP_SCRIPT_SOURCE, + value = "org/hibernate/orm/test/sql/partition/sqlserverpartitions-drop.sql"), + @Setting(name = SchemaToolingSettings.JAKARTA_HBM2DDL_DROP_SOURCE, + value = "metadata-then-script")}) +class SQLServerPartitionedTableTest { + @Test void test(EntityManagerFactoryScope scope) { + scope.inTransaction( session -> { + Partitioned partitioned = new Partitioned(); + partitioned.id = 1L; + partitioned.pid = 500L; + session.persist( partitioned ); + } ); + scope.inTransaction( session -> { + Partitioned partitioned = session.find( Partitioned.class, 1L ); + assertNotNull( partitioned ); + partitioned.text = "updated"; + } ); + } + @Entity + @Table(name = "msparts", + options = "on partScheme(pid)") + static class Partitioned { + @Id Long id; + @PartitionKey Long pid; + String text = ""; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/SybasePartitionedTableTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/SybasePartitionedTableTest.java new file mode 100644 index 000000000000..6ba13648c420 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/sql/partition/SybasePartitionedTableTest.java @@ -0,0 +1,53 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.sql.partition; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import org.hibernate.annotations.PartitionKey; +import org.hibernate.dialect.SybaseASEDialect; +import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; +import org.hibernate.testing.orm.junit.FailureExpected; +import org.hibernate.testing.orm.junit.Jpa; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +// MUST RUN AS USER sa: +// sp_configure 'enable semantic partitioning', 1 +@RequiresDialect(SybaseASEDialect.class) +@Jpa(annotatedClasses = SybasePartitionedTableTest.Partitioned.class) +@FailureExpected(reason = "can't configure 'enable semantic partitioning'") +class SybasePartitionedTableTest { + @Test void test(EntityManagerFactoryScope scope) { + scope.inTransaction( session -> { + Partitioned partitioned = new Partitioned(); + partitioned.id = 1L; + partitioned.pid = 500L; + session.persist( partitioned ); + } ); + scope.inTransaction( session -> { + Partitioned partitioned = session.find( Partitioned.class, 1L ); + assertNotNull( partitioned ); + partitioned.text = "updated"; + } ); + } + @Entity + @Table(name = "syparts", + options = + """ + PARTITION BY RANGE (pid) ( + p1 VALUES <= (1000), + p2 VALUES <= (2000) + ) + """) + static class Partitioned { + @Id Long id; + @PartitionKey Long pid; + String text = ""; + } +} diff --git a/hibernate-core/src/test/resources/org/hibernate/orm/test/sql/partition/postgrespartitions-create.sql b/hibernate-core/src/test/resources/org/hibernate/orm/test/sql/partition/postgrespartitions-create.sql new file mode 100644 index 000000000000..57515b1802d5 --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/orm/test/sql/partition/postgrespartitions-create.sql @@ -0,0 +1,2 @@ +create table p1 partition of pgparts for values from (0) to (1000); +create table p2 partition of pgparts for values from (1001) to (2000); \ No newline at end of file diff --git a/hibernate-core/src/test/resources/org/hibernate/orm/test/sql/partition/postgrespartitions-drop.sql b/hibernate-core/src/test/resources/org/hibernate/orm/test/sql/partition/postgrespartitions-drop.sql new file mode 100644 index 000000000000..5c3afbf06d7a --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/orm/test/sql/partition/postgrespartitions-drop.sql @@ -0,0 +1,2 @@ +drop table if exists p1; +drop table if exists p2; \ No newline at end of file diff --git a/hibernate-core/src/test/resources/org/hibernate/orm/test/sql/partition/sqlserverpartitions-create.sql b/hibernate-core/src/test/resources/org/hibernate/orm/test/sql/partition/sqlserverpartitions-create.sql new file mode 100644 index 000000000000..69c239b4b3ff --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/orm/test/sql/partition/sqlserverpartitions-create.sql @@ -0,0 +1,2 @@ +CREATE PARTITION FUNCTION partFun (bigint) AS RANGE LEFT FOR VALUES (1000, 2000); +CREATE PARTITION SCHEME partScheme AS PARTITION partFun ALL TO ('PRIMARY'); \ No newline at end of file diff --git a/hibernate-core/src/test/resources/org/hibernate/orm/test/sql/partition/sqlserverpartitions-drop.sql b/hibernate-core/src/test/resources/org/hibernate/orm/test/sql/partition/sqlserverpartitions-drop.sql new file mode 100644 index 000000000000..8fbc9a5a03a1 --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/orm/test/sql/partition/sqlserverpartitions-drop.sql @@ -0,0 +1,2 @@ +DROP PARTITION SCHEME partScheme; +DROP PARTITION FUNCTION partFun;