use of org.jumpmind.db.alter.TableChange in project symmetric-ds by JumpMind.
the class AbstractDdlBuilder method processTableStructureChanges.
/**
* Processes the changes to the structure of tables.
*
* @param currentModel
* The current database schema
* @param desiredModel
* The desired database schema
* @param changes
* The change objects
*/
protected void processTableStructureChanges(Database currentModel, Database desiredModel, Collection<TableChange> changes, StringBuilder ddl) {
filterChanges(changes);
LinkedHashMap<String, List<TableChange>> changesPerTable = new LinkedHashMap<String, List<TableChange>>();
LinkedHashMap<String, List<ForeignKey>> unchangedFKs = new LinkedHashMap<String, List<ForeignKey>>();
boolean caseSensitive = delimitedIdentifierModeOn;
// we use the names rather than the table objects
for (Iterator<TableChange> changeIt = changes.iterator(); changeIt.hasNext(); ) {
TableChange change = changeIt.next();
String name = change.getChangedTable().getName();
if (!caseSensitive) {
name = name.toUpperCase();
}
List<TableChange> changesForTable = (List<TableChange>) changesPerTable.get(name);
if (changesForTable == null) {
changesForTable = new ArrayList<TableChange>();
changesPerTable.put(name, changesForTable);
unchangedFKs.put(name, getUnchangedForeignKeys(currentModel, desiredModel, name));
}
changesForTable.add(change);
}
// we also need to drop the foreign keys of the unchanged tables
// referencing the changed tables
addRelevantFKsFromUnchangedTables(currentModel, desiredModel, changesPerTable.keySet(), unchangedFKs);
// we're dropping the unchanged foreign keys
for (Iterator<Map.Entry<String, List<ForeignKey>>> tableFKIt = unchangedFKs.entrySet().iterator(); tableFKIt.hasNext(); ) {
Map.Entry<String, List<ForeignKey>> entry = tableFKIt.next();
Table targetTable = findTable(desiredModel, (String) entry.getKey());
for (Iterator<ForeignKey> fkIt = entry.getValue().iterator(); fkIt.hasNext(); ) {
writeExternalForeignKeyDropStmt(targetTable, fkIt.next(), ddl);
}
}
// We're using a copy of the current model so that the table structure
// changes can modify it
Database copyOfCurrentModel = copy(currentModel);
for (Iterator<Map.Entry<String, List<TableChange>>> tableChangeIt = changesPerTable.entrySet().iterator(); tableChangeIt.hasNext(); ) {
Map.Entry<String, List<TableChange>> entry = tableChangeIt.next();
processTableStructureChanges(copyOfCurrentModel, desiredModel, entry.getKey(), entry.getValue(), ddl);
}
// and finally we're re-creating the unchanged foreign keys
for (Iterator<Map.Entry<String, List<ForeignKey>>> tableFKIt = unchangedFKs.entrySet().iterator(); tableFKIt.hasNext(); ) {
Map.Entry<String, List<ForeignKey>> entry = tableFKIt.next();
Table targetTable = findTable(desiredModel, (String) entry.getKey());
for (Iterator<ForeignKey> fkIt = entry.getValue().iterator(); fkIt.hasNext(); ) {
writeExternalForeignKeyCreateStmt(desiredModel, targetTable, fkIt.next(), ddl);
}
}
}
use of org.jumpmind.db.alter.TableChange in project symmetric-ds by JumpMind.
the class AbstractDdlBuilder method processTableStructureChanges.
/**
* Processes the changes to the structure of a single table.
* Database-specific implementations might redefine this method, but it is
* usually sufficient to redefine the
* {@link #processTableStructureChanges(Database, Database, Table, Table, Map, List)}
* method instead.
*/
protected void processTableStructureChanges(Database currentModel, Database desiredModel, String tableName, List<TableChange> changes, StringBuilder ddl) {
StringBuilder tableDdl = new StringBuilder();
Database originalModel = copy(currentModel);
Table sourceTable = findTable(originalModel, tableName);
Table targetTable = findTable(desiredModel, tableName);
// we're enforcing a full rebuild in case of the addition of a required
// column without a default value that is not autoincrement
boolean requiresFullRebuild = false;
for (Iterator<TableChange> changeIt = changes.iterator(); !requiresFullRebuild && changeIt.hasNext(); ) {
TableChange change = changeIt.next();
if (change instanceof AddColumnChange) {
AddColumnChange addColumnChange = (AddColumnChange) change;
if (addColumnChange.getNewColumn().isRequired() && (addColumnChange.getNewColumn().getDefaultValue() == null) && !addColumnChange.getNewColumn().isAutoIncrement()) {
requiresFullRebuild = true;
}
}
}
if (!requiresFullRebuild) {
processTableStructureChanges(currentModel, desiredModel, sourceTable, targetTable, changes, tableDdl);
}
if (!changes.isEmpty()) {
// we can only copy the data if no required columns without default
// value and non-autoincrement have been added
boolean canMigrateData = true;
Table tempTable = getTemporaryTableFor(sourceTable);
for (Iterator<TableChange> it = changes.iterator(); canMigrateData && it.hasNext(); ) {
TableChange change = it.next();
if (change instanceof AddColumnChange) {
AddColumnChange addColumnChange = (AddColumnChange) change;
if (addColumnChange.getNewColumn().isRequired() && !addColumnChange.getNewColumn().isAutoIncrement() && (addColumnChange.getNewColumn().getDefaultValue() == null)) {
log.warn("Data cannot be retained in table " + change.getChangedTable().getName() + " because of the addition of the required column " + addColumnChange.getNewColumn().getName() + " . The data is backed up in " + tempTable + ", consider manually migrating the data back or dropping this temp table.");
canMigrateData = false;
}
}
}
Table realTargetTable = getRealTargetTableFor(desiredModel, sourceTable, targetTable);
dropTemporaryTable(tempTable, ddl);
createTemporaryTable(tempTable, ddl);
writeCopyDataStatement(sourceTable, tempTable, ddl);
/*
* Note that we don't drop the indices here because the DROP
* TABLE will take care of that Likewise, foreign keys have
* already been dropped as necessary
*/
dropTable(sourceTable, ddl, false, true);
createTable(realTargetTable, ddl, false, true);
if (canMigrateData) {
writeCopyDataStatement(tempTable, targetTable, ddl);
dropTemporaryTable(tempTable, ddl);
writeFixLastIdentityValues(targetTable, ddl);
}
} else {
ddl.append(tableDdl);
}
}
use of org.jumpmind.db.alter.TableChange in project symmetric-ds by JumpMind.
the class AseDdlBuilder method processTableStructureChanges.
@Override
protected void processTableStructureChanges(Database currentModel, Database desiredModel, Table sourceTable, Table targetTable, List<TableChange> changes, StringBuilder ddl) {
// First we drop primary keys as necessary
for (Iterator changeIt = changes.iterator(); changeIt.hasNext(); ) {
TableChange change = (TableChange) changeIt.next();
if (change instanceof RemovePrimaryKeyChange) {
processChange(currentModel, desiredModel, (RemovePrimaryKeyChange) change, ddl);
changeIt.remove();
} else if (change instanceof PrimaryKeyChange) {
PrimaryKeyChange pkChange = (PrimaryKeyChange) change;
RemovePrimaryKeyChange removePkChange = new RemovePrimaryKeyChange(pkChange.getChangedTable(), pkChange.getOldPrimaryKeyColumns());
processChange(currentModel, desiredModel, removePkChange, ddl);
}
}
HashMap columnChanges = new HashMap();
// Next we add/remove columns
for (Iterator changeIt = changes.iterator(); changeIt.hasNext(); ) {
TableChange change = (TableChange) changeIt.next();
if (change instanceof AddColumnChange) {
AddColumnChange addColumnChange = (AddColumnChange) change;
// Sybase can only add not insert columns
if (addColumnChange.isAtEnd()) {
processChange(currentModel, desiredModel, addColumnChange, ddl);
changeIt.remove();
}
} else if (change instanceof CopyColumnValueChange) {
CopyColumnValueChange copyColumnChange = (CopyColumnValueChange) change;
processChange(currentModel, desiredModel, copyColumnChange, ddl);
changeIt.remove();
} else if (change instanceof RemoveColumnChange) {
processChange(currentModel, desiredModel, (RemoveColumnChange) change, ddl);
changeIt.remove();
} else if (change instanceof ColumnAutoIncrementChange) {
// Sybase has no way of adding or removing an IDENTITY
// constraint
// Thus we have to rebuild the table anyway and can ignore all
// the other
// column changes
columnChanges = null;
} else if ((change instanceof ColumnChange) && (columnChanges != null)) {
// we gather all changed columns because we can use the ALTER
// TABLE ALTER COLUMN
// statement for them
ColumnChange columnChange = (ColumnChange) change;
ArrayList changesPerColumn = (ArrayList) columnChanges.get(columnChange.getChangedColumn());
if (changesPerColumn == null) {
changesPerColumn = new ArrayList();
columnChanges.put(columnChange.getChangedColumn(), changesPerColumn);
}
changesPerColumn.add(change);
}
}
if (columnChanges != null) {
for (Iterator changesPerColumnIt = columnChanges.entrySet().iterator(); changesPerColumnIt.hasNext(); ) {
Map.Entry entry = (Map.Entry) changesPerColumnIt.next();
Column sourceColumn = (Column) entry.getKey();
ArrayList changesPerColumn = (ArrayList) entry.getValue();
// different handler
if ((changesPerColumn.size() == 1) && (changesPerColumn.get(0) instanceof ColumnDefaultValueChange)) {
processChange(currentModel, desiredModel, (ColumnDefaultValueChange) changesPerColumn.get(0), ddl);
} else {
Column targetColumn = targetTable.findColumn(sourceColumn.getName(), delimitedIdentifierModeOn);
processColumnChange(sourceTable, targetTable, sourceColumn, targetColumn, ddl);
}
for (Iterator changeIt = changesPerColumn.iterator(); changeIt.hasNext(); ) {
((ColumnChange) changeIt.next()).apply(currentModel, delimitedIdentifierModeOn);
}
}
}
// Finally we add primary keys
for (Iterator changeIt = changes.iterator(); changeIt.hasNext(); ) {
TableChange change = (TableChange) changeIt.next();
if (change instanceof AddPrimaryKeyChange) {
processChange(currentModel, desiredModel, (AddPrimaryKeyChange) change, ddl);
changeIt.remove();
} else if (change instanceof PrimaryKeyChange) {
PrimaryKeyChange pkChange = (PrimaryKeyChange) change;
AddPrimaryKeyChange addPkChange = new AddPrimaryKeyChange(pkChange.getChangedTable(), pkChange.getNewPrimaryKeyColumns());
processChange(currentModel, desiredModel, addPkChange, ddl);
changeIt.remove();
}
}
}
use of org.jumpmind.db.alter.TableChange in project symmetric-ds by JumpMind.
the class DerbyDdlBuilder method processTableStructureChanges.
@Override
protected void processTableStructureChanges(Database currentModel, Database desiredModel, Table sourceTable, Table targetTable, List<TableChange> changes, StringBuilder ddl) {
// (no pk or fk columns, only for VARCHAR columns), so we don't use it
for (Iterator<TableChange> changeIt = changes.iterator(); changeIt.hasNext(); ) {
TableChange change = changeIt.next();
if (change instanceof AddColumnChange) {
AddColumnChange addColumnChange = (AddColumnChange) change;
// cannot be identity columns
if (addColumnChange.isAtEnd() && !addColumnChange.getNewColumn().isAutoIncrement()) {
processChange(currentModel, desiredModel, addColumnChange, ddl);
changeIt.remove();
}
}
}
super.processTableStructureChanges(currentModel, desiredModel, sourceTable, targetTable, changes, ddl);
}
use of org.jumpmind.db.alter.TableChange in project symmetric-ds by JumpMind.
the class FirebirdDdlBuilder method processTableStructureChanges.
@Override
protected void processTableStructureChanges(Database currentModel, Database desiredModel, Table sourceTable, Table targetTable, List<TableChange> changes, StringBuilder ddl) {
// TODO: Dropping of primary keys is currently not supported because we
// cannot determine the pk constraint names and drop them in one go
// (We could used a stored procedure if Firebird would allow them to use
// DDL) This will be easier once named primary keys are supported
boolean pkColumnAdded = false;
for (Iterator<TableChange> changeIt = changes.iterator(); changeIt.hasNext(); ) {
TableChange change = changeIt.next();
if (change instanceof AddColumnChange) {
AddColumnChange addColumnChange = (AddColumnChange) change;
// add a new one afterwards which is not supported yet
if (addColumnChange.getNewColumn().isPrimaryKey()) {
pkColumnAdded = true;
} else {
processChange(currentModel, desiredModel, addColumnChange, ddl);
changeIt.remove();
}
} else if (change instanceof RemoveColumnChange) {
RemoveColumnChange removeColumnChange = (RemoveColumnChange) change;
// add a new one afterwards which is not supported yet
if (!removeColumnChange.getColumn().isPrimaryKey()) {
processChange(currentModel, desiredModel, removeColumnChange, ddl);
changeIt.remove();
}
} else if (change instanceof CopyColumnValueChange) {
CopyColumnValueChange copyColumnChange = (CopyColumnValueChange) change;
processChange(currentModel, desiredModel, copyColumnChange, ddl);
changeIt.remove();
} else if (change instanceof ColumnRequiredChange) {
processChange(currentModel, desiredModel, (ColumnRequiredChange) change, ddl);
changeIt.remove();
}
}
for (Iterator<TableChange> changeIt = changes.iterator(); changeIt.hasNext(); ) {
TableChange change = changeIt.next();
// i.e. none was added during this alteration
if ((change instanceof AddPrimaryKeyChange) && !pkColumnAdded) {
processChange(currentModel, desiredModel, (AddPrimaryKeyChange) change, ddl);
changeIt.remove();
}
}
super.processTableStructureChanges(currentModel, desiredModel, sourceTable, targetTable, changes, ddl);
}
Aggregations