diff --git a/liquibase-core/src/main/java/liquibase/change/core/CreateProcedureChange.java b/liquibase-core/src/main/java/liquibase/change/core/CreateProcedureChange.java index 893000016ad..4c8926e6ffa 100644 --- a/liquibase-core/src/main/java/liquibase/change/core/CreateProcedureChange.java +++ b/liquibase-core/src/main/java/liquibase/change/core/CreateProcedureChange.java @@ -176,6 +176,9 @@ public ValidationErrors validate(Database database) { ValidationErrors validate = new ValidationErrors(); validate.checkDisallowedField("catalogName", this.getCatalogName(), database, MSSQLDatabase.class); + if(getDbms() != null) { + DatabaseList.validateDefinitions(getDbms(), validate); + } if ((StringUtil.trimToNull(getProcedureText()) != null) && (StringUtil.trimToNull(getPath()) != null)) { validate.addError( diff --git a/liquibase-core/src/main/java/liquibase/changelog/visitor/ValidatingVisitor.java b/liquibase-core/src/main/java/liquibase/changelog/visitor/ValidatingVisitor.java index e49ec64061f..44198c12cc8 100644 --- a/liquibase-core/src/main/java/liquibase/changelog/visitor/ValidatingVisitor.java +++ b/liquibase-core/src/main/java/liquibase/changelog/visitor/ValidatingVisitor.java @@ -7,6 +7,8 @@ import liquibase.changelog.RanChangeSet; import liquibase.changelog.filter.ChangeSetFilterResult; import liquibase.database.Database; +import liquibase.database.DatabaseFactory; +import liquibase.database.DatabaseList; import liquibase.exception.*; import liquibase.precondition.ErrorPrecondition; import liquibase.precondition.FailedPrecondition; @@ -96,6 +98,10 @@ private RanChangeSet findChangeSet(ChangeSet changeSet) { public void visit(ChangeSet changeSet, DatabaseChangeLog databaseChangeLog, Database database, Set filterResults) throws LiquibaseException { RanChangeSet ranChangeSet = findChangeSet(changeSet); boolean ran = ranChangeSet != null; + Set dbmsSet = changeSet.getDbmsSet(); + if(dbmsSet != null) { + DatabaseList.validateDefinitions(changeSet.getDbmsSet(), validationErrors); + } changeSet.setStoredCheckSum(ran?ranChangeSet.getLastCheckSum():null); boolean shouldValidate = !ran || changeSet.shouldRunOnChange() || changeSet.shouldAlwaysRun(); for (Change change : changeSet.getChanges()) { diff --git a/liquibase-core/src/main/java/liquibase/database/DatabaseList.java b/liquibase-core/src/main/java/liquibase/database/DatabaseList.java index e27e8ccdc79..943c199178a 100644 --- a/liquibase-core/src/main/java/liquibase/database/DatabaseList.java +++ b/liquibase-core/src/main/java/liquibase/database/DatabaseList.java @@ -1,5 +1,6 @@ package liquibase.database; +import liquibase.exception.ValidationErrors; import liquibase.util.StringUtil; import java.util.Collection; @@ -81,4 +82,28 @@ public static Set toDbmsSet(String dbmsList) { } return dbmsSet; } + + /** + * This method will validate whether a dbms is valid and match with supported database, if it doesn't then + * will add a validation error for it. + * @param definition + * @param vErrors + */ + public static void validateDefinitions(String definition, ValidationErrors vErrors) { + if(!definition.contentEquals("none") && !definition.contentEquals("all") && !definition.startsWith("!")) { + Database database = DatabaseFactory.getInstance().getDatabase(definition.toLowerCase()); + if (database == null) { + vErrors.addError(String.format("%s is not a supported DB", definition)); + } + } + } + + /** + * This method will validate if a set of definitions/dbms are valid supported DBs. + * @param definitions + * @param vErrors + */ + public static void validateDefinitions(Collection definitions, ValidationErrors vErrors) { + definitions.stream().forEach( definition -> validateDefinitions(definition, vErrors)); + } } diff --git a/liquibase-core/src/test/groovy/liquibase/change/core/CreateProcedureChangeTest.groovy b/liquibase-core/src/test/groovy/liquibase/change/core/CreateProcedureChangeTest.groovy index 59b86584409..0af58163242 100644 --- a/liquibase-core/src/test/groovy/liquibase/change/core/CreateProcedureChangeTest.groovy +++ b/liquibase-core/src/test/groovy/liquibase/change/core/CreateProcedureChangeTest.groovy @@ -4,12 +4,16 @@ import liquibase.Scope import liquibase.change.StandardChangeTest import liquibase.changelog.ChangeSet import liquibase.changelog.DatabaseChangeLog +import liquibase.database.core.MSSQLDatabase import liquibase.database.core.OracleDatabase +import liquibase.database.core.PostgresDatabase +import liquibase.exception.ValidationErrors import liquibase.parser.core.ParsedNode import liquibase.database.core.MockDatabase import liquibase.sdk.resource.MockResourceAccessor import liquibase.snapshot.MockSnapshotGeneratorFactory import liquibase.snapshot.SnapshotGeneratorFactory +import liquibase.sqlgenerator.core.CreateProcedureGenerator import liquibase.test.JUnitResourceAccessor import liquibase.util.StreamUtil import spock.lang.Unroll @@ -66,11 +70,31 @@ public class CreateProcedureChangeTest extends StandardChangeTest { fileContents.trim() == "My Logic Here" where: - sqlPath | logicalFilePath | relativeToChangelogFile + sqlPath | logicalFilePath | relativeToChangelogFile "com/example/my-logic.sql" | null | false "com/example/my-logic.sql" | "a/logical/path.xml" | false "my-logic.sql" | null | true "my-logic.sql" | "a/logical/path.xml" | true } + + @Unroll + def "validate CreateProcedure with dmbs attribute set"() { + when: + + CreateProcedureChange createProcedure = new CreateProcedureChange(); + createProcedure.setDbms(dbms); + ValidationErrors valErrors = createProcedure.validate(database); + + then: + valErrors.getErrorMessages().get(0).contains(expectedValidationErrorMsg); + + where: + database | dbms | expectedValidationErrorMsg + new PostgresDatabase() | "post" | String.format("%s is not a supported DB", dbms) + new PostgresDatabase() | "postgresql" | "" + new MockDatabase() | "postgresql, h2, mssql, !sqlite" | "" + new PostgresDatabase() | "none" | "" + new PostgresDatabase() | "all" | "" + } } diff --git a/liquibase-core/src/test/java/liquibase/changelog/visitor/ValidatingVisitorTest.java b/liquibase-core/src/test/java/liquibase/changelog/visitor/ValidatingVisitorTest.java index 820e5cb3769..8533d9d81fc 100644 --- a/liquibase-core/src/test/java/liquibase/changelog/visitor/ValidatingVisitorTest.java +++ b/liquibase-core/src/test/java/liquibase/changelog/visitor/ValidatingVisitorTest.java @@ -26,6 +26,7 @@ public class ValidatingVisitorTest { public void setup() { changeSet1 = new ChangeSet("1", "testAuthor", false, false, "path/changelog", null, null, null); changeSet2 = new ChangeSet("2", "testAuthor", false, false, "path/changelog", null, null, null); + } @@ -129,4 +130,90 @@ public ValidationErrors validate(Database database) { assertTrue(handler.validationPassed()); } + + @Test + public void visit_successfulWithSingleValidDbmsSet() throws Exception { + CreateTableChange change = new CreateTableChange(); + change.setTableName("table1"); + ColumnConfig column1 = new ColumnConfig(); + change.addColumn(column1); + column1.setName("col1"); + column1.setType("int"); + + ChangeSet changeSet = new ChangeSet("1", "testAuthor", false, false, "path/changelog", null, "postgresql", null); + changeSet.addChange(change); + + ValidatingVisitor handler = new ValidatingVisitor(new ArrayList()); + handler.visit(changeSet, new DatabaseChangeLog(), new MockDatabase(), null); + + assertTrue(handler.validationPassed()); + } + + @Test + public void visit_successfulWithValidListOfDbmsSet() throws Exception { + CreateTableChange change = new CreateTableChange(); + change.setTableName("table1"); + ColumnConfig column1 = new ColumnConfig(); + change.addColumn(column1); + column1.setName("col1"); + column1.setType("int"); + ChangeSet changeSet = new ChangeSet("1", "testAuthor", false, false, "path/changelog", null, "postgresql, mssql, h2", null); + changeSet.addChange(change); + + ValidatingVisitor handler = new ValidatingVisitor(new ArrayList()); + handler.visit(changeSet, new DatabaseChangeLog(), new MockDatabase(), null); + + assertTrue(handler.validationPassed()); + } + + @Test + public void visit_unsuccessfulWithInvalidDbmsSet() throws Exception { + CreateTableChange change = new CreateTableChange(); + change.setTableName("table1"); + ColumnConfig column1 = new ColumnConfig(); + change.addColumn(column1); + column1.setName("col1"); + column1.setType("int"); + ChangeSet changeSet = new ChangeSet("1", "testAuthor", false, false, "path/changelog", null, "post", null); + changeSet.addChange(change); + + ValidatingVisitor handler = new ValidatingVisitor(new ArrayList()); + handler.visit(changeSet, new DatabaseChangeLog(), new MockDatabase(), null); + + assertFalse(handler.validationPassed()); + } + + @Test + public void visit_successfulWithNoneSetAsDbms() throws Exception { + CreateTableChange change = new CreateTableChange(); + change.setTableName("table1"); + ColumnConfig column1 = new ColumnConfig(); + change.addColumn(column1); + column1.setName("col1"); + column1.setType("int"); + ChangeSet changeSet = new ChangeSet("1", "testAuthor", false, false, "path/changelog", null, "none", null); + changeSet.addChange(change); + + ValidatingVisitor handler = new ValidatingVisitor(new ArrayList()); + handler.visit(changeSet, new DatabaseChangeLog(), new MockDatabase(), null); + + assertTrue(handler.validationPassed()); + } + + @Test + public void visit_successfulWithAllSetAsDbms() throws Exception { + CreateTableChange change = new CreateTableChange(); + change.setTableName("table1"); + ColumnConfig column1 = new ColumnConfig(); + change.addColumn(column1); + column1.setName("col1"); + column1.setType("int"); + ChangeSet changeSet = new ChangeSet("1", "testAuthor", false, false, "path/changelog", null, "all", null); + changeSet.addChange(change); + + ValidatingVisitor handler = new ValidatingVisitor(new ArrayList()); + handler.visit(changeSet, new DatabaseChangeLog(), new MockDatabase(), null); + + assertTrue(handler.validationPassed()); + } } diff --git a/liquibase-integration-tests/src/test/resources/changelogs/common/batchInsert.changelog.xml b/liquibase-integration-tests/src/test/resources/changelogs/common/batchInsert.changelog.xml index 1ccf72448b5..f4b687cbe8c 100644 --- a/liquibase-integration-tests/src/test/resources/changelogs/common/batchInsert.changelog.xml +++ b/liquibase-integration-tests/src/test/resources/changelogs/common/batchInsert.changelog.xml @@ -34,7 +34,7 @@ + dbms="db2,derby,h2,hsqldb,informix,mariadb,mysql,oracle,postgresql,sqlite,asany,sybase"> diff --git a/liquibase-integration-tests/src/test/resources/changelogs/common/common.tests.changelog.xml b/liquibase-integration-tests/src/test/resources/changelogs/common/common.tests.changelog.xml index 0eb4ffc9ad0..b4ac1d9b57a 100644 --- a/liquibase-integration-tests/src/test/resources/changelogs/common/common.tests.changelog.xml +++ b/liquibase-integration-tests/src/test/resources/changelogs/common/common.tests.changelog.xml @@ -195,7 +195,7 @@ - + @@ -745,7 +745,7 @@ insert into default_val_computed (id) values (1); - + @@ -1064,12 +1064,12 @@ + dbms="db2,derby,firebird,h2,hsqldb,informix,mssql,oracle,postgresql,sqlite,asany,sybase"> Test if we (and the JDBC driver) correctly support TIMESTAMP columns with a extra-large precision of 9 for supported DBMS. - + diff --git a/liquibase-integration-tests/src/test/resources/changelogs/json/common.tests.changelog.json b/liquibase-integration-tests/src/test/resources/changelogs/json/common.tests.changelog.json index 94e7a7f04e0..0a93fac65ac 100644 --- a/liquibase-integration-tests/src/test/resources/changelogs/json/common.tests.changelog.json +++ b/liquibase-integration-tests/src/test/resources/changelogs/json/common.tests.changelog.json @@ -654,7 +654,7 @@ "changeSet": { "id": "hasIndexPrecondition", "author": "nvoxland", - "dbms": "oracle,mssql,mysql,h2,hsql,postgresql", + "dbms": "oracle,mssql,mysql,h2,hsqldb,postgresql", "preConditions": [ { "indexExists": { diff --git a/liquibase-integration-tests/src/test/resources/changelogs/yaml/common.tests.changelog.yaml b/liquibase-integration-tests/src/test/resources/changelogs/yaml/common.tests.changelog.yaml index b8853386787..afa2ead5644 100644 --- a/liquibase-integration-tests/src/test/resources/changelogs/yaml/common.tests.changelog.yaml +++ b/liquibase-integration-tests/src/test/resources/changelogs/yaml/common.tests.changelog.yaml @@ -332,7 +332,7 @@ databaseChangeLog: - changeSet: id: hasIndexPrecondition author: nvoxland - dbms: oracle,mssql,mysql,h2,hsql,postgresql # can checkConstraint with or without table name, derby doesn't work with just column names + dbms: oracle,mssql,mysql,h2,hsqldb,postgresql # can checkConstraint with or without table name, derby doesn't work with just column names preConditions: - indexExists: indexName: idx_compoundtest