HHH-13202 - Add support for PostgreSQL "GENERATED BY DEFAULT AS IDENTITY"

HHH-13106 - Hibernate fails with Schema-validation: missing sequence
This commit is contained in:
Vlad Mihalcea 2019-01-14 14:23:31 +02:00
parent ba4d742d34
commit 76981d97a8
7 changed files with 236 additions and 4 deletions

View File

@ -38,7 +38,7 @@ ext {
'jdbc.url' : 'jdbc:postgresql:hibernate_orm_test'
],
pgsql_docker : [
'db.dialect' : 'org.hibernate.dialect.PostgreSQL95Dialect',
'db.dialect' : 'org.hibernate.dialect.PostgreSQL10Dialect',
'jdbc.driver': 'org.postgresql.Driver',
'jdbc.user' : 'hibernate_orm_test',
'jdbc.pass' : 'hibernate_orm_test',

View File

@ -403,7 +403,7 @@ public enum Database {
POSTGRESQL {
@Override
public Class<? extends Dialect> latestDialect() {
return PostgreSQL95Dialect.class;
return PostgreSQL10Dialect.class;
}
@Override
@ -432,7 +432,7 @@ public enum Database {
else if ( minorVersion < 5 ) {
return new PostgreSQL94Dialect();
}
else if ( minorVersion < 6 ) {
else {
return new PostgreSQL95Dialect();
}
}

View File

@ -0,0 +1,21 @@
/*
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.dialect;
import org.hibernate.dialect.identity.IdentityColumnSupport;
import org.hibernate.dialect.identity.PostgreSQL10IdentityColumnSupport;
/**
* An SQL dialect for Postgres 10 and later.
*/
public class PostgreSQL10Dialect extends PostgreSQL95Dialect {
@Override
public IdentityColumnSupport getIdentityColumnSupport() {
return new PostgreSQL10IdentityColumnSupport();
}
}

View File

@ -0,0 +1,32 @@
/*
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.dialect.identity;
/**
* @author Vlad Mihalcea
*/
public class PostgreSQL10IdentityColumnSupport extends IdentityColumnSupportImpl {
@Override
public boolean supportsIdentityColumns() {
return true;
}
@Override
public String getIdentitySelectString(String table, String column, int type) {
return "select currval('" + table + '_' + column + "_seq')";
}
@Override
public String getIdentityColumnString(int type) {
return "generated by default as identity";
}
@Override
public boolean hasDataTypeInIdentityColumn() {
return true;
}
}

View File

@ -129,7 +129,8 @@ public class DialectFactoryTest extends BaseUnitTestCase {
testDetermination( "PostgreSQL", 9, 3, PostgreSQL92Dialect.class, resolver );
testDetermination( "PostgreSQL", 9, 4, PostgreSQL94Dialect.class, resolver );
testDetermination( "PostgreSQL", 9, 5, PostgreSQL95Dialect.class, resolver );
testDetermination( "PostgreSQL", 10, 0, PostgreSQL95Dialect.class, resolver );
testDetermination( "PostgreSQL", 9, 6, PostgreSQL95Dialect.class, resolver );
testDetermination( "PostgreSQL", 10, 0, PostgreSQL10Dialect.class, resolver );
testDetermination( "EnterpriseDB", 9, 2, PostgresPlusDialect.class, resolver );
testDetermination( "Apache Derby", 10, 4, DerbyDialect.class, resolver );
testDetermination( "Apache Derby", 10, 5, DerbyTenFiveDialect.class, resolver );

View File

@ -0,0 +1,112 @@
/*
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.id.sequence;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.EnumSet;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.PostgreSQL10Dialect;
import org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.schema.TargetType;
import org.hibernate.testing.RequiresDialect;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.fail;
/**
* @author Vlad Mhalcea
*/
@RequiresDialect(jiraKey = "HHH-13106", value = PostgreSQL10Dialect.class)
public class PostgreSQLIdentitySequenceTest extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class[] getAnnotatedClasses() {
return new Class[] { Role.class };
}
private DriverManagerConnectionProviderImpl connectionProvider;
@Override
public void buildEntityManagerFactory() {
connectionProvider = new DriverManagerConnectionProviderImpl();
connectionProvider.configure( Environment.getProperties() );
try(Connection connection = connectionProvider.getConnection();
Statement statement = connection.createStatement()) {
statement.execute( "DROP TABLE IF EXISTS roles CASCADE" );
statement.execute( "CREATE TABLE roles ( id BIGINT NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY )" );
}
catch (SQLException e) {
fail(e.getMessage());
}
super.buildEntityManagerFactory();
}
@Override
public void releaseResources() {
super.releaseResources();
try(Connection connection = connectionProvider.getConnection();
Statement statement = connection.createStatement()) {
statement.execute( "DROP TABLE IF EXISTS roles CASCADE" );
}
catch (SQLException e) {
fail(e.getMessage());
}
if ( connectionProvider != null ) {
connectionProvider.stop();
}
}
@Test
public void test() {
doInJPA( this::entityManagerFactory, entityManager -> {
Role role = new Role();
entityManager.persist( role );
} );
}
@Entity(name = "Role")
public static class Role {
@Id
@Column(name = "id")
@SequenceGenerator(name = "roles_id_seq", sequenceName = "roles_id_seq", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "roles_id_seq")
private Long id;
public Long getId() {
return id;
}
public void setId(final Long id) {
this.id = id;
}
}
}

View File

@ -0,0 +1,66 @@
/*
* 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 <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.id.sequence;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import org.hibernate.dialect.PostgreSQL10Dialect;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.RequiresDialect;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
import static org.junit.Assert.assertNotNull;
/**
* @author Vlad Mhalcea
*/
@RequiresDialect(jiraKey = "HHH-13202", value = PostgreSQL10Dialect.class)
public class PostgreSQLIdentitySupportTest extends BaseEntityManagerFunctionalTestCase {
@Override
protected Class[] getAnnotatedClasses() {
return new Class[] { Role.class };
}
@Test
public void test() {
Role _role = doInJPA( this::entityManagerFactory, entityManager -> {
Role role = new Role();
entityManager.persist( role );
return role;
} );
doInJPA( this::entityManagerFactory, entityManager -> {
Role role = entityManager.find( Role.class, _role.getId() );
assertNotNull(role);
} );
}
@Entity(name = "Role")
public static class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
public Long getId() {
return id;
}
public void setId(final Long id) {
this.id = id;
}
}
}