/** * Implementation delegates logic to the {@link * liquibase.sqlgenerator.SqlGenerator#warn(liquibase.statement.SqlStatement, * liquibase.database.Database, liquibase.sqlgenerator.SqlGeneratorChain)} method on the {@link * SqlStatement} objects returned by {@link #generateStatements }. If a generated statement is not * supported for the given database, no warning will be added since that is a validation error. If * no or null SqlStatements are returned by generateStatements then this method returns no * warnings. */ @Override public Warnings warn(Database database) { Warnings warnings = new Warnings(); if (generateStatementsVolatile(database)) { return warnings; } SqlStatement[] statements = generateStatements(database); if (statements == null) { return warnings; } for (SqlStatement statement : statements) { if (SqlGeneratorFactory.getInstance().supports(statement, database)) { warnings.addAll(SqlGeneratorFactory.getInstance().warn(statement, database)); } else if (statement.skipOnUnsupported()) { warnings.addWarning( statement.getClass().getName() + " is not supported on " + database.getShortName() + ", but " + ChangeFactory.getInstance().getChangeMetaData(this).getName() + " will still execute"); } } return warnings; }
public Warnings warn(Database database) { Warnings warnings = new Warnings(); for (SqlStatement statement : generateStatements(database)) { if (SqlGeneratorFactory.getInstance().supports(statement, database)) { warnings.addAll(SqlGeneratorFactory.getInstance().warn(statement, database)); } } return warnings; }
public void printNonRenames(DatabaseSnapshot reference, DatabaseSnapshot target, StringBuilder sb) throws Exception { CompareControl compareControl = new CompareControl(reference.getSnapshotControl().getTypesToInclude()); DiffResult diffResult = DiffGeneratorFactory.getInstance().compare(reference, target, compareControl); DiffToChangeLog diffToChangeLog = new DiffToChangeLog(diffResult, new DiffOutputControl(false, false, false)); SqlGeneratorFactory generatorFactory = SqlGeneratorFactory.getInstance(); for (ChangeSet changeSet : diffToChangeLog.generateChangeSets()) { for (Change change : changeSet.getChanges()) { for (SqlStatement sqlStatement : change.generateStatements(LiquibaseModelFactory.DATABASE)) { for (Sql sql : generatorFactory.generateSql(sqlStatement, LiquibaseModelFactory.DATABASE)) { final String sqlString = sql.toSql(); if (sqlString.endsWith("DROP INDEX")) { sb.append(StringUtils.substringBefore(sqlString, " DROP INDEX")).append(";\n"); } else { sb.append(sqlString).append(";\n"); } } } } } }
@Override public Sql[] generateSql( CreateDatabaseChangeLogTableStatement statement, Database database, SqlGeneratorChain sqlGeneratorChain) { /* Because Informix has some limitations on the primary key column cumulative size (same is for unique indices), * the ID's column has been made the sole primary key, and also has a reduced size. * * The original configuration provided by the base class causes the database changelog table not to be created. */ CreateTableStatement createTableStatement = new CreateTableStatement( database.getLiquibaseCatalogName(), database.getLiquibaseSchemaName(), database.getDatabaseChangeLogTableName()) .addPrimaryKeyColumn( "ID", DataTypeFactory.getInstance().fromDescription("VARCHAR(" + getIdColumnSize() + ")"), null, null, null, new NotNullConstraint()) .addColumn( "AUTHOR", DataTypeFactory.getInstance() .fromDescription("VARCHAR(" + getAuthorColumnSize() + ")"), null, null, null, new NotNullConstraint()) .addColumn( "FILENAME", DataTypeFactory.getInstance() .fromDescription("VARCHAR(" + getFilenameColumnSize() + ")"), null, null, null, new NotNullConstraint()) .addColumn( "DATEEXECUTED", DataTypeFactory.getInstance().fromDescription("datetime"), null, new NotNullConstraint()) .addColumn( "ORDEREXECUTED", DataTypeFactory.getInstance().fromDescription("INT"), new NotNullConstraint()) .addColumn( "EXECTYPE", DataTypeFactory.getInstance().fromDescription("VARCHAR(10)"), new NotNullConstraint()) .addColumn("MD5SUM", DataTypeFactory.getInstance().fromDescription("VARCHAR(35)")) .addColumn("DESCRIPTION", DataTypeFactory.getInstance().fromDescription("VARCHAR(255)")) .addColumn("COMMENTS", DataTypeFactory.getInstance().fromDescription("VARCHAR(255)")) .addColumn("TAG", DataTypeFactory.getInstance().fromDescription("VARCHAR(255)")) .addColumn("LIQUIBASE", DataTypeFactory.getInstance().fromDescription("VARCHAR(20)")); return SqlGeneratorFactory.getInstance().generateSql(createTableStatement, database); }
/** * Implementation checks the ChangeParameterMetaData for declared required fields and also * delegates logic to the {@link * liquibase.sqlgenerator.SqlGenerator#validate(liquibase.statement.SqlStatement, * liquibase.database.Database, liquibase.sqlgenerator.SqlGeneratorChain)} method on the {@link * SqlStatement} objects returned by {@link #generateStatements }. If no or null SqlStatements are * returned by generateStatements then this method returns no errors. If there are no parameters * than this method returns no errors */ @Override public ValidationErrors validate(Database database) { ValidationErrors changeValidationErrors = new ValidationErrors(); for (ChangeParameterMetaData param : ChangeFactory.getInstance().getChangeMetaData(this).getParameters().values()) { if (param.isRequiredFor(database) && param.getCurrentValue(this) == null) { changeValidationErrors.addError( param.getParameterName() + " is required for " + ChangeFactory.getInstance().getChangeMetaData(this).getName() + " on " + database.getShortName()); } } if (changeValidationErrors.hasErrors()) { return changeValidationErrors; } String unsupportedWarning = ChangeFactory.getInstance().getChangeMetaData(this).getName() + " is not supported on " + database.getShortName(); if (!this.supports(database)) { changeValidationErrors.addError(unsupportedWarning); } else if (!generateStatementsVolatile(database)) { boolean sawUnsupportedError = false; SqlStatement[] statements; statements = generateStatements(database); if (statements != null) { for (SqlStatement statement : statements) { boolean supported = SqlGeneratorFactory.getInstance().supports(statement, database); if (!supported && !sawUnsupportedError) { if (!statement.skipOnUnsupported()) { changeValidationErrors.addError(unsupportedWarning); sawUnsupportedError = true; } } else { changeValidationErrors.addAll( SqlGeneratorFactory.getInstance().validate(statement, database)); } } } } return changeValidationErrors; }
public boolean supports(Database database) { for (SqlStatement statement : generateStatements(database)) { if (!SqlGeneratorFactory.getInstance().supports(statement, database)) { return false; } } return true; }
public boolean requiresUpdatedDatabaseMetadata(Database database) { for (SqlStatement statement : generateStatements(database)) { if (SqlGeneratorFactory.getInstance().requiresCurrentDatabaseMetadata(statement, database)) { return true; } } return false; }
public Set<DatabaseObject> getAffectedDatabaseObjects(Database database) { Set<DatabaseObject> affectedObjects = new HashSet<DatabaseObject>(); for (SqlStatement statement : generateStatements(database)) { affectedObjects.addAll( SqlGeneratorFactory.getInstance().getAffectedDatabaseObjects(statement, database)); } return affectedObjects; }
@Override public void saveRollbackStatement(Change change, List<SqlVisitor> sqlVisitors, Writer writer) throws IOException, UnsupportedChangeException, RollbackImpossibleException, StatementNotSupportedOnDatabaseException, LiquibaseException { SqlStatement[] statements = change.generateRollbackStatements(this); for (SqlStatement statement : statements) { for (Sql sql : SqlGeneratorFactory.getInstance().generateSql(statement, this)) { writer.append(sql.toSql()).append(sql.getEndDelimiter()).append("\n\n"); } } }
@Override public Sql[] generateSql( final AddAutoIncrementStatement statement, Database database, SqlGeneratorChain sqlGeneratorChain) { List<Sql> statements = new ArrayList<Sql>(); // define alter table logic SQLiteDatabase.AlterTableVisitor rename_alter_visitor = new SQLiteDatabase.AlterTableVisitor() { @Override public ColumnConfig[] getColumnsToAdd() { return new ColumnConfig[0]; } @Override public boolean copyThisColumn(ColumnConfig column) { return true; } @Override public boolean createThisColumn(ColumnConfig column) { if (column.getName().equals(statement.getColumnName())) { column.setAutoIncrement(true); column.setType("INTEGER"); } return true; } @Override public boolean createThisIndex(Index index) { return true; } }; try { // alter table for (SqlStatement generatedStatement : SQLiteDatabase.getAlterTableStatements( rename_alter_visitor, database, statement.getCatalogName(), statement.getSchemaName(), statement.getTableName())) { statements.addAll( Arrays.asList( SqlGeneratorFactory.getInstance().generateSql(generatedStatement, database))); } } catch (DatabaseException e) { e.printStackTrace(); } return statements.toArray(new Sql[statements.size()]); }
/* * Executes the statements passed * * @param statements an array containing the SQL statements to be issued * @param sqlVisitors a list of {@link SqlVisitor} objects to be applied to the executed statements * @throws DatabaseException if there were problems issuing the statements */ @Override public void execute(final SqlStatement[] statements, final List<SqlVisitor> sqlVisitors) throws LiquibaseException { for (SqlStatement statement : statements) { if (statement.skipOnUnsupported() && !SqlGeneratorFactory.getInstance().supports(statement, this)) { continue; } LogFactory.getLogger().debug("Executing Statement: " + statement); ExecutorService.getInstance().getExecutor(this).execute(statement, sqlVisitors); } }
/** * Implementation delegates logic to the {@link * liquibase.sqlgenerator.SqlGenerator#generateStatementsIsVolatile(Database) } method on the * {@link SqlStatement} objects returned by {@link #generateStatements }. If zero or null * SqlStatements are returned by generateStatements then this method returns false. */ @Override public boolean generateStatementsVolatile(Database database) { SqlStatement[] statements = generateStatements(database); if (statements == null) { return false; } for (SqlStatement statement : statements) { if (SqlGeneratorFactory.getInstance().generateStatementsVolatile(statement, database)) { return true; } } return false; }
protected void addUniqueConstrantStatements( AddColumnStatement statement, Database database, List<Sql> returnSql) { if (statement.isUnique()) { AddUniqueConstraintStatement addConstraintStmt = new AddUniqueConstraintStatement( statement.getCatalogName(), statement.getSchemaName(), statement.getTableName(), ColumnConfig.arrayFromNames(statement.getColumnName()), statement.getUniqueStatementName()); returnSql.addAll( Arrays.asList( SqlGeneratorFactory.getInstance().generateSql(addConstraintStmt, database))); } }
public ValidationErrors validate(Database database) { ValidationErrors changeValidationErrors = new ValidationErrors(); for (SqlStatement statement : generateStatements(database)) { boolean supported = SqlGeneratorFactory.getInstance().supports(statement, database); if (!supported) { if (statement.skipOnUnsupported()) { LogFactory.getLogger() .info( getChangeMetaData().getName() + " is not supported on " + database.getTypeName() + " but will continue"); } else { changeValidationErrors.addError( getChangeMetaData().getName() + " is not supported on " + database.getTypeName()); } } else { changeValidationErrors.addAll( SqlGeneratorFactory.getInstance().validate(statement, database)); } } return changeValidationErrors; }
@Override public void saveStatements( final Change change, final List<SqlVisitor> sqlVisitors, final Writer writer) throws IOException, StatementNotSupportedOnDatabaseException, LiquibaseException { SqlStatement[] statements = change.generateStatements(this); for (SqlStatement statement : statements) { for (Sql sql : SqlGeneratorFactory.getInstance().generateSql(statement, this)) { writer .append(sql.toSql()) .append(sql.getEndDelimiter()) .append(StreamUtil.getLineSeparator()) .append(StreamUtil.getLineSeparator()); } } }
/** * Implementation delegates logic to the {@link * liquibase.sqlgenerator.SqlGeneratorFactory#getAffectedDatabaseObjects(liquibase.statement.SqlStatement, * liquibase.database.Database)} method on the {@link SqlStatement} objects returned by {@link * #generateStatements } Returns empty set if change is not supported for the passed database */ @Override public Set<DatabaseObject> getAffectedDatabaseObjects(Database database) { if (this.generateStatementsVolatile(database)) { return new HashSet<DatabaseObject>(); } Set<DatabaseObject> affectedObjects = new HashSet<DatabaseObject>(); SqlStatement[] statements = generateStatements(database); if (statements != null) { for (SqlStatement statement : statements) { affectedObjects.addAll( SqlGeneratorFactory.getInstance().getAffectedDatabaseObjects(statement, database)); } } return affectedObjects; }
protected void addForeignKeyStatements( AddColumnStatement statement, Database database, List<Sql> returnSql) { for (ColumnConstraint constraint : statement.getConstraints()) { if (constraint instanceof ForeignKeyConstraint) { ForeignKeyConstraint fkConstraint = (ForeignKeyConstraint) constraint; String refSchemaName = null; String refTableName; String refColName; if (fkConstraint.getReferences() != null) { Matcher referencesMatcher = Pattern.compile("([\\w\\._]+)\\(([\\w_]+)\\)").matcher(fkConstraint.getReferences()); if (!referencesMatcher.matches()) { throw new UnexpectedLiquibaseException( "Don't know how to find table and column names from " + fkConstraint.getReferences()); } refTableName = referencesMatcher.group(1); refColName = referencesMatcher.group(2); } else { refTableName = ((ForeignKeyConstraint) constraint).getReferencedTableName(); refColName = ((ForeignKeyConstraint) constraint).getReferencedColumnNames(); } if (refTableName.indexOf(".") > 0) { refSchemaName = refTableName.split("\\.")[0]; refTableName = refTableName.split("\\.")[1]; } AddForeignKeyConstraintStatement addForeignKeyConstraintStatement = new AddForeignKeyConstraintStatement( fkConstraint.getForeignKeyName(), statement.getCatalogName(), statement.getSchemaName(), statement.getTableName(), ColumnConfig.arrayFromNames(statement.getColumnName()), null, refSchemaName, refTableName, ColumnConfig.arrayFromNames(refColName)); returnSql.addAll( Arrays.asList( SqlGeneratorFactory.getInstance() .generateSql(addForeignKeyConstraintStatement, database))); } } }
@Test public void parseAndGenerate() throws Exception { Database database = liquiBase.getDatabase(); ResourceAccessor resourceAccessor = new ClassLoaderResourceAccessor(); ChangeLogParameters changeLogParameters = new ChangeLogParameters(); DatabaseChangeLog changeLog = ChangeLogParserFactory.getInstance() .getParser(changeLogFile, resourceAccessor) .parse(changeLogFile, changeLogParameters, resourceAccessor); database.checkDatabaseChangeLogTable(false, changeLog, null); changeLog.validate(database); List<ChangeSet> changeSets = changeLog.getChangeSets(); List<String> expectedQuery = new ArrayList<String>(); expectedQuery.add( "MERGE INTO LIQUIBASE.myTable2 m " + "USING LIQUIBASE.myTable d " + "ON (m.pid=d.pid) " + "WHEN MATCHED THEN UPDATE SET m.sales=m.sales+d.sales,m.status=d.status " + "DELETE WHERE (m.status='OBS') " + "WHEN NOT MATCHED THEN INSERT VALUES(d.pid,d.sales,'OLD')"); int i = 0; for (ChangeSet changeSet : changeSets) { for (Change change : changeSet.getChanges()) { Sql[] sql = SqlGeneratorFactory.getInstance() .generateSql(change.generateStatements(database)[0], database); if (i == 3) { assertEquals(expectedQuery.get(0), sql[0].toSql()); } } i++; } }
private void outputStatement(SqlStatement sql, List<SqlVisitor> sqlVisitors) throws DatabaseException { try { if (SqlGeneratorFactory.getInstance().generateStatementsVolatile(sql, database)) { throw new DatabaseException( sql.getClass().getSimpleName() + " requires access to up to date database metadata which is not available in SQL output mode"); } for (String statement : applyVisitors(sql, sqlVisitors)) { if (statement == null) { continue; } output.write(statement); if (database instanceof MSSQLDatabase || database instanceof SybaseDatabase || database instanceof SybaseASADatabase) { output.write(StreamUtil.getLineSeparator()); output.write("GO"); // } else if (database instanceof OracleDatabase) { // output.write(StreamUtil.getLineSeparator()); // output.write("/"); } else { String endDelimiter = ";"; if (sql instanceof RawSqlStatement) { endDelimiter = ((RawSqlStatement) sql).getEndDelimiter(); } if (!statement.endsWith(endDelimiter)) { output.write(endDelimiter); } } output.write(StreamUtil.getLineSeparator()); output.write(StreamUtil.getLineSeparator()); } } catch (IOException e) { throw new DatabaseException(e); } }
@Override public Sql[] generateSql( MarkChangeSetRanStatement statement, Database database, SqlGeneratorChain sqlGeneratorChain) { String dateValue = database.getCurrentDateTimeFunction(); ChangeSet changeSet = statement.getChangeSet(); SqlStatement runStatement; try { if (statement.getExecType().equals(ChangeSet.ExecType.FAILED) || statement.getExecType().equals(ChangeSet.ExecType.SKIPPED)) { return new Sql[0]; // don't mark } else if (statement.getExecType().ranBefore) { runStatement = new UpdateStatement( database.getLiquibaseCatalogName(), database.getLiquibaseSchemaName(), database.getDatabaseChangeLogTableName()) .addNewColumnValue("DATEEXECUTED", new DatabaseFunction(dateValue)) .addNewColumnValue("MD5SUM", changeSet.generateCheckSum().toString()) .addNewColumnValue("EXECTYPE", statement.getExecType().value) .setWhereClause("ID=? AND AUTHOR=? AND FILENAME=?") .addWhereParameters( changeSet.getId(), changeSet.getAuthor(), changeSet.getFilePath()); } else { runStatement = new InsertStatement( database.getLiquibaseCatalogName(), database.getLiquibaseSchemaName(), database.getDatabaseChangeLogTableName()) .addColumnValue("ID", changeSet.getId()) .addColumnValue("AUTHOR", changeSet.getAuthor()) .addColumnValue("FILENAME", changeSet.getFilePath()) .addColumnValue("DATEEXECUTED", new DatabaseFunction(dateValue)) .addColumnValue( "ORDEREXECUTED", ChangeLogHistoryServiceFactory.getInstance() .getChangeLogService(database) .getNextSequenceValue()) .addColumnValue("MD5SUM", changeSet.generateCheckSum().toString()) .addColumnValue("DESCRIPTION", limitSize(changeSet.getDescription())) .addColumnValue( "COMMENTS", limitSize( database.escapeStringForDatabase( StringUtils.trimToEmpty(changeSet.getComments())))) .addColumnValue("EXECTYPE", statement.getExecType().value) .addColumnValue( "LIQUIBASE", LiquibaseUtil.getBuildVersion().replaceAll("SNAPSHOT", "SNP")); String tag = null; List<Change> changes = changeSet.getChanges(); if (changes != null && changes.size() == 1) { Change change = changes.get(0); if (change instanceof TagDatabaseChange) { TagDatabaseChange tagChange = (TagDatabaseChange) change; tag = tagChange.getTag(); } } if (tag != null) { ((InsertStatement) runStatement).addColumnValue("TAG", tag); } } } catch (LiquibaseException e) { throw new UnexpectedLiquibaseException(e); } return SqlGeneratorFactory.getInstance().generateSql(runStatement, database); }
@Test public void minimumRequiredIsValidSql() throws Exception { ChangeFactory changeFactory = ChangeFactory.getInstance(); for (String changeName : changeFactory.getDefinedChanges()) { if (changeName.equals("addDefaultValue")) { continue; // need to better handle strange "one of defaultValue* is required" logic } if (changeName.equals("changeWithNestedTags") || changeName.equals("sampleChange")) { continue; // not a real change } for (Database database : DatabaseFactory.getInstance().getImplementedDatabases()) { if (database.getShortName() == null) { continue; } TestState state = new TestState( name.getMethodName(), changeName, database.getShortName(), TestState.Type.SQL); state.addComment("Database: " + database.getShortName()); Change change = changeFactory.create(changeName); if (!change.supports(database)) { continue; } if (change.generateStatementsVolatile(database)) { continue; } ChangeMetaData changeMetaData = ChangeFactory.getInstance().getChangeMetaData(change); change.setResourceAccessor(new JUnitResourceAccessor()); for (String paramName : new TreeSet<String>(changeMetaData.getRequiredParameters(database).keySet())) { ChangeParameterMetaData param = changeMetaData.getParameters().get(paramName); Object paramValue = param.getExampleValue(); String serializedValue; serializedValue = formatParameter(paramValue); state.addComment("Change Parameter: " + param.getParameterName() + "=" + serializedValue); param.setValue(change, paramValue); } ValidationErrors errors = change.validate(database); assertFalse( "Validation errors for " + changeMetaData.getName() + " on " + database.getShortName() + ": " + errors.toString(), errors.hasErrors()); SqlStatement[] sqlStatements = change.generateStatements(database); for (SqlStatement statement : sqlStatements) { Sql[] sql = SqlGeneratorFactory.getInstance().generateSql(statement, database); if (sql == null) { System.out.println("Null sql for " + statement + " on " + database.getShortName()); } else { for (Sql line : sql) { String sqlLine = line.toSql(); assertFalse( "Change " + changeMetaData.getName() + " contains 'null' for " + database.getShortName() + ": " + sqlLine, sqlLine.contains(" null ")); state.addValue(sqlLine + ";"); } } } state.test(); } } }