Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEike Stepper2018-10-20 04:57:47 -0400
committerEike Stepper2018-10-20 04:57:47 -0400
commitddea24c1a6bb38a36d9d096d6994a6b0b16ce085 (patch)
tree2d2971f324e1ccf93cab2273b026c57d6f30e436
parent1e272a47e8da690ce4f56ce2126c6f7f0f3fb9cc (diff)
downloadcdo-ddea24c1a6bb38a36d9d096d6994a6b0b16ce085.tar.gz
cdo-ddea24c1a6bb38a36d9d096d6994a6b0b16ce085.tar.xz
cdo-ddea24c1a6bb38a36d9d096d6994a6b0b16ce085.zip
[256856] Support model evolution
https://bugs.eclipse.org/bugs/show_bug.cgi?id=256856
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractFeatureMapping.java89
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMapping.java64
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMapping2.java2
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IFeatureMapping2.java33
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreMigrator.java333
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractBasicListTableMapping.java32
-rw-r--r--plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java34
-rw-r--r--plugins/org.eclipse.emf.cdo.server.evolution/src/org/eclipse/emf/cdo/server/evolution/Renamer.java51
-rw-r--r--plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/EvolutionTest.java80
-rw-r--r--plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBType.java8
-rw-r--r--plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/IDBField.java5
-rw-r--r--plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBField.java25
-rw-r--r--plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DelegatingDBField.java5
13 files changed, 596 insertions, 165 deletions
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractFeatureMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractFeatureMapping.java
new file mode 100644
index 0000000000..8aff30db13
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractFeatureMapping.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2004-2018 Eike Stepper (Loehne, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.server.db.mapping;
+
+import org.eclipse.net4j.db.ddl.IDBField;
+
+import org.eclipse.emf.ecore.EStructuralFeature;
+
+/**
+ * @author Eike Stepper
+ * @since 4.7
+ */
+public abstract class AbstractFeatureMapping implements IFeatureMapping2
+{
+ private IMappingStrategy mappingStrategy;
+
+ private EStructuralFeature feature;
+
+ private IDBField unsettableField;
+
+ public AbstractFeatureMapping()
+ {
+ }
+
+ public final IMappingStrategy getMappingStrategy()
+ {
+ return mappingStrategy;
+ }
+
+ public final void setMappingStrategy(IMappingStrategy mappingStrategy)
+ {
+ this.mappingStrategy = mappingStrategy;
+ }
+
+ public final EStructuralFeature getFeature()
+ {
+ return feature;
+ }
+
+ public final void setFeature(EStructuralFeature feature)
+ {
+ this.feature = feature;
+ }
+
+ public final IDBField getUnsettableField()
+ {
+ return unsettableField;
+ }
+
+ public final void setUnsettableField(IDBField unsettableField)
+ {
+ this.unsettableField = unsettableField;
+ }
+
+ public static IDBField getField(IClassMapping2 classMapping, IFeatureMapping featureMapping)
+ {
+ if (featureMapping instanceof IFeatureMapping2)
+ {
+ return ((IFeatureMapping2)featureMapping).getField();
+ }
+
+ if (featureMapping instanceof ITypeMapping)
+ {
+ return ((ITypeMapping)featureMapping).getField();
+ }
+
+ EStructuralFeature feature = featureMapping.getFeature();
+ return classMapping.getListSizeFields().get(feature);
+ }
+
+ public static IDBField getUnsettableField(IClassMapping2 classMapping, IFeatureMapping featureMapping)
+ {
+ if (featureMapping instanceof IFeatureMapping2)
+ {
+ return ((IFeatureMapping2)featureMapping).getUnsettableField();
+ }
+
+ EStructuralFeature feature = featureMapping.getFeature();
+ return classMapping.getUnsettableFields().get(feature);
+ }
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMapping.java
index 3e08245b49..58b5e38cee 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMapping.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/AbstractTypeMapping.java
@@ -39,7 +39,7 @@ import java.sql.SQLException;
import java.text.MessageFormat;
/**
- * This is a default implementation for the {@link ITypeMapping} interface which provides default behavor for all common
+ * This is a default implementation for the {@link ITypeMapping} interface which provides default behavior for all common
* types. Implementors should provide a constructor which the factory (see below) can use and implement
* {@link #getResultSetValue(ResultSet)}. If needed, {@link #doSetValue(PreparedStatement, int, Object)} can also be
* overridden as a counterpart to {@link #getResultSetValue(ResultSet)}. Finally, an implementor should also implement a
@@ -51,14 +51,10 @@ import java.text.MessageFormat;
* @author Stefan Winkler
* @since 4.0
*/
-public abstract class AbstractTypeMapping implements ITypeMapping
+public abstract class AbstractTypeMapping extends AbstractFeatureMapping implements ITypeMapping
{
private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, AbstractTypeMapping.class);
- private IMappingStrategy mappingStrategy;
-
- private EStructuralFeature feature;
-
private DBType dbType;
private IDBField field;
@@ -70,24 +66,9 @@ public abstract class AbstractTypeMapping implements ITypeMapping
{
}
- public final IMappingStrategy getMappingStrategy()
- {
- return mappingStrategy;
- }
-
- public final void setMappingStrategy(IMappingStrategy mappingStrategy)
- {
- this.mappingStrategy = mappingStrategy;
- }
-
- public final EStructuralFeature getFeature()
- {
- return feature;
- }
-
- public final void setFeature(EStructuralFeature feature)
+ public DBType getDBType()
{
- this.feature = feature;
+ return dbType;
}
public final void setDBType(DBType dbType)
@@ -95,11 +76,6 @@ public abstract class AbstractTypeMapping implements ITypeMapping
this.dbType = dbType;
}
- public DBType getDBType()
- {
- return dbType;
- }
-
public final void setValueFromRevision(PreparedStatement stmt, int index, InternalCDORevision revision) throws SQLException
{
setValue(stmt, index, getRevisionValue(revision));
@@ -116,13 +92,15 @@ public abstract class AbstractTypeMapping implements ITypeMapping
{
if (TRACER.isEnabled())
{
- TRACER.format("TypeMapping for {0}: converting Revision.NIL to DB-null", feature.getName()); //$NON-NLS-1$
+ TRACER.format("TypeMapping for {0}: converting Revision.NIL to DB-null", getFeature().getName()); //$NON-NLS-1$
}
stmt.setNull(index, getSqlType());
}
else if (value == null)
{
+ EStructuralFeature feature = getFeature();
+
if (feature.isMany() || getDefaultValue() == null)
{
if (TRACER.isEnabled())
@@ -151,7 +129,7 @@ public abstract class AbstractTypeMapping implements ITypeMapping
@Deprecated
public final void createDBField(IDBTable table)
{
- createDBField(table, mappingStrategy.getFieldName(feature));
+ createDBField(table, getMappingStrategy().getFieldName(getFeature()));
}
public final void createDBField(IDBTable table, String fieldName)
@@ -166,6 +144,14 @@ public abstract class AbstractTypeMapping implements ITypeMapping
return field;
}
+ /**
+ * @since 4.7
+ */
+ public final void setField(IDBField field)
+ {
+ this.field = field;
+ }
+
public final void setDBField(IDBTable table, String fieldName)
{
field = table.getFieldSafe(fieldName);
@@ -182,11 +168,11 @@ public abstract class AbstractTypeMapping implements ITypeMapping
Object value = getResultSetValue(resultSet);
if (resultSet.wasNull())
{
- if (feature.isMany())
+ if (getFeature().isMany())
{
if (TRACER.isEnabled())
{
- TRACER.format("TypeMapping for {0}: read db.null - setting Revision.null", feature.getName()); //$NON-NLS-1$
+ TRACER.format("TypeMapping for {0}: read db.null - setting Revision.null", getFeature().getName()); //$NON-NLS-1$
}
value = null;
@@ -198,7 +184,7 @@ public abstract class AbstractTypeMapping implements ITypeMapping
if (TRACER.isEnabled())
{
TRACER.format("TypeMapping for {0}: read db.null - setting Revision.null, because of default", //$NON-NLS-1$
- feature.getName());
+ getFeature().getName());
}
value = null;
@@ -207,7 +193,7 @@ public abstract class AbstractTypeMapping implements ITypeMapping
{
if (TRACER.isEnabled())
{
- TRACER.format("TypeMapping for {0}: read db.null - setting Revision.NIL", feature.getName()); //$NON-NLS-1$
+ TRACER.format("TypeMapping for {0}: read db.null - setting Revision.NIL", getFeature().getName()); //$NON-NLS-1$
}
value = CDORevisionData.NIL;
@@ -223,12 +209,12 @@ public abstract class AbstractTypeMapping implements ITypeMapping
{
Object mappedElement = field != null ? field : dbType;
return MessageFormat.format("{0}[{1}.{2} --> {3}]", getClass().getSimpleName(), //$NON-NLS-1$
- feature.getEContainingClass().getName(), feature.getName(), mappedElement);
+ getFeature().getEContainingClass().getName(), getFeature().getName(), mappedElement);
}
protected Object getDefaultValue()
{
- return feature.getDefaultValue();
+ return getFeature().getDefaultValue();
}
protected final Object getRevisionValue(InternalCDORevision revision)
@@ -256,7 +242,7 @@ public abstract class AbstractTypeMapping implements ITypeMapping
* Returns the SQL type of this TypeMapping. The default implementation considers the type map held by the
* {@link MetaDataManager meta-data manager}. Subclasses may override.
*
- * @return The sql type of this TypeMapping.
+ * @return The SQL type of this TypeMapping.
*/
protected int getSqlType()
{
@@ -265,6 +251,8 @@ public abstract class AbstractTypeMapping implements ITypeMapping
protected int getDBLength(DBType type)
{
+ EStructuralFeature feature = getFeature();
+
String value = DBAnnotation.COLUMN_LENGTH.getValue(feature);
if (value != null)
{
@@ -278,7 +266,7 @@ public abstract class AbstractTypeMapping implements ITypeMapping
}
}
- IDBAdapter adapter = mappingStrategy.getStore().getDBAdapter();
+ IDBAdapter adapter = getMappingStrategy().getStore().getDBAdapter();
return adapter.getFieldLength(type);
}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMapping2.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMapping2.java
index bd71a2613b..2faa064860 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMapping2.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMapping2.java
@@ -28,6 +28,8 @@ import java.util.Map;
*/
public interface IClassMapping2 extends IClassMapping
{
+ public IDBTable getTable();
+
public void setTable(IDBTable table);
public void initTable(IDBStoreAccessor accessor);
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IFeatureMapping2.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IFeatureMapping2.java
new file mode 100644
index 0000000000..49eeeb22c0
--- /dev/null
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IFeatureMapping2.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018 Eike Stepper (Loehne, Germany) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Eike Stepper - initial API and implementation
+ */
+package org.eclipse.emf.cdo.server.db.mapping;
+
+import org.eclipse.net4j.db.ddl.IDBField;
+
+/**
+ * An extension interface for {@link IFeatureMapping feature mappings}.
+ *
+ * @author Eike Stepper
+ * @since 4.7
+ */
+public interface IFeatureMapping2 extends IFeatureMapping
+{
+ /**
+ * @return The value field if this feature mapping is an {@link ITypeMapping} or the size field if this feature mapping is an {@link IListMapping}.
+ */
+ public IDBField getField();
+
+ public void setField(IDBField field);
+
+ public IDBField getUnsettableField();
+
+ public void setUnsettableField(IDBField unsettableField);
+}
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreMigrator.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreMigrator.java
index 48940cd907..fba568afb4 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreMigrator.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreMigrator.java
@@ -20,11 +20,13 @@ import org.eclipse.emf.cdo.internal.server.Repository;
import org.eclipse.emf.cdo.server.db.IDBStore;
import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
import org.eclipse.emf.cdo.server.db.IMetaDataManager;
+import org.eclipse.emf.cdo.server.db.mapping.AbstractFeatureMapping;
import org.eclipse.emf.cdo.server.db.mapping.IClassMapping;
import org.eclipse.emf.cdo.server.db.mapping.IClassMapping2;
import org.eclipse.emf.cdo.server.db.mapping.IFeatureMapping;
import org.eclipse.emf.cdo.server.db.mapping.IListMapping;
import org.eclipse.emf.cdo.server.db.mapping.IListMapping4;
+import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy.Props;
import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy3;
import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;
import org.eclipse.emf.cdo.server.evolution.Renamer;
@@ -44,7 +46,6 @@ import org.eclipse.net4j.db.ddl.IDBField;
import org.eclipse.net4j.db.ddl.IDBSchema;
import org.eclipse.net4j.db.ddl.IDBTable;
import org.eclipse.net4j.db.ddl.delta.IDBSchemaDelta;
-import org.eclipse.net4j.spi.db.ddl.InternalDBNamedElement;
import org.eclipse.net4j.spi.db.ddl.InternalDBSchema;
import org.eclipse.net4j.util.ObjectUtil;
import org.eclipse.net4j.util.collection.Pair;
@@ -85,7 +86,9 @@ public class DBStoreMigrator
private final IDBStore store;
- private final IDBAdapter dbAdapter;
+ private final IDBAdapter adapter;
+
+ private final IDBConnection connection;
private final IMappingStrategy3 mappingStrategy;
@@ -99,6 +102,8 @@ public class DBStoreMigrator
private final Map<EModelElement, EModelElement> repositoryToOldElements = new HashMap<EModelElement, EModelElement>();
+ private final Map<IDBTable, ColumnRenamer> columnRenamers = new HashMap<IDBTable, ColumnRenamer>();
+
public DBStoreMigrator(IDBStoreAccessor accessor, MigrationContext context, Release release)
{
this.accessor = accessor;
@@ -106,82 +111,27 @@ public class DBStoreMigrator
this.release = release;
store = accessor.getStore();
- dbAdapter = store.getDBAdapter();
+ adapter = store.getDBAdapter();
+ connection = accessor.getDBConnection();
mappingStrategy = (IMappingStrategy3)store.getMappingStrategy();
metaDataManager = store.getMetaDataManager();
repository = (InternalRepository)store.getRepository();
repositoryPackageRegistry = repository.getPackageRegistry();
-
- ////////////////////////////////////////////////////////////////////////////////////////
- // Build bidirectional mappings between repository and previous release classifiers.
- ////////////////////////////////////////////////////////////////////////////////////////
-
oldRelease = release.getPreviousRelease();
- if (oldRelease != null)
- {
- for (EPackage oldPackage : oldRelease.getAllPackages())
- {
- EPackage repositoryPackage = repositoryPackageRegistry.getEPackage(oldPackage.getNsURI());
- if (repositoryPackage != null)
- {
- repositoryToOldElements.put(repositoryPackage, oldPackage);
- oldToRepositoryElements.put(oldPackage, repositoryPackage);
- for (EClassifier oldClassifier : oldPackage.getEClassifiers())
- {
- EClassifier repositoryClassifier = repositoryPackage.getEClassifier(oldClassifier.getName());
- if (repositoryClassifier != null)
- {
- repositoryToOldElements.put(repositoryClassifier, oldClassifier);
- oldToRepositoryElements.put(oldClassifier, repositoryClassifier);
-
- if (oldClassifier instanceof EClass)
- {
- EClass oldClass = (EClass)oldClassifier;
- EClass repositoryClass = (EClass)repositoryClassifier;
-
- for (EStructuralFeature oldFeature : oldClass.getEStructuralFeatures())
- {
- EStructuralFeature repositoryFeature = repositoryClass.getEStructuralFeature(oldFeature.getName());
- if (repositoryFeature != null)
- {
- repositoryToOldElements.put(repositoryFeature, oldFeature);
- oldToRepositoryElements.put(oldFeature, repositoryFeature);
- }
- }
- }
- else if (oldClassifier instanceof EEnum)
- {
- EEnum oldEnum = (EEnum)oldClassifier;
- EEnum repositoryEnum = (EEnum)repositoryClassifier;
-
- for (EEnumLiteral oldLiteral : oldEnum.getELiterals())
- {
- EEnumLiteral repositoryLiteral = repositoryEnum.getEEnumLiteral(oldLiteral.getName());
- if (repositoryLiteral != null)
- {
- repositoryToOldElements.put(repositoryLiteral, oldLiteral);
- oldToRepositoryElements.put(oldLiteral, repositoryLiteral);
- }
- }
- }
- }
- }
- }
- }
- }
+ mapRepositoryAndOldElements();
+ createAllRepositoryClassMappings();
}
public void migrate(OMMonitor monitor)
{
- IDBConnection connection = accessor.getDBConnection();
Statement statement = null;
try
{
statement = connection.createStatement();
- migrate(connection, statement, monitor);
+ migrate(statement, monitor);
}
catch (SQLException ex)
{
@@ -193,7 +143,7 @@ public class DBStoreMigrator
}
}
- public void migrate(IDBConnection connection, Statement statement, OMMonitor monitor) throws SQLException
+ private void migrate(Statement statement, OMMonitor monitor) throws SQLException
{
InternalCDOPackageRegistry newPackageRegistry = (InternalCDOPackageRegistry)release.createPackageRegistry();
InternalCDOPackageUnit[] newPackageUnits = newPackageRegistry.getPackageUnits();
@@ -241,7 +191,6 @@ public class DBStoreMigrator
Renamer tableRenamer = new TableRenamer(connection);
Set<IDBTable> tablesToRemove = new HashSet<IDBTable>();
- int counter = 0;
for (ElementChange elementChange : release.getElementChanges(EcorePackage.Literals.ECLASS, ChangeKind.REMOVED))
{
EClass oldClass = (EClass)elementChange.getOldElement();
@@ -252,9 +201,7 @@ public class DBStoreMigrator
{
if (table != null)
{
- String tempName = "CDO_OLD_" + (++counter);
- tableRenamer.addNames(table.getName(), tempName);
- ((InternalDBNamedElement)table).setName(tempName); // TODO Remap in schema?
+ tableRenamer.addName(table.getName());
tablesToRemove.add(table);
}
@@ -266,10 +213,12 @@ public class DBStoreMigrator
////////////////////////////////////////////////////////////////////////////////////////
// Create renaming rules for the mapped tables of renamed classes and features.
+ // Create renaming rules for the columns that become obsolete after the migration.
////////////////////////////////////////////////////////////////////////////////////////
Set<IClassMapping2> addedClassMappings = new HashSet<IClassMapping2>();
Map<CDOID, Pair<CDOID, ? extends EModelElement>> oldToNewMetaIDs = new HashMap<CDOID, Pair<CDOID, ? extends EModelElement>>();
+ List<IDBField> fieldsToRemove = new ArrayList<IDBField>();
for (IClassMapping2 newClassMapping : newClassMappings.values())
{
@@ -277,7 +226,7 @@ public class DBStoreMigrator
EClass oldClass = (EClass)newToOldElements.get(newClass);
IClassMapping2 oldClassMapping = oldClass == null ? null : (IClassMapping2)mappingStrategy.getClassMapping(oldClass);
- IDBTable table = oldClassMapping == null ? null : oldClassMapping.getDBTables().get(0);
+ IDBTable table = oldClassMapping == null ? null : oldClassMapping.getTable();
String oldTableName = table == null ? null : mappingStrategy.getTableName(oldClass);
String newTableName = mappingStrategy.getTableName(newClass);
@@ -291,8 +240,6 @@ public class DBStoreMigrator
{
if (newClass != null)
{
- ColumnRenamer columnRenamer = null;
-
if (table != null)
{
for (ITypeMapping newValueMapping : newClassMapping.getValueMappings())
@@ -305,13 +252,13 @@ public class DBStoreMigrator
if (!newFieldName.equals(oldFieldName))
{
- if (columnRenamer == null)
- {
- columnRenamer = new ColumnRenamer(connection, table);
- }
-
+ ColumnRenamer columnRenamer = getColumnRenamer(table);
columnRenamer.addNames(oldFieldName, newFieldName);
}
+ else
+ {
+ renameChangedColumn(oldClass, oldFeature, newClassMapping, newValueMapping, table, fieldsToRemove);
+ }
monitor.checkCanceled();
}
@@ -340,22 +287,19 @@ public class DBStoreMigrator
if (!newListSizeFieldName.equals(oldListSizeFieldName))
{
- if (columnRenamer == null)
- {
- columnRenamer = new ColumnRenamer(connection, table);
- }
-
+ ColumnRenamer columnRenamer = getColumnRenamer(table);
columnRenamer.addNames(oldListSizeFieldName, newListSizeFieldName);
}
+ else
+ {
+ renameChangedColumn(oldClass, oldFeature, newClassMapping, newListMapping, table, fieldsToRemove);
+ }
}
monitor.checkCanceled();
}
- if (columnRenamer != null)
- {
- columnRenamer.run();
- }
+ runColumnRenamer(table);
CDOID oldMetaID = metaDataManager.getMetaID(oldClass, CDOBranchPoint.UNSPECIFIED_DATE);
CDOID newMetaID = metaDataManager.getMetaID(newClass, CDOBranchPoint.UNSPECIFIED_DATE);
@@ -391,7 +335,12 @@ public class DBStoreMigrator
tableRenamer.run();
////////////////////////////////////////////////////////////////////////////////////////
- // Create table columns for features added to existing classes.
+ // Create table columns for features added to existing classes, i.e.:
+ // 1. A value column for a new single-valued feature
+ // 2. A list size column for a new many-valued feature
+ // 3. A boolean column for a new unsettable feature
+ //
+ // Create table columns for existing features that map to a different column type.
////////////////////////////////////////////////////////////////////////////////////////
IDBSchemaTransaction schemaTransaction = null;
@@ -409,7 +358,7 @@ public class DBStoreMigrator
IClassMapping2 repositoryClassMapping = (IClassMapping2)mappingStrategy.getClassMapping(repositoryClass);
if (repositoryClassMapping != null)
{
- IDBTable table = repositoryClassMapping.getDBTables().get(0);
+ IDBTable table = repositoryClassMapping.getTable();
if (table != null)
{
for (IFeatureMapping newFeatureMapping : newClassMapping.getFeatureMappings())
@@ -418,16 +367,40 @@ public class DBStoreMigrator
EStructuralFeature oldFeature = (EStructuralFeature)newToOldElements.get(newFeature);
if (oldFeature == null)
{
- context.log("New feature " + newClass.getName() + "." + newFeature.getName());
-
+ // Create table column for the added feature.
if (schemaTransaction == null)
{
schemaTransaction = store.getDatabase().openSchemaTransaction(connection);
}
- IDBSchema workingCopy = schemaTransaction.getWorkingCopy();
- IDBTable workingTable = workingCopy.getTable(table.getName());
- repositoryClassMapping.createFeatureMappings(workingTable, false, newFeature);
+ IDBTable workingTable = schemaTransaction.getWorkingCopy().getTable(table.getName());
+ IFeatureMapping featureMapping = repositoryClassMapping.createFeatureMappings(workingTable, false, newFeature)[0];
+
+ IDBField field = AbstractFeatureMapping.getField(repositoryClassMapping, featureMapping);
+ context.log("Creating column for new feature " + newClass.getName() + "." + newFeature.getName() + " --> " + field.getFullName());
+ }
+ else
+ {
+ EStructuralFeature repositoryFeature = (EStructuralFeature)oldToRepositoryElements.get(oldFeature);
+ IFeatureMapping repositoryFeatureMapping = repositoryClassMapping.getFeatureMapping(repositoryFeature);
+
+ IDBField repositoryField = AbstractFeatureMapping.getField(repositoryClassMapping, repositoryFeatureMapping);
+ IDBField newField = AbstractFeatureMapping.getField(newClassMapping, newFeatureMapping);
+
+ if (!newField.isAssignableFrom(repositoryField))
+ {
+ // Create table column for the changed feature.
+ if (schemaTransaction == null)
+ {
+ schemaTransaction = store.getDatabase().openSchemaTransaction(connection);
+ }
+
+ IDBTable workingTable = schemaTransaction.getWorkingCopy().getTable(table.getName());
+ IFeatureMapping featureMapping = repositoryClassMapping.createFeatureMappings(workingTable, false, newFeature)[0];
+
+ IDBField field = AbstractFeatureMapping.getField(repositoryClassMapping, featureMapping);
+ context.log("Creating column for changed feature " + newClass.getName() + "." + newFeature.getName() + " --> " + field.getFullName());
+ }
}
}
}
@@ -446,11 +419,19 @@ public class DBStoreMigrator
finally
{
IOUtil.close(schemaTransaction);
+ schemaTransaction = null;
}
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
+ context.log("######################");
+ context.log("Migrating instances...");
+ context.log("######################");
+
+ ////////////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////////////
+
if (!tablesToRemove.isEmpty())
{
context.log("Dropping obsolete tables:");
@@ -458,7 +439,7 @@ public class DBStoreMigrator
for (IDBTable table : tablesToRemove)
{
context.log(" " + table);
- dbAdapter.dropTable(table, statement);
+ adapter.dropTable(table, statement);
monitor.checkCanceled();
}
}
@@ -466,6 +447,39 @@ public class DBStoreMigrator
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
+ if (!fieldsToRemove.isEmpty())
+ {
+ context.log("Dropping obsolete columns:");
+ schemaTransaction = store.getDatabase().openSchemaTransaction(connection);
+ IDBSchema workingSchema = schemaTransaction.getWorkingCopy();
+
+ try
+ {
+ for (IDBField field : fieldsToRemove)
+ {
+ context.log(" " + field.getFullName());
+
+ IDBTable workingTable = workingSchema.getTableSafe(field.getTable().getName());
+ IDBField workingField = workingTable.getFieldSafe(field.getName());
+ workingField.remove();
+ monitor.checkCanceled();
+ }
+
+ IDBSchemaDelta schemaDelta = schemaTransaction.getSchemaDelta();
+ context.log(DBUtil.dumpToString(schemaDelta));
+
+ schemaTransaction.commit();
+ }
+ finally
+ {
+ IOUtil.close(schemaTransaction);
+ schemaTransaction = null;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////////////
+
if (oldRelease != null)
{
context.log("Removing old package units from system tables:");
@@ -487,9 +501,7 @@ public class DBStoreMigrator
////////////////////////////////////////////////////////////////////////////////////////
context.log("Adding new package units to system tables:");
- for (
-
- InternalCDOPackageUnit newPackageUnit : newPackageUnits)
+ for (InternalCDOPackageUnit newPackageUnit : newPackageUnits)
{
context.log(" " + newPackageUnit.getID());
}
@@ -517,6 +529,125 @@ public class DBStoreMigrator
}
/**
+ * Build bidirectional mappings between repository and previous release classifiers.
+ */
+ private void mapRepositoryAndOldElements()
+ {
+ if (oldRelease != null)
+ {
+ for (EPackage oldPackage : oldRelease.getAllPackages())
+ {
+ EPackage repositoryPackage = repositoryPackageRegistry.getEPackage(oldPackage.getNsURI());
+ if (repositoryPackage != null)
+ {
+ repositoryToOldElements.put(repositoryPackage, oldPackage);
+ oldToRepositoryElements.put(oldPackage, repositoryPackage);
+
+ for (EClassifier oldClassifier : oldPackage.getEClassifiers())
+ {
+ EClassifier repositoryClassifier = repositoryPackage.getEClassifier(oldClassifier.getName());
+ if (repositoryClassifier != null)
+ {
+ repositoryToOldElements.put(repositoryClassifier, oldClassifier);
+ oldToRepositoryElements.put(oldClassifier, repositoryClassifier);
+
+ if (oldClassifier instanceof EClass)
+ {
+ EClass oldClass = (EClass)oldClassifier;
+ EClass repositoryClass = (EClass)repositoryClassifier;
+
+ for (EStructuralFeature oldFeature : oldClass.getEStructuralFeatures())
+ {
+ EStructuralFeature repositoryFeature = repositoryClass.getEStructuralFeature(oldFeature.getName());
+ if (repositoryFeature != null)
+ {
+ repositoryToOldElements.put(repositoryFeature, oldFeature);
+ oldToRepositoryElements.put(oldFeature, repositoryFeature);
+ }
+ }
+ }
+ else if (oldClassifier instanceof EEnum)
+ {
+ EEnum oldEnum = (EEnum)oldClassifier;
+ EEnum repositoryEnum = (EEnum)repositoryClassifier;
+
+ for (EEnumLiteral oldLiteral : oldEnum.getELiterals())
+ {
+ EEnumLiteral repositoryLiteral = repositoryEnum.getEEnumLiteral(oldLiteral.getName());
+ if (repositoryLiteral != null)
+ {
+ repositoryToOldElements.put(repositoryLiteral, oldLiteral);
+ oldToRepositoryElements.put(oldLiteral, repositoryLiteral);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void createAllRepositoryClassMappings()
+ {
+ Map<String, String> mappingStrategyProperties = mappingStrategy.getProperties();
+ String oldEagerTableCreation = mappingStrategyProperties.put(Props.EAGER_TABLE_CREATION, String.valueOf(Boolean.FALSE));
+
+ try
+ {
+ mappingStrategy.getClassMappings(true);
+ }
+ finally
+ {
+ mappingStrategyProperties.put(Props.EAGER_TABLE_CREATION, oldEagerTableCreation);
+ }
+ }
+
+ private ColumnRenamer getColumnRenamer(IDBTable table)
+ {
+ ColumnRenamer columnRenamer = columnRenamers.get(table);
+ if (columnRenamer == null)
+ {
+ columnRenamer = new ColumnRenamer(connection, table);
+ columnRenamers.put(table, columnRenamer);
+ }
+
+ return columnRenamer;
+ }
+
+ private ColumnRenamer runColumnRenamer(IDBTable table)
+ {
+ ColumnRenamer columnRenamer = columnRenamers.get(table);
+ if (columnRenamer != null)
+ {
+ columnRenamer.run();
+ }
+
+ return columnRenamer;
+ }
+
+ private void renameChangedColumn(EClass oldClass, EStructuralFeature oldFeature, IClassMapping2 newClassMapping, IFeatureMapping newFeatureMapping,
+ IDBTable table, List<IDBField> columnsToDelete)
+ {
+ EClass repositoryClass = (EClass)oldToRepositoryElements.get(oldClass);
+ IClassMapping2 repositoryClassMapping = (IClassMapping2)mappingStrategy.getClassMapping(repositoryClass);
+
+ EStructuralFeature repositoryFeature = (EStructuralFeature)oldToRepositoryElements.get(oldFeature);
+ IFeatureMapping repositoryFeatureMapping = repositoryClassMapping.getFeatureMapping(repositoryFeature);
+
+ IDBField repositoryField = AbstractFeatureMapping.getField(repositoryClassMapping, repositoryFeatureMapping);
+ IDBField newField = AbstractFeatureMapping.getField(newClassMapping, newFeatureMapping);
+
+ if (!newField.isAssignableFrom(repositoryField))
+ {
+ ColumnRenamer columnRenamer = getColumnRenamer(table);
+ columnRenamer.addName(repositoryField.getName());
+
+ columnsToDelete.add(repositoryField);
+ }
+ }
+
+ /**
* @author Eike Stepper
*/
public abstract class LoggingRenamer extends Renamer
@@ -645,7 +776,11 @@ public class DBStoreMigrator
public TableRenamer(IDBConnection connection)
{
super(connection, "Renaming tables:");
+ }
+ @Override
+ protected void initNames()
+ {
// Initialize the renamer with all existing table names.
for (IDBTable table : accessor.getStore().getDBSchema().getTables())
{
@@ -656,7 +791,7 @@ public class DBStoreMigrator
@Override
protected String getSQL(String oldName, String newName)
{
- return dbAdapter.sqlRenameTable(newName, oldName);
+ return adapter.sqlRenameTable(newName, oldName);
}
@Override
@@ -690,7 +825,11 @@ public class DBStoreMigrator
{
super(connection, "Renaming columns of table " + table + ":");
this.table = table;
+ }
+ @Override
+ protected void initNames()
+ {
// Initialize the renamer with all existing column names.
for (IDBField field : table.getFields())
{
@@ -708,7 +847,7 @@ public class DBStoreMigrator
try
{
- return dbAdapter.sqlRenameField(field, oldName);
+ return adapter.sqlRenameField(field, oldName);
}
finally
{
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractBasicListTableMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractBasicListTableMapping.java
index 7cf19c5a30..f303e8ca1e 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractBasicListTableMapping.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractBasicListTableMapping.java
@@ -26,6 +26,7 @@ import org.eclipse.emf.cdo.common.revision.delta.CDOSetFeatureDelta;
import org.eclipse.emf.cdo.common.revision.delta.CDOUnsetFeatureDelta;
import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
import org.eclipse.emf.cdo.server.db.IIDHandler;
+import org.eclipse.emf.cdo.server.db.mapping.AbstractFeatureMapping;
import org.eclipse.emf.cdo.server.db.mapping.IClassMapping;
import org.eclipse.emf.cdo.server.db.mapping.IListMapping4;
import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
@@ -36,6 +37,7 @@ import org.eclipse.emf.cdo.server.internal.db.mapping.AbstractMappingStrategy;
import org.eclipse.net4j.db.DBException;
import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.db.ddl.IDBField;
import org.eclipse.net4j.db.ddl.IDBTable;
import org.eclipse.net4j.util.om.trace.ContextTracer;
@@ -56,24 +58,17 @@ import java.util.Set;
/**
* @author Stefan Winkler
*/
-public abstract class AbstractBasicListTableMapping implements IListMapping4, IMappingConstants
+public abstract class AbstractBasicListTableMapping extends AbstractFeatureMapping implements IListMapping4, IMappingConstants
{
- private IMappingStrategy mappingStrategy;
-
private EClass containingClass;
- private EStructuralFeature feature;
+ private IDBField listSizeField;
public AbstractBasicListTableMapping(IMappingStrategy mappingStrategy, EClass containingClass, EStructuralFeature feature)
{
- this.mappingStrategy = mappingStrategy;
+ setMappingStrategy(mappingStrategy);
+ setFeature(feature);
this.containingClass = containingClass;
- this.feature = feature;
- }
-
- public final IMappingStrategy getMappingStrategy()
- {
- return mappingStrategy;
}
public final EClass getContainingClass()
@@ -81,11 +76,6 @@ public abstract class AbstractBasicListTableMapping implements IListMapping4, IM
return containingClass;
}
- public final EStructuralFeature getFeature()
- {
- return feature;
- }
-
public IDBTable getTable()
{
Iterator<IDBTable> iterator = getDBTables().iterator();
@@ -97,6 +87,16 @@ public abstract class AbstractBasicListTableMapping implements IListMapping4, IM
return null;
}
+ public IDBField getField()
+ {
+ return listSizeField;
+ }
+
+ public void setField(IDBField field)
+ {
+ listSizeField = field;
+ }
+
public void addSimpleChunkWhere(IDBStoreAccessor accessor, CDOID cdoid, StringBuilder builder, int index)
{
builder.append(LIST_IDX);
diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java
index 0f01db5c7f..e75f3b174f 100644
--- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java
+++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java
@@ -38,6 +38,7 @@ import org.eclipse.emf.cdo.server.db.IDBStoreAccessor;
import org.eclipse.emf.cdo.server.db.IIDHandler;
import org.eclipse.emf.cdo.server.db.mapping.IClassMapping2;
import org.eclipse.emf.cdo.server.db.mapping.IFeatureMapping;
+import org.eclipse.emf.cdo.server.db.mapping.IFeatureMapping2;
import org.eclipse.emf.cdo.server.db.mapping.IListMapping;
import org.eclipse.emf.cdo.server.db.mapping.IListMapping3;
import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
@@ -162,7 +163,12 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping2,
addListMapping(listMapping);
IDBField listSizeField = table.getField(fieldName);
- addListSizeFiled(feature, listSizeField);
+ addListSizeField(feature, listSizeField);
+
+ if (listMapping instanceof IFeatureMapping2)
+ {
+ ((IFeatureMapping2)listMapping).setField(listSizeField);
+ }
}
}
else
@@ -187,6 +193,12 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping2,
String fieldName = mappingStrategy.getUnsettableFieldName(feature);
IDBField field = table.getField(fieldName);
unsettableFields.put(feature, field);
+
+ IFeatureMapping featureMapping = getFeatureMapping(feature);
+ if (featureMapping instanceof IFeatureMapping2)
+ {
+ ((IFeatureMapping2)featureMapping).setUnsettableField(field);
+ }
}
}
@@ -281,10 +293,14 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping2,
// Add field for list sizes.
IDBField listSizeField = table.addField(fieldName, DBType.INTEGER);
-
if (updateClassMapping)
{
- addListSizeFiled(feature, listSizeField);
+ addListSizeField(feature, listSizeField);
+ }
+
+ if (listMapping instanceof IFeatureMapping2)
+ {
+ ((IFeatureMapping2)listMapping).setField(listSizeField);
}
}
}
@@ -324,7 +340,13 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping2,
for (EStructuralFeature feature : unsettableFields.keySet())
{
String fieldName = mappingStrategy.getUnsettableFieldName(feature);
- table.addField(fieldName, DBType.BOOLEAN);
+ IDBField field = table.addField(fieldName, DBType.BOOLEAN);
+
+ IFeatureMapping featureMapping = getFeatureMapping(feature);
+ if (featureMapping instanceof IFeatureMapping2)
+ {
+ ((IFeatureMapping2)featureMapping).setUnsettableField(field);
+ }
}
if (updateClassMapping)
@@ -420,7 +442,7 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping2,
listMappings.add(mapping);
}
- private void addListSizeFiled(EStructuralFeature feature, IDBField field)
+ private void addListSizeField(EStructuralFeature feature, IDBField field)
{
if (listSizeFields == null)
{
@@ -687,7 +709,7 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping2,
return null;
}
- protected final IDBTable getTable()
+ public final IDBTable getTable()
{
return table;
}
diff --git a/plugins/org.eclipse.emf.cdo.server.evolution/src/org/eclipse/emf/cdo/server/evolution/Renamer.java b/plugins/org.eclipse.emf.cdo.server.evolution/src/org/eclipse/emf/cdo/server/evolution/Renamer.java
index d4a5862c9e..c0137baa28 100644
--- a/plugins/org.eclipse.emf.cdo.server.evolution/src/org/eclipse/emf/cdo/server/evolution/Renamer.java
+++ b/plugins/org.eclipse.emf.cdo.server.evolution/src/org/eclipse/emf/cdo/server/evolution/Renamer.java
@@ -27,6 +27,10 @@ public abstract class Renamer implements Runnable
private final Map<String, String> newNames = new HashMap<String, String>();
+ private boolean initialized;
+
+ private int counter;
+
public Renamer()
{
}
@@ -43,6 +47,12 @@ public abstract class Renamer implements Runnable
public void addNames(String oldName, String newName)
{
+ if (!initialized)
+ {
+ initialized = true;
+ initNames();
+ }
+
if (oldName != null)
{
oldNames.put(oldName, newName);
@@ -54,10 +64,17 @@ public abstract class Renamer implements Runnable
}
}
+ public String addName(String oldName)
+ {
+ String newName = createUniqueName(++counter);
+ addNames(oldName, newName);
+ return newName;
+ }
+
public void run()
{
List<String> colliding = new ArrayList<String>();
- Set<String> newNames = new HashSet<String>();
+ Set<String> names = new HashSet<String>();
for (Map.Entry<String, String> entry : oldNames.entrySet())
{
@@ -80,21 +97,21 @@ public abstract class Renamer implements Runnable
doRename(oldName, newName);
}
- newNames.add(newName);
+ names.add(newName);
}
}
Map<String, String> tempNames = new LinkedHashMap<String, String>();
- int tempCounter = 0;
+ int tmpCounter = 0;
while (!colliding.isEmpty())
{
String oldName = colliding.remove(0);
String newName = oldNames.get(oldName);
- if (newNames.contains(newName) || colliding.contains(newName))
+ if (names.contains(newName) || colliding.contains(newName))
{
- String tempName = createTempName(++tempCounter);
+ String tempName = createTmpName(++tmpCounter);
tempNames.put(tempName, newName);
doRename(oldName, tempName);
@@ -111,20 +128,38 @@ public abstract class Renamer implements Runnable
String newName = entry.getValue();
doRename(tempName, newName);
}
+
+ oldNames.clear();
+ newNames.clear();
+ initialized = false;
+ }
+
+ protected void initNames()
+ {
}
protected abstract void doRename(String oldName, String newName);
- protected String createTempName(int id)
+ protected String createTmpName(int id)
{
- return getTempPrefix() + id;
+ return getTmpPrefix() + id;
}
- protected String getTempPrefix()
+ protected String getTmpPrefix()
{
return "CDO_TMP_";
}
+ protected String createUniqueName(int id)
+ {
+ return getUniquePrefix() + id;
+ }
+
+ protected String getUniquePrefix()
+ {
+ return "CDO_OLD_";
+ }
+
// public static void main(String[] args)
// {
// Renamer renamer = new Renamer()
diff --git a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/EvolutionTest.java b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/EvolutionTest.java
index 339e1389d2..9d0e46278e 100644
--- a/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/EvolutionTest.java
+++ b/plugins/org.eclipse.emf.cdo.tests.db/src/org/eclipse/emf/cdo/tests/db/EvolutionTest.java
@@ -596,6 +596,56 @@ public class EvolutionTest extends AbstractCDOTest
assertEquals(3, eList(customer2, "sites").size());
}
+ public void testChangeAttributeType_SingleValued() throws Exception
+ {
+ // InternalRepository repository = getRepository();
+ // IDBStore store = (IDBStore)repository.getStore();
+ // IDBSchema schema = store.getDatabase().getSchema();
+ // IMappingStrategy mappingStrategy = store.getMappingStrategy();
+
+ Model model = createEvolution("evolution/model1.ecore");
+ String nsURI = model.getRootPackage().getNsURI();
+ Evolution evolution = model.getEvolution();
+
+ Release v1 = evolution.createRelease();
+ migrate(v1);
+
+ CDOSession session0 = openSession();
+ CDOTransaction transaction0 = session0.openTransaction();
+ CDOResource resource0 = transaction0.getOrCreateResource(getResourcePath("res"));
+ EObject customer0 = new SessionPackage(nsURI).create("Customer");
+ resource0.getContents().add(customer0);
+ transaction0.commit();
+ session0.close();
+
+ EPackage ePackage = model.getRootPackage();
+ EClass addressClass = (EClass)ePackage.getEClassifier("Address");
+ addressClass.getEStructuralFeature("city").setEType(EcorePackage.Literals.EINT);
+
+ Release v2 = evolution.createRelease();
+ migrate(v2);
+
+ CDOSession session = openSession();
+
+ CDOPackageUnit packageUnit = session.getPackageRegistry().getPackageUnit(nsURI);
+ assertNotNull(packageUnit);
+
+ EObject customer = new SessionPackage(nsURI).create("Customer");
+ eSet(customer, "city", 32584);
+
+ CDOTransaction transaction = session.openTransaction();
+ CDOResource resource = transaction.getOrCreateResource(getResourcePath("res"));
+ resource.getContents().add(customer);
+ transaction.commit();
+ CDOID customerID = CDOUtil.getCDOObject(customer).cdoID();
+ session.close();
+
+ CDOSession session2 = openSession();
+ CDOTransaction transaction2 = session2.openTransaction();
+ EObject customer2 = transaction2.getObject(customerID);
+ assertEquals(32584, eGet(customer2, "city"));
+ }
+
public void _testNewPackageVersionWithSameNSURI() throws Exception
{
throw new UnsupportedOperationException();
@@ -615,4 +665,34 @@ public class EvolutionTest extends AbstractCDOTest
{
throw new UnsupportedOperationException();
}
+
+ public void _testChangeAttributeToSingleValued() throws Exception
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void _testChangeAttributeToManyValued() throws Exception
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void _testChangeReferenceToSingleValued() throws Exception
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void _testChangeReferenceToManyValued() throws Exception
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void _testChangeAttributeToReference() throws Exception
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public void _testChangeReferenceToAttribute() throws Exception
+ {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBType.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBType.java
index 9cc76a2eac..da382a8506 100644
--- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBType.java
+++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBType.java
@@ -790,6 +790,14 @@ public enum DBType
}
/**
+ * @since 4.8
+ */
+ public boolean isAssignableFrom(DBType other)
+ {
+ return equals(other);
+ }
+
+ /**
* @since 3.0
*/
public void writeValue(ExtendedDataOutput out, ResultSet resultSet, int column, boolean canBeNull) throws SQLException, IOException
diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/IDBField.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/IDBField.java
index a2add8a0a5..25914bbaa0 100644
--- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/IDBField.java
+++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/IDBField.java
@@ -56,5 +56,10 @@ public interface IDBField extends IDBSchemaElement, PositionProvider
/**
* @since 4.8
*/
+ public boolean isAssignableFrom(IDBField other);
+
+ /**
+ * @since 4.8
+ */
public boolean rename(String newName);
}
diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBField.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBField.java
index ea0b2d927f..21c44b100d 100644
--- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBField.java
+++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBField.java
@@ -243,6 +243,31 @@ public class DBField extends DBSchemaElement implements InternalDBField
((InternalDBTable)table).removeField(this);
}
+ public boolean isAssignableFrom(IDBField other)
+ {
+ if (!getType().isAssignableFrom(other.getType()))
+ {
+ return false;
+ }
+
+ if (getPrecision() < other.getPrecision())
+ {
+ return false;
+ }
+
+ if (getScale() < other.getScale())
+ {
+ return false;
+ }
+
+ if (isNotNull() && !other.isNotNull())
+ {
+ return false;
+ }
+
+ return true;
+ }
+
public String formatPrecision()
{
int precision = getPrecision();
diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DelegatingDBField.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DelegatingDBField.java
index c4e808594c..bb216cb79e 100644
--- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DelegatingDBField.java
+++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DelegatingDBField.java
@@ -107,6 +107,11 @@ public final class DelegatingDBField extends DelegatingDBSchemaElement implement
getDelegate().setNotNull(notNull);
}
+ public boolean isAssignableFrom(IDBField other)
+ {
+ return getDelegate().isAssignableFrom(unwrap(other));
+ }
+
public String formatPrecision()
{
return getDelegate().formatPrecision();

Back to the top