Search in sources :

Example 16 with Database

use of org.jumpmind.db.model.Database in project symmetric-ds by JumpMind.

the class AbstractSymmetricDialect method createOrAlterTablesIfNecessary.

/*
     * @return true if SQL was executed.
     */
public boolean createOrAlterTablesIfNecessary(String... tableNames) {
    try {
        log.info("Checking if SymmetricDS tables need created or altered");
        Database modelFromXml = readSymmetricSchemaFromXml();
        Database modelFromDatabase = readSymmetricSchemaFromDatabase();
        if (tableNames != null && tableNames.length > 0) {
            tableNames = platform.alterCaseToMatchDatabaseDefaultCase(tableNames);
            modelFromXml.removeAllTablesExcept(tableNames);
            modelFromDatabase.removeAllTablesExcept(tableNames);
        }
        IDdlBuilder builder = platform.getDdlBuilder();
        List<IAlterDatabaseInterceptor> alterDatabaseInterceptors = extensionService.getExtensionPointList(IAlterDatabaseInterceptor.class);
        IAlterDatabaseInterceptor[] interceptors = alterDatabaseInterceptors.toArray(new IAlterDatabaseInterceptor[alterDatabaseInterceptors.size()]);
        if (builder.isAlterDatabase(modelFromDatabase, modelFromXml, interceptors)) {
            String delimiter = platform.getDatabaseInfo().getSqlCommandDelimiter();
            ISqlResultsListener resultsListener = new LogSqlResultsListener(log);
            List<IDatabaseUpgradeListener> databaseUpgradeListeners = extensionService.getExtensionPointList(IDatabaseUpgradeListener.class);
            for (IDatabaseUpgradeListener listener : databaseUpgradeListeners) {
                String sql = listener.beforeUpgrade(this, this.parameterService.getTablePrefix(), modelFromDatabase, modelFromXml);
                SqlScript script = new SqlScript(sql, getPlatform().getSqlTemplate(), true, false, false, delimiter, null);
                script.setListener(resultsListener);
                script.execute(platform.getDatabaseInfo().isRequiresAutoCommitForDdl());
            }
            String alterSql = builder.alterDatabase(modelFromDatabase, modelFromXml, interceptors);
            if (isNotBlank(alterSql)) {
                log.info("There are SymmetricDS tables that needed altered");
                log.debug("Alter SQL generated: {}", alterSql);
                SqlScript script = new SqlScript(alterSql, getPlatform().getSqlTemplate(), true, false, false, delimiter, null);
                script.setListener(resultsListener);
                script.execute(platform.getDatabaseInfo().isRequiresAutoCommitForDdl());
                for (IDatabaseUpgradeListener listener : databaseUpgradeListeners) {
                    String sql = listener.afterUpgrade(this, this.parameterService.getTablePrefix(), modelFromXml);
                    script = new SqlScript(sql, getPlatform().getSqlTemplate(), true, false, false, delimiter, null);
                    script.setListener(resultsListener);
                    script.execute(platform.getDatabaseInfo().isRequiresAutoCommitForDdl());
                }
                log.info("Done with auto update of SymmetricDS tables");
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    } catch (RuntimeException ex) {
        throw ex;
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}
Also used : IDatabaseUpgradeListener(org.jumpmind.symmetric.ext.IDatabaseUpgradeListener) IAlterDatabaseInterceptor(org.jumpmind.db.platform.IAlterDatabaseInterceptor) SqlException(org.jumpmind.db.sql.SqlException) IoException(org.jumpmind.exception.IoException) IOException(java.io.IOException) ISqlResultsListener(org.jumpmind.db.sql.ISqlResultsListener) IDdlBuilder(org.jumpmind.db.platform.IDdlBuilder) Database(org.jumpmind.db.model.Database) SqlScript(org.jumpmind.db.sql.SqlScript) LogSqlResultsListener(org.jumpmind.db.sql.LogSqlResultsListener)

Example 17 with Database

use of org.jumpmind.db.model.Database in project symmetric-ds by JumpMind.

the class AbstractSymmetricEngine method buildTablesFromDdlUtilXmlIfProvided.

protected boolean buildTablesFromDdlUtilXmlIfProvided() {
    boolean loaded = false;
    String xml = parameterService.getString(ParameterConstants.AUTO_CONFIGURE_REG_SVR_DDLUTIL_XML);
    if (!StringUtils.isBlank(xml)) {
        File file = new File(xml);
        URL fileUrl = null;
        if (file.isFile()) {
            try {
                fileUrl = file.toURI().toURL();
            } catch (MalformedURLException e) {
                throw new RuntimeException(e);
            }
        } else {
            fileUrl = getClass().getResource(xml);
        }
        if (fileUrl != null) {
            try {
                log.info("Building database schema from: {}", xml);
                Database database = DatabaseXmlUtil.read(new InputStreamReader(fileUrl.openStream()));
                IDatabasePlatform platform = symmetricDialect.getPlatform();
                platform.createDatabase(database, true, true);
                loaded = true;
            } catch (Exception e) {
                log.error("", e);
            }
        }
    }
    return loaded;
}
Also used : MalformedURLException(java.net.MalformedURLException) IDatabasePlatform(org.jumpmind.db.platform.IDatabasePlatform) InputStreamReader(java.io.InputStreamReader) Database(org.jumpmind.db.model.Database) File(java.io.File) URL(java.net.URL) SqlException(org.jumpmind.db.sql.SqlException) MalformedURLException(java.net.MalformedURLException)

Example 18 with Database

use of org.jumpmind.db.model.Database in project symmetric-ds by JumpMind.

the class DefaultDatabaseWriter method create.

@Override
protected boolean create(CsvData data) {
    String xml = null;
    try {
        transaction.commit();
        statistics.get(batch).startTimer(DataWriterStatisticConstants.DATABASEMILLIS);
        xml = data.getParsedData(CsvData.ROW_DATA)[0];
        log.info("About to create table using the following definition: {}", xml);
        StringReader reader = new StringReader(xml);
        Database db = DatabaseXmlUtil.read(reader, false);
        if (writerSettings.isCreateTableAlterCaseToMatchDatabaseDefault()) {
            platform.alterCaseToMatchDatabaseDefaultCase(db);
        }
        platform.makePlatformSpecific(db);
        if (writerSettings.isAlterTable()) {
            platform.alterDatabase(db, !writerSettings.isCreateTableFailOnError());
        } else {
            platform.createDatabase(db, writerSettings.isCreateTableDropFirst(), !writerSettings.isCreateTableFailOnError());
        }
        platform.resetCachedTableModel();
        statistics.get(batch).increment(DataWriterStatisticConstants.CREATECOUNT);
        return true;
    } catch (RuntimeException ex) {
        log.error("Failed to alter table using the following xml: {}", xml);
        throw ex;
    } finally {
        statistics.get(batch).stopTimer(DataWriterStatisticConstants.DATABASEMILLIS);
    }
}
Also used : StringReader(java.io.StringReader) Database(org.jumpmind.db.model.Database)

Example 19 with Database

use of org.jumpmind.db.model.Database 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 20 with Database

use of org.jumpmind.db.model.Database 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)

Aggregations

Database (org.jumpmind.db.model.Database)37 Table (org.jumpmind.db.model.Table)21 IDatabasePlatform (org.jumpmind.db.platform.IDatabasePlatform)9 Test (org.junit.Test)7 IOException (java.io.IOException)6 IoException (org.jumpmind.exception.IoException)6 AbstractServiceTest (org.jumpmind.symmetric.service.impl.AbstractServiceTest)5 IDdlBuilder (org.jumpmind.db.platform.IDdlBuilder)4 SqlException (org.jumpmind.db.sql.SqlException)4 SqlScript (org.jumpmind.db.sql.SqlScript)4 DbExport (org.jumpmind.symmetric.io.data.DbExport)4 DbImport (org.jumpmind.symmetric.io.data.DbImport)4 File (java.io.File)3 ArrayList (java.util.ArrayList)3 InputStreamReader (java.io.InputStreamReader)2 LinkedHashMap (java.util.LinkedHashMap)2 AddTableChange (org.jumpmind.db.alter.AddTableChange)2 RemoveTableChange (org.jumpmind.db.alter.RemoveTableChange)2 TableChange (org.jumpmind.db.alter.TableChange)2 Column (org.jumpmind.db.model.Column)2