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);
}
}
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;
}
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);
}
}
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);
}
}
}
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);
}
}
Aggregations