HHH-11647 - Use ALTER TABLE IF EXISTS on Postgres

This commit is contained in:
ChristophDreis 2017-04-19 18:41:49 +02:00 committed by Vlad Mihalcea
parent 72e0d593b9
commit f85737cb0b
14 changed files with 105 additions and 31 deletions

View File

@ -1451,6 +1451,22 @@ public abstract class Dialect implements ConversionContext {
return "create table";
}
/**
* Command used to alter a table.
*
* @param tableName The name of the table to alter
* @return The command used to alter a table.
* @since 5.2.11
*/
public String getAlterTableString(String tableName) {
final StringBuilder sb = new StringBuilder( "alter table " );
if ( supportsIfExistsAfterAlterTable() ) {
sb.append( "if exists " );
}
sb.append( tableName );
return sb.toString();
}
/**
* Slight variation on {@link #getCreateTableString}. Here, we have the
* command used to create a table when there is no primary key and
@ -2241,6 +2257,16 @@ public abstract class Dialect implements ConversionContext {
return false;
}
/**
* For an "alter table", can the phrase "if exists" be applied?
*
* @return {@code true} if the "if exists" can be applied after ALTER TABLE
* @since 5.2.11
*/
public boolean supportsIfExistsAfterAlterTable() {
return false;
}
/**
* Generate a DROP TABLE statement
*

View File

@ -22,4 +22,10 @@ public class PostgreSQL92Dialect extends PostgreSQL91Dialect {
super();
this.registerColumnType( Types.JAVA_OBJECT, "json" );
}
@Override
public boolean supportsIfExistsAfterAlterTable() {
return true;
}
}

View File

@ -53,7 +53,8 @@ public class DefaultUniqueDelegate implements UniqueDelegate {
);
final String constraintName = dialect.quote( uniqueKey.getName() );
return "alter table " + tableName + " add constraint " + constraintName + " " + uniqueConstraintSql( uniqueKey );
return dialect.getAlterTableString( tableName )
+ " add constraint " + constraintName + " " + uniqueConstraintSql( uniqueKey );
}
protected String uniqueConstraintSql(UniqueKey uniqueKey) {
@ -83,8 +84,7 @@ public class DefaultUniqueDelegate implements UniqueDelegate {
dialect
);
final StringBuilder buf = new StringBuilder( "alter table " );
buf.append( tableName );
final StringBuilder buf = new StringBuilder( dialect.getAlterTableString(tableName) );
buf.append( getDropUnique() );
if ( dialect.supportsIfExistsBeforeConstraintName() ) {
buf.append( "if exists " );

View File

@ -32,7 +32,8 @@ public class InformixUniqueDelegate extends DefaultUniqueDelegate {
metadata.getDatabase().getJdbcEnvironment().getDialect()
);
final String constraintName = dialect.quote( uniqueKey.getName() );
return "alter table " + tableName + " add constraint " + uniqueConstraintSql( uniqueKey ) + " constraint " + constraintName;
return dialect.getAlterTableString( tableName )
+ " add constraint " + uniqueConstraintSql( uniqueKey ) + " constraint " + constraintName;
}
}

View File

@ -165,10 +165,11 @@ public abstract class Constraint implements RelationalModel, Exportable, Seriali
public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema) {
if ( isGenerated( dialect ) ) {
final String tableName = getTable().getQualifiedName( dialect, defaultCatalog, defaultSchema );
return String.format(
Locale.ROOT,
"alter table %s drop constraint %s",
getTable().getQualifiedName( dialect, defaultCatalog, defaultSchema ),
"%s drop constraint %s",
dialect.getAlterTableString( tableName ),
dialect.quote( getName() )
);
}
@ -184,8 +185,8 @@ public abstract class Constraint implements RelationalModel, Exportable, Seriali
// empty string. Prevent blank "alter table" statements.
String constraintString = sqlConstraintString( dialect, getName(), defaultCatalog, defaultSchema );
if ( !StringHelper.isEmpty( constraintString ) ) {
return "alter table " + getTable().getQualifiedName( dialect, defaultCatalog, defaultSchema )
+ constraintString;
final String tableName = getTable().getQualifiedName( dialect, defaultCatalog, defaultSchema );
return dialect.getAlterTableString( tableName ) + " " + constraintString;
}
}
return null;

View File

@ -173,8 +173,8 @@ public class ForeignKey extends Constraint {
}
public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema) {
final StringBuilder buf = new StringBuilder( "alter table " );
buf.append( getTable().getQualifiedName( dialect, defaultCatalog, defaultSchema ) );
String tableName = getTable().getQualifiedName( dialect, defaultCatalog, defaultSchema );
final StringBuilder buf = new StringBuilder( dialect.getAlterTableString( tableName ) );
buf.append( dialect.getDropForeignKeyString() );
if ( dialect.supportsIfExistsBeforeConstraintName() ) {
buf.append( "if exists " );

View File

@ -447,13 +447,12 @@ public class Table implements RelationalModel, Serializable, Exportable {
final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment();
StringBuilder root = new StringBuilder( "alter table " )
.append(
jdbcEnvironment.getQualifiedObjectNameFormatter().format(
tableInfo.getName(),
dialect
)
)
final String tableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format(
tableInfo.getName(),
dialect
);
StringBuilder root = new StringBuilder( dialect.getAlterTableString( tableName ) )
.append( ' ' )
.append( dialect.getAddColumnString() );

View File

@ -100,8 +100,7 @@ public class StandardForeignKeyExporter implements Exporter<ForeignKey> {
dialect
);
final StringBuilder buffer = new StringBuilder( "alter table " )
.append( sourceTableName )
final StringBuilder buffer = new StringBuilder( dialect.getAlterTableString( sourceTableName ) )
.append(
foreignKey.getKeyDefinition() != null ?
dialect.getAddForeignKeyConstraintString(
@ -146,7 +145,8 @@ public class StandardForeignKeyExporter implements Exporter<ForeignKey> {
dialect
);
return new String[] {
"alter table " + sourceTableName + dialect.getDropForeignKeyString() + foreignKey.getName()
dialect.getAlterTableString( sourceTableName )
+ dialect.getDropForeignKeyString() + foreignKey.getName()
};
}
}

View File

@ -0,0 +1,33 @@
/*
* 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.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseUnitTestCase;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* Test case for PostgreSQL 9.2 specific things.
*
* @author Christoph Dreis
*/
public class PostgreSQL92DialectTestCase extends BaseUnitTestCase {
/**
* Tests that getAlterTableString() will make use of IF EXISTS syntax
*/
@Test
@TestForIssue( jiraKey = "HHH-11647" )
public void testGetAlterTableString() {
PostgreSQL92Dialect dialect = new PostgreSQL92Dialect();
assertEquals("alter table if exists table_name", dialect.getAlterTableString( "table_name" ));
}
}

