Skip to content

Commit 76981d9

Browse files
committed
HHH-13202 - Add support for PostgreSQL "GENERATED BY DEFAULT AS IDENTITY"
HHH-13106 - Hibernate fails with Schema-validation: missing sequence
1 parent ba4d742 commit 76981d9

File tree

7 files changed

+236
-4
lines changed

7 files changed

+236
-4
lines changed

gradle/databases.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ ext {
3838
'jdbc.url' : 'jdbc:postgresql:hibernate_orm_test'
3939
],
4040
pgsql_docker : [
41-
'db.dialect' : 'org.hibernate.dialect.PostgreSQL95Dialect',
41+
'db.dialect' : 'org.hibernate.dialect.PostgreSQL10Dialect',
4242
'jdbc.driver': 'org.postgresql.Driver',
4343
'jdbc.user' : 'hibernate_orm_test',
4444
'jdbc.pass' : 'hibernate_orm_test',

hibernate-core/src/main/java/org/hibernate/dialect/Database.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ public Dialect resolveDialect(DialectResolutionInfo info) {
403403
POSTGRESQL {
404404
@Override
405405
public Class<? extends Dialect> latestDialect() {
406-
return PostgreSQL95Dialect.class;
406+
return PostgreSQL10Dialect.class;
407407
}
408408

409409
@Override
@@ -432,7 +432,7 @@ else if ( minorVersion < 4 ) {
432432
else if ( minorVersion < 5 ) {
433433
return new PostgreSQL94Dialect();
434434
}
435-
else if ( minorVersion < 6 ) {
435+
else {
436436
return new PostgreSQL95Dialect();
437437
}
438438
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.dialect;
8+
9+
import org.hibernate.dialect.identity.IdentityColumnSupport;
10+
import org.hibernate.dialect.identity.PostgreSQL10IdentityColumnSupport;
11+
12+
/**
13+
* An SQL dialect for Postgres 10 and later.
14+
*/
15+
public class PostgreSQL10Dialect extends PostgreSQL95Dialect {
16+
17+
@Override
18+
public IdentityColumnSupport getIdentityColumnSupport() {
19+
return new PostgreSQL10IdentityColumnSupport();
20+
}
21+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.dialect.identity;
8+
9+
/**
10+
* @author Vlad Mihalcea
11+
*/
12+
public class PostgreSQL10IdentityColumnSupport extends IdentityColumnSupportImpl {
13+
@Override
14+
public boolean supportsIdentityColumns() {
15+
return true;
16+
}
17+
18+
@Override
19+
public String getIdentitySelectString(String table, String column, int type) {
20+
return "select currval('" + table + '_' + column + "_seq')";
21+
}
22+
23+
@Override
24+
public String getIdentityColumnString(int type) {
25+
return "generated by default as identity";
26+
}
27+
28+
@Override
29+
public boolean hasDataTypeInIdentityColumn() {
30+
return true;
31+
}
32+
}

hibernate-core/src/test/java/org/hibernate/dialect/resolver/DialectFactoryTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ public void testPreregisteredDialects() {
129129
testDetermination( "PostgreSQL", 9, 3, PostgreSQL92Dialect.class, resolver );
130130
testDetermination( "PostgreSQL", 9, 4, PostgreSQL94Dialect.class, resolver );
131131
testDetermination( "PostgreSQL", 9, 5, PostgreSQL95Dialect.class, resolver );
132-
testDetermination( "PostgreSQL", 10, 0, PostgreSQL95Dialect.class, resolver );
132+
testDetermination( "PostgreSQL", 9, 6, PostgreSQL95Dialect.class, resolver );
133+
testDetermination( "PostgreSQL", 10, 0, PostgreSQL10Dialect.class, resolver );
133134
testDetermination( "EnterpriseDB", 9, 2, PostgresPlusDialect.class, resolver );
134135
testDetermination( "Apache Derby", 10, 4, DerbyDialect.class, resolver );
135136
testDetermination( "Apache Derby", 10, 5, DerbyTenFiveDialect.class, resolver );
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.test.id.sequence;
8+
9+
import java.sql.Connection;
10+
import java.sql.SQLException;
11+
import java.sql.Statement;
12+
import java.util.EnumSet;
13+
import java.util.Map;
14+
import javax.persistence.Column;
15+
import javax.persistence.Entity;
16+
import javax.persistence.GeneratedValue;
17+
import javax.persistence.GenerationType;
18+
import javax.persistence.Id;
19+
import javax.persistence.SequenceGenerator;
20+
21+
import org.hibernate.boot.MetadataSources;
22+
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
23+
import org.hibernate.boot.spi.MetadataImplementor;
24+
import org.hibernate.cfg.AvailableSettings;
25+
import org.hibernate.cfg.Environment;
26+
import org.hibernate.dialect.PostgreSQL10Dialect;
27+
import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl;
28+
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
29+
import org.hibernate.service.ServiceRegistry;
30+
import org.hibernate.tool.hbm2ddl.SchemaExport;
31+
import org.hibernate.tool.schema.TargetType;
32+
33+
import org.hibernate.testing.RequiresDialect;
34+
import org.junit.Test;
35+
36+
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
37+
import static org.junit.Assert.fail;
38+
39+
/**
40+
* @author Vlad Mhalcea
41+
*/
42+
@RequiresDialect(jiraKey = "HHH-13106", value = PostgreSQL10Dialect.class)
43+
public class PostgreSQLIdentitySequenceTest extends BaseEntityManagerFunctionalTestCase {
44+
45+
@Override
46+
protected Class[] getAnnotatedClasses() {
47+
return new Class[] { Role.class };
48+
}
49+
50+
private DriverManagerConnectionProviderImpl connectionProvider;
51+
52+
@Override
53+
public void buildEntityManagerFactory() {
54+
connectionProvider = new DriverManagerConnectionProviderImpl();
55+
connectionProvider.configure( Environment.getProperties() );
56+
57+
try(Connection connection = connectionProvider.getConnection();
58+
Statement statement = connection.createStatement()) {
59+
statement.execute( "DROP TABLE IF EXISTS roles CASCADE" );
60+
statement.execute( "CREATE TABLE roles ( id BIGINT NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY )" );
61+
}
62+
catch (SQLException e) {
63+
fail(e.getMessage());
64+
}
65+
66+
super.buildEntityManagerFactory();
67+
}
68+
69+
@Override
70+
public void releaseResources() {
71+
super.releaseResources();
72+
73+
try(Connection connection = connectionProvider.getConnection();
74+
Statement statement = connection.createStatement()) {
75+
statement.execute( "DROP TABLE IF EXISTS roles CASCADE" );
76+
}
77+
catch (SQLException e) {
78+
fail(e.getMessage());
79+
}
80+
81+
if ( connectionProvider != null ) {
82+
connectionProvider.stop();
83+
}
84+
}
85+
86+
@Test
87+
public void test() {
88+
doInJPA( this::entityManagerFactory, entityManager -> {
89+
Role role = new Role();
90+
entityManager.persist( role );
91+
} );
92+
}
93+
94+
@Entity(name = "Role")
95+
public static class Role {
96+
97+
@Id
98+
@Column(name = "id")
99+
@SequenceGenerator(name = "roles_id_seq", sequenceName = "roles_id_seq", allocationSize = 1)
100+
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "roles_id_seq")
101+
private Long id;
102+
103+
public Long getId() {
104+
return id;
105+
}
106+
107+
public void setId(final Long id) {
108+
this.id = id;
109+
}
110+
}
111+
112+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
6+
*/
7+
package org.hibernate.test.id.sequence;
8+
9+
import javax.persistence.Entity;
10+
import javax.persistence.GeneratedValue;
11+
import javax.persistence.GenerationType;
12+
import javax.persistence.Id;
13+
14+
import org.hibernate.dialect.PostgreSQL10Dialect;
15+
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
16+
17+
import org.hibernate.testing.RequiresDialect;
18+
import org.junit.Test;
19+
20+
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
21+
import static org.junit.Assert.assertNotNull;
22+
23+
/**
24+
* @author Vlad Mhalcea
25+
*/
26+
@RequiresDialect(jiraKey = "HHH-13202", value = PostgreSQL10Dialect.class)
27+
public class PostgreSQLIdentitySupportTest extends BaseEntityManagerFunctionalTestCase {
28+
29+
@Override
30+
protected Class[] getAnnotatedClasses() {
31+
return new Class[] { Role.class };
32+
}
33+
34+
@Test
35+
public void test() {
36+
Role _role = doInJPA( this::entityManagerFactory, entityManager -> {
37+
Role role = new Role();
38+
39+
entityManager.persist( role );
40+
41+
return role;
42+
} );
43+
44+
doInJPA( this::entityManagerFactory, entityManager -> {
45+
Role role = entityManager.find( Role.class, _role.getId() );
46+
assertNotNull(role);
47+
} );
48+
}
49+
50+
@Entity(name = "Role")
51+
public static class Role {
52+
53+
@Id
54+
@GeneratedValue(strategy = GenerationType.IDENTITY)
55+
private Long id;
56+
57+
public Long getId() {
58+
return id;
59+
}
60+
61+
public void setId(final Long id) {
62+
this.id = id;
63+
}
64+
}
65+
66+
}

0 commit comments

Comments
 (0)