Search in sources :

Example 1 with TableChange

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);
        }
    }
}
Also used : Table(org.jumpmind.db.model.Table) ForeignKey(org.jumpmind.db.model.ForeignKey) LinkedHashMap(java.util.LinkedHashMap) Database(org.jumpmind.db.model.Database) List(java.util.List) ArrayList(java.util.ArrayList) TypeMap(org.jumpmind.db.model.TypeMap) Map(java.util.Map) LinkedHashMap(java.util.LinkedHashMap) RemoveTableChange(org.jumpmind.db.alter.RemoveTableChange) TableChange(org.jumpmind.db.alter.TableChange) AddTableChange(org.jumpmind.db.alter.AddTableChange)

Example 2 with TableChange

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);
    }
}
Also used : Table(org.jumpmind.db.model.Table) Database(org.jumpmind.db.model.Database) AddColumnChange(org.jumpmind.db.alter.AddColumnChange) RemoveTableChange(org.jumpmind.db.alter.RemoveTableChange) TableChange(org.jumpmind.db.alter.TableChange) AddTableChange(org.jumpmind.db.alter.AddTableChange)

Example 3 with TableChange

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();
        }
    }
}
Also used : CopyColumnValueChange(org.jumpmind.db.alter.CopyColumnValueChange) RemovePrimaryKeyChange(org.jumpmind.db.alter.RemovePrimaryKeyChange) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) ColumnDefaultValueChange(org.jumpmind.db.alter.ColumnDefaultValueChange) ColumnChange(org.jumpmind.db.alter.ColumnChange) AddColumnChange(org.jumpmind.db.alter.AddColumnChange) RemoveColumnChange(org.jumpmind.db.alter.RemoveColumnChange) Column(org.jumpmind.db.model.Column) PrimaryKeyChange(org.jumpmind.db.alter.PrimaryKeyChange) AddPrimaryKeyChange(org.jumpmind.db.alter.AddPrimaryKeyChange) RemovePrimaryKeyChange(org.jumpmind.db.alter.RemovePrimaryKeyChange) RemoveColumnChange(org.jumpmind.db.alter.RemoveColumnChange) Iterator(java.util.Iterator) ColumnAutoIncrementChange(org.jumpmind.db.alter.ColumnAutoIncrementChange) AddPrimaryKeyChange(org.jumpmind.db.alter.AddPrimaryKeyChange) AddColumnChange(org.jumpmind.db.alter.AddColumnChange) HashMap(java.util.HashMap) Map(java.util.Map) TableChange(org.jumpmind.db.alter.TableChange)

Example 4 with TableChange

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);
}
Also used : AddColumnChange(org.jumpmind.db.alter.AddColumnChange) TableChange(org.jumpmind.db.alter.TableChange)

Example 5 with TableChange

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);
}
Also used : CopyColumnValueChange(org.jumpmind.db.alter.CopyColumnValueChange) RemoveColumnChange(org.jumpmind.db.alter.RemoveColumnChange) ColumnRequiredChange(org.jumpmind.db.alter.ColumnRequiredChange) AddPrimaryKeyChange(org.jumpmind.db.alter.AddPrimaryKeyChange) AddColumnChange(org.jumpmind.db.alter.AddColumnChange) TableChange(org.jumpmind.db.alter.TableChange)

Aggregations

TableChange (org.jumpmind.db.alter.TableChange)18 AddColumnChange (org.jumpmind.db.alter.AddColumnChange)15 RemoveColumnChange (org.jumpmind.db.alter.RemoveColumnChange)13 CopyColumnValueChange (org.jumpmind.db.alter.CopyColumnValueChange)12 AddPrimaryKeyChange (org.jumpmind.db.alter.AddPrimaryKeyChange)10 ArrayList (java.util.ArrayList)8 ColumnAutoIncrementChange (org.jumpmind.db.alter.ColumnAutoIncrementChange)7 PrimaryKeyChange (org.jumpmind.db.alter.PrimaryKeyChange)7 RemovePrimaryKeyChange (org.jumpmind.db.alter.RemovePrimaryKeyChange)7 ColumnDefaultValueChange (org.jumpmind.db.alter.ColumnDefaultValueChange)6 ColumnSizeChange (org.jumpmind.db.alter.ColumnSizeChange)6 ColumnChange (org.jumpmind.db.alter.ColumnChange)5 ColumnDataTypeChange (org.jumpmind.db.alter.ColumnDataTypeChange)5 Column (org.jumpmind.db.model.Column)5 ColumnRequiredChange (org.jumpmind.db.alter.ColumnRequiredChange)4 Map (java.util.Map)3 AddTableChange (org.jumpmind.db.alter.AddTableChange)3 RemoveTableChange (org.jumpmind.db.alter.RemoveTableChange)3 Table (org.jumpmind.db.model.Table)3 HashMap (java.util.HashMap)2