View File

@ -161,8 +161,7 @@ public class ForeignKeyGenerationTest extends BaseUnitTestCase {
final List<String> sqlLines = Files.readAllLines( output.toPath(), Charset.defaultCharset() );
boolean found = false;
for ( String line : sqlLines ) {
if ( line.contains( expectedAlterTableStatement ) ) {
found = true;
if ( line.matches( expectedAlterTableStatement ) ) {
return;
}
}
@ -187,7 +186,7 @@ public class ForeignKeyGenerationTest extends BaseUnitTestCase {
}
public String toSQL() {
return "alter table " + tableName + " add constraint " + fkConstraintName + " foreign key (" + fkColumnName + ") references " + referenceTableName;
return "alter table (?:if exists) " + tableName + " add constraint " + fkConstraintName + " foreign key \\(" + fkColumnName + "\\) references " + referenceTableName;
}
}

View File

@ -78,8 +78,7 @@ public class JoinedInheritanceForeignKeyTest extends BaseUnitTestCase {
final List<String> sqlLines = Files.readAllLines( output.toPath(), Charset.defaultCharset() );
boolean found = false;
for ( String line : sqlLines ) {
if ( line.contains( expectedAlterTableStatement ) ) {
found = true;
if ( line.matches( expectedAlterTableStatement ) ) {
return;
}
}
@ -104,7 +103,7 @@ public class JoinedInheritanceForeignKeyTest extends BaseUnitTestCase {
}
public String toSQL() {
return "alter table " + tableName + " add constraint " + fkConstraintName + " foreign key (" + fkColumnName + ") references " + referenceTableName;
return "alter table (?:if exists) " + tableName + " add constraint " + fkConstraintName + " foreign key \\(" + fkColumnName + "\\) references " + referenceTableName;
}
}

View File

@ -18,6 +18,7 @@ import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.PostgreSQL81Dialect;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.schema.TargetType;
@ -73,7 +74,7 @@ public class SchemaCreationTest {
for ( String statement : sqlLines ) {
assertThat(
"Should not try to create the unique constraint for the non existing table element",
statement.toLowerCase().contains( "alter table element" ),
statement.toLowerCase().matches( "alter table (?:if exists) element" ),
is( false )
);
if (ssr.getService(JdbcEnvironment.class).getDialect() instanceof DB2Dialect) {
@ -81,7 +82,14 @@ public class SchemaCreationTest {
&& statement.toLowerCase().contains("category (code)")) {
isUniqueConstraintCreated = true;
}
} else {
}
else if (ssr.getService(JdbcEnvironment.class).getDialect() instanceof PostgreSQL81Dialect) {
if (statement.toLowerCase().startsWith("alter table if exists category add constraint")
&& statement.toLowerCase().contains("unique (code)")) {
isUniqueConstraintCreated = true;
}
}
else {
if (statement.toLowerCase().startsWith("alter table category add constraint")
&& statement.toLowerCase().contains("unique (code)")) {
isUniqueConstraintCreated = true;

View File

@ -126,7 +126,7 @@ public class UniqueConstraintDropTest {
private boolean checkDropConstraint(String tableName, String columnName) throws IOException {
boolean matches = false;
String regex = "alter table " + tableName + " drop constraint";
String regex = "alter table (?:if exists) " + tableName + " drop constraint";
if ( getDialect().supportsIfExistsBeforeConstraintName() ) {
regex += " if exists";

View File

@ -19,6 +19,7 @@ import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.PostgreSQL81Dialect;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.schema.TargetType;
@ -70,7 +71,8 @@ public class UniqueConstraintGenerationTest {
isCreateUniqueIndexGenerated("test_entity_item", "item"),
is(true)
);
} else {
}
else {
assertThat(
"The test_entity_item table unique constraint has not been generated",
isUniqueConstraintGenerated("test_entity_item", "item"),
@ -87,7 +89,7 @@ public class UniqueConstraintGenerationTest {
private boolean isUniqueConstraintGenerated(String tableName, String columnName) throws IOException {
boolean matches = false;
final String regex = "alter table " + tableName + " add constraint uk_(.)* unique \\(" + columnName + "\\)";
final String regex = "alter table (?:if exists) " + tableName + " add constraint uk_(.)* unique \\(" + columnName + "\\)";
final String fileContent = new String( Files.readAllBytes( output.toPath() ) ).toLowerCase();
final String[] split = fileContent.split( System.lineSeparator() );