diff options
Diffstat (limited to 'plugins/org.eclipse.emf.cdo.server.db')
45 files changed, 2588 insertions, 755 deletions
diff --git a/plugins/org.eclipse.emf.cdo.server.db/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.server.db/META-INF/MANIFEST.MF index c647e64286..eeb863c4b8 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.emf.cdo.server.db/META-INF/MANIFEST.MF @@ -1,7 +1,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-SymbolicName: org.eclipse.emf.cdo.server.db;singleton:=true -Bundle-Version: 4.6.0.qualifier +Bundle-Version: 4.7.0.qualifier Bundle-Name: %pluginName Bundle-Vendor: %providerName Bundle-Localization: plugin @@ -11,12 +11,12 @@ Bundle-RequiredExecutionEnvironment: J2SE-1.5 Bundle-ClassPath: . Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)", org.eclipse.net4j.db;bundle-version="[4.0.0,5.0.0)";visibility:=reexport, - org.eclipse.emf.cdo.server;bundle-version="[4.0.0,5.0.0)";visibility:=reexport -Export-Package: org.eclipse.emf.cdo.server.db;version="4.6.0", - org.eclipse.emf.cdo.server.db.mapping;version="4.6.0", - org.eclipse.emf.cdo.server.internal.db;version="4.6.0";x-friends:="org.eclipse.emf.cdo.tests,org.eclipse.emf.cdo.tests.db,org.eclipse.emf.cdo.explorer.ui", - org.eclipse.emf.cdo.server.internal.db.bundle;version="4.6.0";x-internal:=true, - org.eclipse.emf.cdo.server.internal.db.mapping;version="4.6.0";x-friends:="org.eclipse.emf.cdo.tests,org.eclipse.emf.cdo.tests.db", - org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;version="4.6.0";x-friends:="org.eclipse.emf.cdo.tests,org.eclipse.emf.cdo.tests.db", - org.eclipse.emf.cdo.server.internal.db.messages;version="4.6.0";x-internal:=true + org.eclipse.emf.cdo.server.evolution;bundle-version="[1.0.0,2.0.0)";visibility:=reexport +Export-Package: org.eclipse.emf.cdo.server.db;version="4.7.0", + org.eclipse.emf.cdo.server.db.mapping;version="4.7.0", + org.eclipse.emf.cdo.server.internal.db;version="4.7.0";x-friends:="org.eclipse.emf.cdo.tests,org.eclipse.emf.cdo.tests.db,org.eclipse.emf.cdo.explorer.ui", + org.eclipse.emf.cdo.server.internal.db.bundle;version="4.7.0";x-internal:=true, + org.eclipse.emf.cdo.server.internal.db.mapping;version="4.7.0";x-friends:="org.eclipse.emf.cdo.tests,org.eclipse.emf.cdo.tests.db", + org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;version="4.7.0";x-friends:="org.eclipse.emf.cdo.tests,org.eclipse.emf.cdo.tests.db", + org.eclipse.emf.cdo.server.internal.db.messages;version="4.7.0";x-internal:=true Automatic-Module-Name: org.eclipse.emf.cdo.server.db diff --git a/plugins/org.eclipse.emf.cdo.server.db/plugin.xml b/plugins/org.eclipse.emf.cdo.server.db/plugin.xml index 9ccde6a50a..b7c0881896 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/plugin.xml +++ b/plugins/org.eclipse.emf.cdo.server.db/plugin.xml @@ -15,13 +15,19 @@ <extension-point id="mappingStrategies" name="%extension-point.name" schema="schema/mappingStrategies.exsd"/> - <extension - point="org.eclipse.net4j.util.factories"> + <extension point="org.eclipse.net4j.util.factories"> + <factory + productGroup="org.eclipse.emf.cdo.server.browserPages" + type="dbmappings" + class="org.eclipse.emf.cdo.server.internal.db.DBMappingsPage$Factory"/> <factory - class="org.eclipse.emf.cdo.server.internal.db.DBBrowserPage$Factory" productGroup="org.eclipse.emf.cdo.server.browserPages" - type="db"> - </factory> + type="dbschema" + class="org.eclipse.emf.cdo.server.internal.db.DBSchemaPage$Factory"/> + <factory + productGroup="org.eclipse.emf.cdo.server.browserPages" + type="dbtables" + class="org.eclipse.emf.cdo.server.internal.db.DBTablesPage$Factory"/> </extension> <extension @@ -32,8 +38,7 @@ </storeFactory> </extension> - <extension - point="org.eclipse.emf.cdo.server.db.mappingStrategies"> + <extension point="org.eclipse.emf.cdo.server.db.mappingStrategies"> <mappingStrategy class="org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalMappingStrategy" type="horizontal"/> diff --git a/plugins/org.eclipse.emf.cdo.server.db/pom.xml b/plugins/org.eclipse.emf.cdo.server.db/pom.xml index 4d4b891552..b9bbbb2f03 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/pom.xml +++ b/plugins/org.eclipse.emf.cdo.server.db/pom.xml @@ -25,7 +25,7 @@ <groupId>org.eclipse.emf.cdo</groupId> <artifactId>org.eclipse.emf.cdo.server.db</artifactId> - <version>4.6.0-SNAPSHOT</version> + <version>4.7.0-SNAPSHOT</version> <packaging>eclipse-plugin</packaging> </project> diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/CDODBUtil.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/CDODBUtil.java index 4e8e0a5fab..9b228e91fe 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/CDODBUtil.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/CDODBUtil.java @@ -13,8 +13,10 @@ package org.eclipse.emf.cdo.server.db; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; -import org.eclipse.emf.cdo.server.internal.db.DBBrowserPage; +import org.eclipse.emf.cdo.server.internal.db.DBMappingsPage; +import org.eclipse.emf.cdo.server.internal.db.DBSchemaPage; import org.eclipse.emf.cdo.server.internal.db.DBStore; +import org.eclipse.emf.cdo.server.internal.db.DBTablesPage; import org.eclipse.emf.cdo.server.internal.db.bundle.OM; import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalAuditMappingStrategy; import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalAuditMappingStrategyWithRanges; @@ -78,7 +80,9 @@ public final class CDODBUtil */ public static void prepareContainer(IManagedContainer container) { - container.registerFactory(new DBBrowserPage.Factory()); + container.registerFactory(new DBMappingsPage.Factory()); + container.registerFactory(new DBSchemaPage.Factory()); + container.registerFactory(new DBTablesPage.Factory()); } /** diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreAccessor.java index e21f8d52d8..35fc9967f3 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreAccessor.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreAccessor.java @@ -13,6 +13,7 @@ package org.eclipse.emf.cdo.server.db; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.server.IStoreAccessor; import org.eclipse.emf.cdo.server.IStoreAccessor.UnitSupport; +import org.eclipse.emf.cdo.server.spi.evolution.EvolutionSupport; import org.eclipse.net4j.db.IDBConnection; import org.eclipse.net4j.db.ddl.IDBTable; @@ -28,7 +29,7 @@ import java.sql.Connection; * @noextend This interface is not intended to be extended by clients. * @noimplement This interface is not intended to be implemented by clients. */ -public interface IDBStoreAccessor extends IStoreAccessor.Raw2, UnitSupport +public interface IDBStoreAccessor extends IStoreAccessor.Raw2, UnitSupport, EvolutionSupport { public IDBStore getStore(); diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IMetaDataManager.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IMetaDataManager.java index 23d2074d4b..5e451e063e 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IMetaDataManager.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IMetaDataManager.java @@ -100,6 +100,19 @@ public interface IMetaDataManager public void writePackageUnits(Connection connection, InternalCDOPackageUnit[] packageUnits, OMMonitor monitor); /** + * Delete package units from the database. + * + * @param connection + * the DB connection to write to. + * @param packageUnits + * the package units to delete. + * @param monitor + * the monitor to indicate progress. + * @since 4.7 + */ + public void deletePackageUnits(Connection connection, InternalCDOPackageUnit[] packageUnits, OMMonitor monitor); + + /** * @since 3.0 */ public void rawExport(Connection connection, CDODataOutput out, long fromCommitTime, long toCommitTime) throws IOException; 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 new file mode 100644 index 0000000000..bd71a2613b --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMapping2.java @@ -0,0 +1,46 @@ +/* + * 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.emf.cdo.server.db.IDBStoreAccessor; + +import org.eclipse.net4j.db.ddl.IDBField; +import org.eclipse.net4j.db.ddl.IDBSchema; +import org.eclipse.net4j.db.ddl.IDBTable; + +import org.eclipse.emf.ecore.EStructuralFeature; + +import java.util.Map; + +/** + * An extension interface for {@link IClassMapping class mappings} that support <i>units</i>. + * + * @author Eike Stepper + * @since 4.7 + */ +public interface IClassMapping2 extends IClassMapping +{ + public void setTable(IDBTable table); + + public void initTable(IDBStoreAccessor accessor); + + public IDBTable createTable(IDBSchema schema, String tableName); + + public Map<EStructuralFeature, IDBField> getUnsettableFields(); + + public Map<EStructuralFeature, IDBField> getListSizeFields(); + + public IFeatureMapping[] createFeatureMappings(IDBTable table, boolean updateClassMapping, EStructuralFeature... features); + + public IFeatureMapping[] getFeatureMappings(); + + public IFeatureMapping getFeatureMapping(EStructuralFeature feature); +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IFeatureMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IFeatureMapping.java new file mode 100644 index 0000000000..8c64172042 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IFeatureMapping.java @@ -0,0 +1,27 @@ +/* + * 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.emf.ecore.EStructuralFeature; + +/** + * Mapping of a {@link EStructuralFeature feature} to and from the database. + * + * @author Eike Stepper + * @since 4.7 + */ +public interface IFeatureMapping +{ + /** + * @return The feature which is associated with this mapping. + */ + public EStructuralFeature getFeature(); +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMapping.java index 045e63850c..350b4a3002 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMapping.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMapping.java @@ -23,8 +23,6 @@ import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.net4j.db.ddl.IDBTable; -import org.eclipse.emf.ecore.EStructuralFeature; - import java.util.Collection; import java.util.List; @@ -35,16 +33,9 @@ import java.util.List; * @author Stefan Winkler * @since 2.0 */ -public interface IListMapping +public interface IListMapping extends IFeatureMapping { /** - * Return the mapped feature. - * - * @return the mapped feature. - */ - public EStructuralFeature getFeature(); - - /** * Returns all DB tables which are used by this feature. * * @return a collection of all tables of this feature. diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMapping4.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMapping4.java new file mode 100644 index 0000000000..a39b28da83 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMapping4.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.emf.cdo.server.db.IDBStoreAccessor; + +import org.eclipse.net4j.db.ddl.IDBSchema; +import org.eclipse.net4j.db.ddl.IDBTable; + +/** + * Extension interface to {@link IListMapping3}. + * + * @author Eike Stepper + * @since 4.7 + */ +public interface IListMapping4 extends IListMapping3 +{ + public IDBTable getTable(); + + public void setTable(IDBTable table); + + public void initTable(IDBStoreAccessor accessor); + + public IDBTable createTable(IDBSchema schema, String tableName); +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IMappingStrategy.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IMappingStrategy.java index da87d29f3f..6924d8c44e 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IMappingStrategy.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IMappingStrategy.java @@ -171,7 +171,7 @@ public interface IMappingStrategy * Should only be called by mapping classes. * * @param containingClass - * the class containeng the feature. + * the class containing the feature. * @param feature * the feature for which the table name should be created. * @return the created table name. It is guaranteed that the table name is compatible with the chosen database. @@ -372,7 +372,7 @@ public interface IMappingStrategy public String getListJoin(String attrTable, String listTable); /** - * Contains symbolic constants that specifiy valid keys of {@link IMappingStrategy#getProperties() mapping strategy properties}. + * Contains symbolic constants that specify valid keys of {@link IMappingStrategy#getProperties() mapping strategy properties}. * * @author Eike Stepper * @since 4.4 diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IMappingStrategy3.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IMappingStrategy3.java new file mode 100644 index 0000000000..54491f5829 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IMappingStrategy3.java @@ -0,0 +1,41 @@ +/* + * 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.emf.cdo.common.model.CDOPackageUnit; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; + +import java.util.List; + +/** + * Interface to complement {@link IMappingStrategy}. + * + * @author Eike Stepper + * @since 4.7 + */ +public interface IMappingStrategy3 extends IMappingStrategy +{ + public INamingStrategy getNamingStrategy(); + + public void setNamingStrategy(INamingStrategy namingStrategy); + + public String getUnsettableFieldName(EStructuralFeature feature); + + public boolean isMapped(EClass eClass); + + public List<EClass> getMappedClasses(CDOPackageUnit[] packageUnits); + + public IClassMapping createClassMapping(EClass eClass); + + public void clearClassMappings(); +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/INamingStrategy.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/INamingStrategy.java new file mode 100644 index 0000000000..b7d9c090f6 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/INamingStrategy.java @@ -0,0 +1,77 @@ +/* + * 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.util.factory.ProductCreationException; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.ENamedElement; +import org.eclipse.emf.ecore.EStructuralFeature; + +import java.util.Map; + +/** + * @author Eike Stepper + * @since 4.7 + */ +public interface INamingStrategy +{ + public void initialize(IMappingStrategy mappingStrategy); + + /** + * Create a suitable table name which can be used to map the given element. Should only be called by mapping classes. + * + * @param element + * the element for which the name should be created. It must hold: + * <code>element instanceof EClass || element instanceof EPackage</code>. + * @return the created table name. It is guaranteed that the table name is compatible with the chosen database. + */ + public String getTableName(ENamedElement element); + + /** + * Create a suitable table name which can be used to map the given element. Should only be called by mapping classes. + * Should only be called by mapping classes. + * + * @param containingClass + * the class that contains the feature. + * @param feature + * the feature for which the table name should be created. + * @return the created table name. It is guaranteed that the table name is compatible with the chosen database. + */ + public String getTableName(EClass containingClass, EStructuralFeature feature); + + /** + * Create a suitable column name which can be used to map the given element. Should only be called by mapping classes. + * + * @param feature + * the feature for which the column name should be created. + * @return the created column name. It is guaranteed that the name is compatible with the chosen database. + */ + public String getFieldName(EStructuralFeature feature); + + public String getUnsettableFieldName(EStructuralFeature feature); + + /** + * @author Eike Stepper + */ + public static abstract class Factory extends org.eclipse.net4j.util.factory.PropertiesFactory + { + public static final String PRODUCT_GROUP = "org.eclipse.emf.cdo.server.db.namingStrategies"; + + public Factory(String type) + { + super(PRODUCT_GROUP, type); + } + + @Override + public abstract INamingStrategy create(Map<String, String> properties) throws ProductCreationException; + } +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/ITypeMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/ITypeMapping.java index a7f21053e4..4eaad7aa02 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/ITypeMapping.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/ITypeMapping.java @@ -37,14 +37,9 @@ import java.util.Collection; * @author Stefan Winkler * @since 2.0 */ -public interface ITypeMapping +public interface ITypeMapping extends IFeatureMapping { /** - * @return The feature which is associated with this mapping. - */ - public EStructuralFeature getFeature(); - - /** * @return The db field which is associated with this mapping. */ public IDBField getField(); diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/CDODBSchema.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/CDODBSchema.java index 354249ff59..943445f12a 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/CDODBSchema.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/CDODBSchema.java @@ -70,7 +70,7 @@ public class CDODBSchema PACKAGE_UNITS.addField("time_stamp", DBType.BIGINT); //$NON-NLS-1$ public static final IDBField PACKAGE_UNITS_PACKAGE_DATA = // - PACKAGE_UNITS.addField("package_data", DBType.BLOB); //$NON-NLS-1$ + PACKAGE_UNITS.addField("package_data", MetaDataManager.ZIP_PACKAGE_BYTES ? DBType.BLOB : DBType.CLOB); //$NON-NLS-1$ public static final IDBIndex INDEX_PACKAGE_UNITS_PK = // PACKAGE_UNITS.addIndex(IDBIndex.Type.PRIMARY_KEY, PACKAGE_UNITS_ID); diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBMappingsPage.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBMappingsPage.java new file mode 100644 index 0000000000..a0eb4ef3f5 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBMappingsPage.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2010-2013, 2015, 2016 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.internal.db; + +import org.eclipse.emf.cdo.common.model.CDOPackageRegistry; +import org.eclipse.emf.cdo.common.model.CDOPackageUnit; +import org.eclipse.emf.cdo.common.model.EMFUtil; +import org.eclipse.emf.cdo.server.CDOServerBrowser; +import org.eclipse.emf.cdo.server.CDOServerBrowser.AbstractPage; +import org.eclipse.emf.cdo.server.db.IDBStore; +import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; +import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; +import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy3; +import org.eclipse.emf.cdo.spi.server.InternalRepository; + +import org.eclipse.net4j.db.ddl.IDBTable; +import org.eclipse.net4j.util.factory.ProductCreationException; + +import org.eclipse.emf.ecore.EClass; + +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Eike Stepper + * @since 4.0 + */ +public class DBMappingsPage extends AbstractPage +{ + public DBMappingsPage() + { + super("mappings", "DB Mappings"); + } + + public boolean canDisplay(InternalRepository repository) + { + return repository.getStore() instanceof IDBStore; + } + + public void display(CDOServerBrowser browser, InternalRepository repository, PrintStream out) + { + boolean mapAll = "all".equals(browser.getParam("map")); + + IDBStore store = (IDBStore)repository.getStore(); + IMappingStrategy mappingStrategy = store.getMappingStrategy(); + Map<EClass, IClassMapping> classMappings = mappingStrategy.getClassMappings(mapAll); + + if (mappingStrategy instanceof IMappingStrategy3) + { + CDOPackageRegistry packageRegistry = store.getRepository().getPackageRegistry(); + CDOPackageUnit[] packageUnits = packageRegistry.getPackageUnits(); + + IMappingStrategy3 mappingStrategy3 = (IMappingStrategy3)mappingStrategy; + List<EClass> mappedClasses = mappingStrategy3.getMappedClasses(packageUnits); + + int countMapped = classMappings.size(); + int countMappable = mappedClasses.size(); + + out.print("Mappable classes: " + countMappable + "<br>\r\n"); + out.print("Mapped classes: " + countMapped + "<br>\r\n"); + out.print("Unmapped classes: " + (countMappable - countMapped)); + + if (countMapped < countMappable) + { + out.print(" " + browser.href("(map all)", getName(), "map", "all")); + } + + out.print("<br>\r\n"); + out.print("<br>\r\n"); + } + + List<String> qualifiedNames = new ArrayList<String>(); + Map<String, IClassMapping> byQualifiedName = new LinkedHashMap<String, IClassMapping>(); + for (Map.Entry<EClass, IClassMapping> entry : classMappings.entrySet()) + { + EClass eClass = entry.getKey(); + IClassMapping classMapping = entry.getValue(); + + String qualifiedName = EMFUtil.getQualifiedName(eClass, "."); + qualifiedNames.add(qualifiedName); + byQualifiedName.put(qualifiedName, classMapping); + } + + Collections.sort(qualifiedNames); + + out.print("<table border=1>\r\n"); + out.print("<tr><th>Class</th><th>Table</th></tr/>\r\n"); + + for (String qualifiedName : qualifiedNames) + { + IClassMapping classMapping = byQualifiedName.get(qualifiedName); + List<IDBTable> tables = classMapping.getDBTables(); + + boolean mapped = tables.get(0) != null; + String fontPrefix = mapped ? "<b>" : "<font color=\"gray\">"; + String fontSuffix = mapped ? "</b>" : "</font>"; + + out.print("<tr><td valign=\"top\">"); + out.print(fontPrefix); + out.print(qualifiedName); + out.print(fontSuffix); + out.print("</td><td>"); + + boolean first = true; + for (IDBTable table : tables) + { + if (table != null) + { + if (first) + { + first = false; + } + else + { + out.print("<br/>"); + } + + out.print(DBTablesPage.tableHRef(browser, table)); + } + } + + out.print("</td></tr/>\r\n"); + } + + out.print("</table>\r\n"); + } + + /** + * @author Eike Stepper + */ + public static class Factory extends org.eclipse.net4j.util.factory.Factory + { + public static final String TYPE = "dbmappings"; + + public Factory() + { + super(PRODUCT_GROUP, TYPE); + } + + public DBMappingsPage create(String description) throws ProductCreationException + { + return new DBMappingsPage(); + } + } +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBSchemaPage.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBSchemaPage.java new file mode 100644 index 0000000000..414c104f60 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBSchemaPage.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2010-2013, 2015, 2016 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.internal.db; + +import org.eclipse.emf.cdo.server.CDOServerBrowser; +import org.eclipse.emf.cdo.server.CDOServerBrowser.AbstractPage; +import org.eclipse.emf.cdo.server.db.IDBStore; +import org.eclipse.emf.cdo.spi.server.InternalRepository; + +import org.eclipse.net4j.db.DBUtil; +import org.eclipse.net4j.db.ddl.IDBSchema; +import org.eclipse.net4j.spi.db.ddl.InternalDBNamedElement.DumpFormat; +import org.eclipse.net4j.util.factory.ProductCreationException; +import org.eclipse.net4j.util.io.IOUtil; + +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintStream; + +/** + * @author Eike Stepper + * @since 4.0 + */ +public class DBSchemaPage extends AbstractPage +{ + public DBSchemaPage() + { + super("schema", "DB Schema"); + } + + public boolean canDisplay(InternalRepository repository) + { + return repository.getStore() instanceof IDBStore; + } + + public void display(CDOServerBrowser browser, InternalRepository repository, PrintStream out) + { + IDBStore store = (IDBStore)repository.getStore(); + IDBSchema schema = store.getDBSchema(); + + OutputStreamWriter writer = null; + + try + { + writer = new DumpFormat.HTML(out); + DBUtil.dump(schema, writer); + } + catch (IOException ex) + { + ex.printStackTrace(); + } + finally + { + IOUtil.close(writer); + } + } + + /** + * @author Eike Stepper + */ + public static class Factory extends org.eclipse.net4j.util.factory.Factory + { + public static final String TYPE = "dbschema"; + + public Factory() + { + super(PRODUCT_GROUP, TYPE); + } + + public DBSchemaPage create(String description) throws ProductCreationException + { + return new DBSchemaPage(); + } + } +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java index 99bfa0f933..5a332cdc8b 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreAccessor.java @@ -32,6 +32,7 @@ import org.eclipse.emf.cdo.common.revision.CDORevisionCacheAdder; import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; import org.eclipse.emf.cdo.common.util.CDOQueryInfo; import org.eclipse.emf.cdo.eresource.EresourcePackage; +import org.eclipse.emf.cdo.evolution.Release; import org.eclipse.emf.cdo.server.IQueryHandler; import org.eclipse.emf.cdo.server.IRepository; import org.eclipse.emf.cdo.server.ISession; @@ -52,6 +53,7 @@ import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy2; import org.eclipse.emf.cdo.server.internal.db.bundle.OM; import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.AbstractHorizontalClassMapping; import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.UnitMappingTable; +import org.eclipse.emf.cdo.server.spi.evolution.MigrationContext; import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch; import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranchManager; import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranchManager.BranchLoader3; @@ -76,6 +78,7 @@ import org.eclipse.net4j.db.IDBDatabase; import org.eclipse.net4j.db.IDBPreparedStatement; import org.eclipse.net4j.db.IDBPreparedStatement.ReuseProbability; import org.eclipse.net4j.db.IDBSchemaTransaction; +import org.eclipse.net4j.db.ddl.IDBSchema; import org.eclipse.net4j.db.ddl.IDBTable; import org.eclipse.net4j.internal.db.ddl.DBField; import org.eclipse.net4j.util.HexUtil; @@ -812,12 +815,13 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor, { IDBDatabase database = store.getDatabase(); IDBSchemaTransaction schemaTransaction = database.openSchemaTransaction(); + IDBSchema schema = schemaTransaction.getWorkingCopy(); try { for (IDBTable table : createdTables) { - table.remove(); + schema.removeTable(table.getName()); } schemaTransaction.commit(); @@ -1508,6 +1512,12 @@ public class DBStoreAccessor extends StoreAccessor implements IDBStoreAccessor, unitMappingTable.writeUnitMappings(this, unitMappings, timeStamp); } + public void migrateTo(Release release, MigrationContext context, OMMonitor monitor) + { + DBStoreMigrator migrator = new DBStoreMigrator(this, context, release); + migrator.migrate(monitor); + } + public void tableCreated(IDBTable table) { if (createdTables == null) 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 new file mode 100644 index 0000000000..48940cd907 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreMigrator.java @@ -0,0 +1,738 @@ +/* + * 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.internal.db; + +import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.evolution.ChangeKind; +import org.eclipse.emf.cdo.evolution.ElementChange; +import org.eclipse.emf.cdo.evolution.Release; +import org.eclipse.emf.cdo.evolution.util.ElementHandler; +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.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.IMappingStrategy3; +import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping; +import org.eclipse.emf.cdo.server.evolution.Renamer; +import org.eclipse.emf.cdo.server.internal.db.mapping.AbstractMappingStrategy; +import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.AbstractHorizontalMappingStrategy; +import org.eclipse.emf.cdo.server.spi.evolution.MigrationContext; +import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageRegistry; +import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit; +import org.eclipse.emf.cdo.spi.server.InternalRepository; + +import org.eclipse.net4j.db.DBException; +import org.eclipse.net4j.db.DBUtil; +import org.eclipse.net4j.db.IDBAdapter; +import org.eclipse.net4j.db.IDBConnection; +import org.eclipse.net4j.db.IDBSchemaTransaction; +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; +import org.eclipse.net4j.util.io.IOUtil; +import org.eclipse.net4j.util.lifecycle.LifecycleUtil; +import org.eclipse.net4j.util.om.monitor.OMMonitor; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EEnum; +import org.eclipse.emf.ecore.EEnumLiteral; +import org.eclipse.emf.ecore.EModelElement; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.EcorePackage; + +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @author Eike Stepper + */ +public class DBStoreMigrator +{ + private final IDBStoreAccessor accessor; + + private final MigrationContext context; + + private final Release release; + + private final Release oldRelease; + + private final IDBStore store; + + private final IDBAdapter dbAdapter; + + private final IMappingStrategy3 mappingStrategy; + + private final IMetaDataManager metaDataManager; + + private final InternalRepository repository; + + private final InternalCDOPackageRegistry repositoryPackageRegistry; + + private final Map<EModelElement, EModelElement> oldToRepositoryElements = new HashMap<EModelElement, EModelElement>(); + + private final Map<EModelElement, EModelElement> repositoryToOldElements = new HashMap<EModelElement, EModelElement>(); + + public DBStoreMigrator(IDBStoreAccessor accessor, MigrationContext context, Release release) + { + this.accessor = accessor; + this.context = context; + this.release = release; + + store = accessor.getStore(); + dbAdapter = store.getDBAdapter(); + 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); + } + } + } + } + } + } + } + } + } + + public void migrate(OMMonitor monitor) + { + IDBConnection connection = accessor.getDBConnection(); + Statement statement = null; + + try + { + statement = connection.createStatement(); + migrate(connection, statement, monitor); + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + DBUtil.close(statement); + } + } + + public void migrate(IDBConnection connection, Statement statement, OMMonitor monitor) throws SQLException + { + InternalCDOPackageRegistry newPackageRegistry = (InternalCDOPackageRegistry)release.createPackageRegistry(); + InternalCDOPackageUnit[] newPackageUnits = newPackageRegistry.getPackageUnits(); + Map<EModelElement, EModelElement> newToOldElements = release.getChange().getNewToOldElements(); + + //////////////////////////////////////////////////////////////////////////////////////// + // Compute all new class mappings in a temporary schema. + //////////////////////////////////////////////////////////////////////////////////////// + + Map<EClass, IClassMapping2> newClassMappings = new HashMap<EClass, IClassMapping2>(); + boolean oldSkipMappingInitialization = AbstractMappingStrategy.setSkipMappingInitialization(true); + + try + { + IDBSchema schema = DBUtil.createSchema("v" + release.getVersion()); + + for (EClass newClass : mappingStrategy.getMappedClasses(newPackageUnits)) + { + IClassMapping2 newClassMapping = (IClassMapping2)mappingStrategy.createClassMapping(newClass); + IDBTable newTable = newClassMapping.createTable(schema, mappingStrategy.getTableName(newClass)); + newClassMapping.setTable(newTable); + newClassMappings.put(newClass, newClassMapping); + + for (IListMapping listMapping : newClassMapping.getListMappings()) + { + IDBTable listTable = ((IListMapping4)listMapping).createTable(schema, mappingStrategy.getTableName(newClass, listMapping.getFeature())); + ((IListMapping4)listMapping).setTable(listTable); + monitor.checkCanceled(); + } + + monitor.checkCanceled(); + } + + // context.log("Computing " + DBUtil.dumpToString(schema)); + } + finally + { + AbstractMappingStrategy.setSkipMappingInitialization(oldSkipMappingInitialization); + } + + //////////////////////////////////////////////////////////////////////////////////////// + // Create renaming rules for the tables that become obsolete after the migration. + //////////////////////////////////////////////////////////////////////////////////////// + + 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(); + EClass repositoryClass = (EClass)oldToRepositoryElements.get(oldClass); + IClassMapping repositoryClassMapping = mappingStrategy.getClassMapping(repositoryClass); + + for (IDBTable table : repositoryClassMapping.getDBTables()) + { + if (table != null) + { + String tempName = "CDO_OLD_" + (++counter); + tableRenamer.addNames(table.getName(), tempName); + ((InternalDBNamedElement)table).setName(tempName); // TODO Remap in schema? + tablesToRemove.add(table); + } + + monitor.checkCanceled(); + } + + monitor.checkCanceled(); + } + + //////////////////////////////////////////////////////////////////////////////////////// + // Create renaming rules for the mapped tables of renamed classes and features. + //////////////////////////////////////////////////////////////////////////////////////// + + Set<IClassMapping2> addedClassMappings = new HashSet<IClassMapping2>(); + Map<CDOID, Pair<CDOID, ? extends EModelElement>> oldToNewMetaIDs = new HashMap<CDOID, Pair<CDOID, ? extends EModelElement>>(); + + for (IClassMapping2 newClassMapping : newClassMappings.values()) + { + EClass newClass = newClassMapping.getEClass(); + EClass oldClass = (EClass)newToOldElements.get(newClass); + + IClassMapping2 oldClassMapping = oldClass == null ? null : (IClassMapping2)mappingStrategy.getClassMapping(oldClass); + IDBTable table = oldClassMapping == null ? null : oldClassMapping.getDBTables().get(0); + + String oldTableName = table == null ? null : mappingStrategy.getTableName(oldClass); + String newTableName = mappingStrategy.getTableName(newClass); + + if (!newTableName.equals(oldTableName)) + { + tableRenamer.addNames(oldTableName, newTableName); + } + + if (oldClass != null) + { + if (newClass != null) + { + ColumnRenamer columnRenamer = null; + + if (table != null) + { + for (ITypeMapping newValueMapping : newClassMapping.getValueMappings()) + { + EStructuralFeature newFeature = newValueMapping.getFeature(); + EStructuralFeature oldFeature = (EStructuralFeature)newToOldElements.get(newFeature); + + String oldFieldName = oldFeature == null ? null : mappingStrategy.getFieldName(oldFeature); + String newFieldName = mappingStrategy.getFieldName(newFeature); + + if (!newFieldName.equals(oldFieldName)) + { + if (columnRenamer == null) + { + columnRenamer = new ColumnRenamer(connection, table); + } + + columnRenamer.addNames(oldFieldName, newFieldName); + } + + monitor.checkCanceled(); + } + } + + for (IListMapping newListMapping : newClassMapping.getListMappings()) + { + EStructuralFeature newFeature = newListMapping.getFeature(); + EStructuralFeature oldFeature = (EStructuralFeature)newToOldElements.get(newFeature); + + IListMapping4 oldListMapping = oldFeature == null ? null : (IListMapping4)oldClassMapping.getListMapping(oldFeature); + IDBTable listTable = oldListMapping == null ? null : oldListMapping.getTable(); + + oldTableName = listTable == null ? null : mappingStrategy.getTableName(oldClass, oldFeature); + newTableName = mappingStrategy.getTableName(newClass, newFeature); + + if (!newTableName.equals(oldTableName)) + { + tableRenamer.addNames(oldTableName, newTableName); + } + + if (table != null) + { + String oldListSizeFieldName = oldFeature == null ? null : mappingStrategy.getFieldName(oldFeature); + String newListSizeFieldName = mappingStrategy.getFieldName(newFeature); + + if (!newListSizeFieldName.equals(oldListSizeFieldName)) + { + if (columnRenamer == null) + { + columnRenamer = new ColumnRenamer(connection, table); + } + + columnRenamer.addNames(oldListSizeFieldName, newListSizeFieldName); + } + } + + monitor.checkCanceled(); + } + + if (columnRenamer != null) + { + columnRenamer.run(); + } + + CDOID oldMetaID = metaDataManager.getMetaID(oldClass, CDOBranchPoint.UNSPECIFIED_DATE); + CDOID newMetaID = metaDataManager.getMetaID(newClass, CDOBranchPoint.UNSPECIFIED_DATE); + if (!ObjectUtil.equals(oldMetaID, newMetaID)) + { + oldToNewMetaIDs.put(oldMetaID, Pair.create(newMetaID, newClass)); + + if (mappingStrategy instanceof AbstractHorizontalMappingStrategy) + { + AbstractHorizontalMappingStrategy horizontalMappingStrategy = (AbstractHorizontalMappingStrategy)mappingStrategy; + + int count = horizontalMappingStrategy.getObjectTypeMapper().changeObjectType(accessor, oldClass, newClass); + if (count > 0) + { + context.log("Changed type of " + count + " objects from " + oldMetaID + " to " + newMetaID // + + " (" + ElementHandler.getLabel(oldClass) + " --> " + ElementHandler.getLabel(newClass) + ")"); + } + } + } + } + } + else + { + addedClassMappings.add(newClassMapping); + } + + monitor.checkCanceled(); + } + + //////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////// + + tableRenamer.run(); + + //////////////////////////////////////////////////////////////////////////////////////// + // Create table columns for features added to existing classes. + //////////////////////////////////////////////////////////////////////////////////////// + + IDBSchemaTransaction schemaTransaction = null; + + try + { + for (IClassMapping2 newClassMapping : newClassMappings.values()) + { + EClass newClass = newClassMapping.getEClass(); + EClass oldClass = (EClass)newToOldElements.get(newClass); + if (oldClass != null) + { + EClass repositoryClass = (EClass)oldToRepositoryElements.get(oldClass); + + IClassMapping2 repositoryClassMapping = (IClassMapping2)mappingStrategy.getClassMapping(repositoryClass); + if (repositoryClassMapping != null) + { + IDBTable table = repositoryClassMapping.getDBTables().get(0); + if (table != null) + { + for (IFeatureMapping newFeatureMapping : newClassMapping.getFeatureMappings()) + { + EStructuralFeature newFeature = newFeatureMapping.getFeature(); + EStructuralFeature oldFeature = (EStructuralFeature)newToOldElements.get(newFeature); + if (oldFeature == null) + { + context.log("New feature " + newClass.getName() + "." + newFeature.getName()); + + if (schemaTransaction == null) + { + schemaTransaction = store.getDatabase().openSchemaTransaction(connection); + } + + IDBSchema workingCopy = schemaTransaction.getWorkingCopy(); + IDBTable workingTable = workingCopy.getTable(table.getName()); + repositoryClassMapping.createFeatureMappings(workingTable, false, newFeature); + } + } + } + } + } + } + + if (schemaTransaction != null) + { + IDBSchemaDelta schemaDelta = schemaTransaction.getSchemaDelta(); + context.log(DBUtil.dumpToString(schemaDelta)); + + schemaTransaction.commit(); + } + } + finally + { + IOUtil.close(schemaTransaction); + } + + //////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////// + + if (!tablesToRemove.isEmpty()) + { + context.log("Dropping obsolete tables:"); + + for (IDBTable table : tablesToRemove) + { + context.log(" " + table); + dbAdapter.dropTable(table, statement); + monitor.checkCanceled(); + } + } + + //////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////// + + if (oldRelease != null) + { + context.log("Removing old package units from system tables:"); + List<InternalCDOPackageUnit> repositoryPackageUnits = new ArrayList<InternalCDOPackageUnit>(); + + for (EPackage oldRootPackage : oldRelease.getRootPackages()) + { + EPackage repositoryRootPackage = (EPackage)oldToRepositoryElements.get(oldRootPackage); + InternalCDOPackageUnit repositoryPackageUnit = repositoryPackageRegistry.getPackageUnit(repositoryRootPackage); + repositoryPackageUnits.add(repositoryPackageUnit); + context.log(" " + repositoryPackageUnit.getID()); + } + + InternalCDOPackageUnit[] packageUnits = repositoryPackageUnits.toArray(new InternalCDOPackageUnit[repositoryPackageUnits.size()]); + metaDataManager.deletePackageUnits(connection, packageUnits, monitor); + } + + //////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////// + + context.log("Adding new package units to system tables:"); + for ( + + InternalCDOPackageUnit newPackageUnit : newPackageUnits) + { + context.log(" " + newPackageUnit.getID()); + } + + metaDataManager.writePackageUnits(accessor.getConnection(), newPackageUnits, monitor); + + //////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////////////////////////////////////////////////////////// + + context.log("Committing migration results"); + connection.commit(); + + context.log("Reinitializing package registry"); + LifecycleUtil.deactivate(repositoryPackageRegistry); + LifecycleUtil.activate(repositoryPackageRegistry); + Repository.readPackageUnits(accessor, repositoryPackageRegistry); + + context.log("Resetting metadata manager"); + metaDataManager.clearMetaIDMappings(); + + context.log("Recomputing class mappings"); + mappingStrategy.clearClassMappings(); + mappingStrategy.getClassMappings(true); + + } + + /** + * @author Eike Stepper + */ + public abstract class LoggingRenamer extends Renamer + { + private int count; + + private String header; + + public LoggingRenamer(String header) + { + this.header = header; + } + + public int getCount() + { + return count; + } + + @Override + public void run() + { + try + { + super.run(); + + if (count != 0) + { + doFinally(true); + } + } + catch (RuntimeException ex) + { + if (count != 0) + { + doFinally(false); + } + + throw ex; + } + catch (Error ex) + { + if (count != 0) + { + doFinally(false); + } + + throw ex; + } + } + + protected void doInit() + { + } + + @Override + protected final void doRename(String oldName, String newName) + { + if (++count == 1) + { + context.log(header); + doInit(); + } + + context.log(" " + oldName + " --> " + newName); + doRename(oldName, newName, count); + } + + protected abstract void doRename(String oldName, String newName, int count); + + protected void doFinally(boolean success) + { + } + } + + /** + * @author Eike Stepper + */ + public abstract class JDBCRenamer extends LoggingRenamer + { + private final IDBConnection connection; + + private Statement statement; + + public JDBCRenamer(IDBConnection connection, String header) + { + super(header); + this.connection = connection; + } + + @Override + protected void doInit() + { + try + { + statement = connection.createStatement(); + } + catch (SQLException ex) + { + throw new DBException(ex); + } + } + + @Override + protected void doRename(String oldName, String newName, int count) + { + String sql = getSQL(oldName, newName); + + try + { + statement.execute(sql); + } + catch (SQLException ex) + { + throw new DBException(ex); + } + } + + protected abstract String getSQL(String oldName, String newName); + } + + /** + * @author Eike Stepper + */ + public class TableRenamer extends JDBCRenamer + { + public TableRenamer(IDBConnection connection) + { + super(connection, "Renaming tables:"); + + // Initialize the renamer with all existing table names. + for (IDBTable table : accessor.getStore().getDBSchema().getTables()) + { + addNames(table.getName(), null); + } + } + + @Override + protected String getSQL(String oldName, String newName) + { + return dbAdapter.sqlRenameTable(newName, oldName); + } + + @Override + protected void doRename(String oldName, String newName, int count) + { + super.doRename(oldName, newName, count); + + InternalDBSchema schema = (InternalDBSchema)accessor.getStore().getDBSchema(); + IDBTable table = schema.getTable(oldName); + schema.unlock(); + + try + { + table.rename(newName); + } + finally + { + schema.lock(); + } + } + } + + /** + * @author Eike Stepper + */ + public class ColumnRenamer extends JDBCRenamer + { + private final IDBTable table; + + public ColumnRenamer(IDBConnection connection, IDBTable table) + { + super(connection, "Renaming columns of table " + table + ":"); + this.table = table; + + // Initialize the renamer with all existing column names. + for (IDBField field : table.getFields()) + { + addNames(field.getName(), null); + } + } + + @Override + @SuppressWarnings("deprecation") + protected String getSQL(String oldName, String newName) + { + IDBField field = table.getField(oldName); + String restoreName = field.getName(); + field.setName(newName); + + try + { + return dbAdapter.sqlRenameField(field, oldName); + } + finally + { + field.setName(restoreName); + } + } + + @Override + protected void doRename(String oldName, String newName, int count) + { + super.doRename(oldName, newName, count); + + InternalDBSchema schema = (InternalDBSchema)accessor.getStore().getDBSchema(); + IDBField field = table.getField(oldName); + schema.unlock(); + + try + { + field.rename(newName); + } + finally + { + schema.lock(); + } + } + } +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBBrowserPage.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBTablesPage.java index fe6b898f77..b0d38ef475 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBBrowserPage.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBTablesPage.java @@ -17,6 +17,7 @@ import org.eclipse.emf.cdo.spi.server.InternalRepository; import org.eclipse.net4j.db.DBException; import org.eclipse.net4j.db.DBUtil; import org.eclipse.net4j.db.IDBConnectionProvider; +import org.eclipse.net4j.db.ddl.IDBTable; import org.eclipse.net4j.util.factory.ProductCreationException; import java.io.PrintStream; @@ -31,11 +32,15 @@ import java.util.List; * @author Eike Stepper * @since 4.0 */ -public class DBBrowserPage extends AbstractPage +public class DBTablesPage extends AbstractPage { - public DBBrowserPage() + private static final String PARAM_TABLE = "table"; + + private static final String NAME = "tables"; + + public DBTablesPage() { - super("tables", "DB Tables"); + super(NAME, "DB Tables"); } public boolean canDisplay(InternalRepository repository) @@ -84,7 +89,7 @@ public class DBBrowserPage extends AbstractPage */ protected String showTables(CDOServerBrowser browser, PrintStream pout, Connection connection, String repo) { - String table = browser.getParam("table"); + String table = browser.getParam(PARAM_TABLE); boolean used = browser.isParam("used"); boolean schema = browser.isParam("schema"); @@ -126,7 +131,7 @@ public class DBBrowserPage extends AbstractPage } else { - pout.print(browser.href(label, getName(), "table", tableName, "order", null, "direction", null)); + pout.print(browser.href(label, getName(), PARAM_TABLE, tableName, "order", null, "direction", null)); } if (rowCount > 0) @@ -235,21 +240,32 @@ public class DBBrowserPage extends AbstractPage } } + public static String tableHRef(CDOServerBrowser browser, IDBTable table) + { + if (table == null) + { + return " "; + } + + String tableName = table.getName(); + return browser.href(tableName, NAME, PARAM_TABLE, tableName); + } + /** * @author Eike Stepper */ public static class Factory extends org.eclipse.net4j.util.factory.Factory { - public static final String TYPE = "db"; + public static final String TYPE = "dbtables"; public Factory() { super(PRODUCT_GROUP, TYPE); } - public DBBrowserPage create(String description) throws ProductCreationException + public DBTablesPage create(String description) throws ProductCreationException { - return new DBBrowserPage(); + return new DBTablesPage(); } } } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/IObjectTypeMapper.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/IObjectTypeMapper.java index 642ecdd06d..03791515dd 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/IObjectTypeMapper.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/IObjectTypeMapper.java @@ -37,6 +37,8 @@ public interface IObjectTypeMapper public boolean removeObjectType(IDBStoreAccessor accessor, CDOID id); + public int changeObjectType(IDBStoreAccessor accessor, EClass oldType, EClass newType); + /** * Return the maximum object id managed by this cache. * diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/MetaDataManager.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/MetaDataManager.java index 6dc45c79bd..b6f410f929 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/MetaDataManager.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/MetaDataManager.java @@ -38,6 +38,7 @@ import org.eclipse.net4j.db.IDBPreparedStatement; import org.eclipse.net4j.db.IDBPreparedStatement.ReuseProbability; import org.eclipse.net4j.db.IDBRowHandler; import org.eclipse.net4j.util.lifecycle.Lifecycle; +import org.eclipse.net4j.util.om.OMPlatform; import org.eclipse.net4j.util.om.monitor.Monitor; import org.eclipse.net4j.util.om.monitor.OMMonitor; import org.eclipse.net4j.util.om.monitor.OMMonitor.Async; @@ -65,9 +66,9 @@ import java.util.Map.Entry; */ public class MetaDataManager extends Lifecycle implements IMetaDataManager { - private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, MetaDataManager.class); + public static final boolean ZIP_PACKAGE_BYTES = OMPlatform.INSTANCE.isProperty("org.eclipse.emf.cdo.server.db.zipPackageBytes", true); - private static final boolean ZIP_PACKAGE_BYTES = true; + private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, MetaDataManager.class); private IDBStore store; @@ -123,7 +124,7 @@ public class MetaDataManager extends Lifecycle implements IMetaDataManager { String where = CDODBSchema.PACKAGE_UNITS_ID.getName() + "='" + packageUnit.getID() + "'"; //$NON-NLS-1$ //$NON-NLS-2$ Object[] values = DBUtil.select(connection, where, CDODBSchema.PACKAGE_UNITS_PACKAGE_DATA); - byte[] bytes = (byte[])values[0]; + byte[] bytes = ZIP_PACKAGE_BYTES ? (byte[])values[0] : ((String)values[0]).getBytes(); EPackage ePackage = createEPackage(packageUnit, bytes); return EMFUtil.getAllPackages(ePackage); } @@ -133,96 +134,101 @@ public class MetaDataManager extends Lifecycle implements IMetaDataManager return readPackageUnits(connection, CDOBranchPoint.UNSPECIFIED_DATE, CDOBranchPoint.UNSPECIFIED_DATE, new Monitor()); } - public final void writePackageUnits(Connection connection, InternalCDOPackageUnit[] packageUnits, OMMonitor monitor) + private Collection<InternalCDOPackageUnit> readPackageUnits(Connection connection, long fromCommitTime, long toCommitTime, OMMonitor monitor) { - try + final Map<String, InternalCDOPackageUnit> packageUnits = new HashMap<String, InternalCDOPackageUnit>(); + IDBRowHandler unitRowHandler = new IDBRowHandler() { - monitor.begin(2); - fillSystemTables((IDBConnection)connection, packageUnits, monitor.fork()); - } - finally + public boolean handle(int row, final Object... values) + { + int index = DBUtil.asInt(values[1]); + long timestamp = DBUtil.asLong(values[2]); + + InternalCDOPackageUnit packageUnit = createPackageUnit(); + packageUnit.setOriginalType(CDOPackageUnit.Type.values()[index]); + packageUnit.setTimeStamp(timestamp); + + packageUnits.put((String)values[0], packageUnit); + return true; + } + }; + + String where = null; + if (fromCommitTime != CDOBranchPoint.UNSPECIFIED_DATE) { - monitor.done(); + where = CDODBSchema.PACKAGE_UNITS_ID + "<>'" + CDOModelConstants.CORE_PACKAGE_URI + "' AND " + CDODBSchema.PACKAGE_UNITS_ID + "<>'" + + CDOModelConstants.RESOURCE_PACKAGE_URI + "' AND " + CDODBSchema.PACKAGE_UNITS_ID + "<>'" + CDOModelConstants.TYPES_PACKAGE_URI + "' AND " + + CDODBSchema.PACKAGE_UNITS_TIME_STAMP + " BETWEEN " + fromCommitTime + " AND " + toCommitTime; } - } - public void rawExport(Connection connection, CDODataOutput out, long fromCommitTime, long toCommitTime) throws IOException - { - // Export package units - String where = " WHERE p_u." + CDODBSchema.PACKAGE_UNITS_ID + "<>'" + CDOModelConstants.CORE_PACKAGE_URI + // - "' AND p_u." + CDODBSchema.PACKAGE_UNITS_ID + "<>'" + CDOModelConstants.RESOURCE_PACKAGE_URI + // - "' AND p_u." + CDODBSchema.PACKAGE_UNITS_ID + "<>'" + CDOModelConstants.TYPES_PACKAGE_URI + // - "' AND p_u." + CDODBSchema.PACKAGE_UNITS_TIME_STAMP + " BETWEEN " + fromCommitTime + " AND " + toCommitTime; - DBUtil.serializeTable(out, connection, CDODBSchema.PACKAGE_UNITS, "p_u", where); + DBUtil.select(connection, unitRowHandler, where, CDODBSchema.PACKAGE_UNITS_ID, CDODBSchema.PACKAGE_UNITS_ORIGINAL_TYPE, + CDODBSchema.PACKAGE_UNITS_TIME_STAMP); - // Export package infos - String join = ", " + CDODBSchema.PACKAGE_UNITS + " p_u" + where + " AND p_i." + CDODBSchema.PACKAGE_INFOS_UNIT + "=p_u." + CDODBSchema.PACKAGE_UNITS_ID; - DBUtil.serializeTable(out, connection, CDODBSchema.PACKAGE_INFOS, "p_i", join); - } + final Map<String, List<InternalCDOPackageInfo>> packageInfos = new HashMap<String, List<InternalCDOPackageInfo>>(); + IDBRowHandler infoRowHandler = new IDBRowHandler() + { + public boolean handle(int row, final Object... values) + { + InternalCDOPackageInfo packageInfo = createPackageInfo(); + packageInfo.setPackageURI((String)values[1]); + packageInfo.setParentURI((String)values[2]); - public Collection<InternalCDOPackageUnit> rawImport(Connection connection, CDODataInput in, long fromCommitTime, long toCommitTime, OMMonitor monitor) - throws IOException - { - monitor.begin(3); + String unit = (String)values[0]; + List<InternalCDOPackageInfo> list = packageInfos.get(unit); + if (list == null) + { + list = new ArrayList<InternalCDOPackageInfo>(); + packageInfos.put(unit, list); + } + + list.add(packageInfo); + return true; + } + }; + + monitor.begin(); + Async async = monitor.forkAsync(); try { - DBUtil.deserializeTable(in, connection, CDODBSchema.PACKAGE_UNITS, monitor.fork()); - DBUtil.deserializeTable(in, connection, CDODBSchema.PACKAGE_INFOS, monitor.fork()); - return readPackageUnits(connection, fromCommitTime, toCommitTime, monitor.fork()); + DBUtil.select(connection, infoRowHandler, CDODBSchema.PACKAGE_INFOS_UNIT, CDODBSchema.PACKAGE_INFOS_URI, CDODBSchema.PACKAGE_INFOS_PARENT); } finally { + async.stop(); monitor.done(); } - } - protected IDBStore getStore() - { - return store; - } - - @Override - protected void doBeforeActivate() throws Exception - { - checkState(store, "Store is not set"); //$NON-NLS-1$ - } - - @Override - protected void doDeactivate() throws Exception - { - clearMetaIDMappings(); - super.doDeactivate(); - } - - protected InternalCDOPackageInfo createPackageInfo() - { - return (InternalCDOPackageInfo)CDOModelUtil.createPackageInfo(); - } - - protected InternalCDOPackageUnit createPackageUnit() - { - return (InternalCDOPackageUnit)CDOModelUtil.createPackageUnit(); - } + for (Entry<String, InternalCDOPackageUnit> entry : packageUnits.entrySet()) + { + String id = entry.getKey(); + InternalCDOPackageUnit packageUnit = entry.getValue(); - private InternalCDOPackageRegistry getPackageRegistry() - { - return (InternalCDOPackageRegistry)store.getRepository().getPackageRegistry(); - } + List<InternalCDOPackageInfo> list = packageInfos.get(id); + InternalCDOPackageInfo[] array = list.toArray(new InternalCDOPackageInfo[list.size()]); + packageUnit.setPackageInfos(array); + } - private EPackage createEPackage(InternalCDOPackageUnit packageUnit, byte[] bytes) - { - ResourceSet resourceSet = EMFUtil.newEcoreResourceSet(getPackageRegistry()); - return EMFUtil.createEPackage(packageUnit.getID(), bytes, ZIP_PACKAGE_BYTES, resourceSet, false); + return packageUnits.values(); } - private byte[] getEPackageBytes(InternalCDOPackageUnit packageUnit) + public final void writePackageUnits(Connection connection, InternalCDOPackageUnit[] packageUnits, OMMonitor monitor) { - EPackage ePackage = packageUnit.getTopLevelPackageInfo().getEPackage(); - return EMFUtil.getEPackageBytes(ePackage, ZIP_PACKAGE_BYTES, getPackageRegistry()); + try + { + monitor.begin(packageUnits.length); + for (InternalCDOPackageUnit packageUnit : packageUnits) + { + writePackageUnit((IDBConnection)connection, packageUnit, monitor.fork()); + } + } + finally + { + monitor.done(); + } } - private void fillSystemTables(IDBConnection connection, InternalCDOPackageUnit packageUnit, OMMonitor monitor) + private void writePackageUnit(IDBConnection connection, InternalCDOPackageUnit packageUnit, OMMonitor monitor) { if (TRACER.isEnabled()) { @@ -230,7 +236,6 @@ public class MetaDataManager extends Lifecycle implements IMetaDataManager } InternalCDOPackageInfo[] packageInfos = packageUnit.getPackageInfos(); - Async async = null; monitor.begin(1 + packageInfos.length); try @@ -241,6 +246,7 @@ public class MetaDataManager extends Lifecycle implements IMetaDataManager DBUtil.trace(sql); IDBPreparedStatement stmt = connection.prepareStatement(sql, ReuseProbability.MEDIUM); + Async async = null; try { @@ -248,7 +254,15 @@ public class MetaDataManager extends Lifecycle implements IMetaDataManager stmt.setString(1, packageUnit.getID()); stmt.setInt(2, packageUnit.getOriginalType().ordinal()); stmt.setLong(3, packageUnit.getTimeStamp()); - stmt.setBytes(4, getEPackageBytes(packageUnit)); + + if (ZIP_PACKAGE_BYTES) + { + stmt.setBytes(4, getEPackageBytes(packageUnit)); + } + else + { + stmt.setString(4, new String(getEPackageBytes(packageUnit))); + } if (stmt.execute()) { @@ -275,7 +289,7 @@ public class MetaDataManager extends Lifecycle implements IMetaDataManager for (InternalCDOPackageInfo packageInfo : packageInfos) { - fillSystemTables(connection, packageInfo, monitor); // Don't fork monitor + writePackageInfo(connection, packageInfo, monitor); // Don't fork monitor } } finally @@ -284,23 +298,7 @@ public class MetaDataManager extends Lifecycle implements IMetaDataManager } } - private void fillSystemTables(IDBConnection connection, InternalCDOPackageUnit[] packageUnits, OMMonitor monitor) - { - try - { - monitor.begin(packageUnits.length); - for (InternalCDOPackageUnit packageUnit : packageUnits) - { - fillSystemTables(connection, packageUnit, monitor.fork()); - } - } - finally - { - monitor.done(); - } - } - - private void fillSystemTables(IDBConnection connection, InternalCDOPackageInfo packageInfo, OMMonitor monitor) + private void writePackageInfo(IDBConnection connection, InternalCDOPackageInfo packageInfo, OMMonitor monitor) { if (TRACER.isEnabled()) { @@ -348,82 +346,194 @@ public class MetaDataManager extends Lifecycle implements IMetaDataManager } } - private Collection<InternalCDOPackageUnit> readPackageUnits(Connection connection, long fromCommitTime, long toCommitTime, OMMonitor monitor) + public final void deletePackageUnits(Connection connection, InternalCDOPackageUnit[] packageUnits, OMMonitor monitor) { - final Map<String, InternalCDOPackageUnit> packageUnits = new HashMap<String, InternalCDOPackageUnit>(); - IDBRowHandler unitRowHandler = new IDBRowHandler() + try { - public boolean handle(int row, final Object... values) + monitor.begin(packageUnits.length); + for (InternalCDOPackageUnit packageUnit : packageUnits) { - int index = DBUtil.asInt(values[1]); - long timestamp = DBUtil.asLong(values[2]); - - InternalCDOPackageUnit packageUnit = createPackageUnit(); - packageUnit.setOriginalType(CDOPackageUnit.Type.values()[index]); - packageUnit.setTimeStamp(timestamp); - - packageUnits.put((String)values[0], packageUnit); - return true; + deletePackageUnit((IDBConnection)connection, packageUnit, monitor.fork()); } - }; + } + finally + { + monitor.done(); + } + } - String where = null; - if (fromCommitTime != CDOBranchPoint.UNSPECIFIED_DATE) + private void deletePackageUnit(IDBConnection connection, InternalCDOPackageUnit packageUnit, OMMonitor monitor) + { + if (TRACER.isEnabled()) { - where = CDODBSchema.PACKAGE_UNITS_ID + "<>'" + CDOModelConstants.CORE_PACKAGE_URI + "' AND " + CDODBSchema.PACKAGE_UNITS_ID + "<>'" - + CDOModelConstants.RESOURCE_PACKAGE_URI + "' AND " + CDODBSchema.PACKAGE_UNITS_ID + "<>'" + CDOModelConstants.TYPES_PACKAGE_URI + "' AND " - + CDODBSchema.PACKAGE_UNITS_TIME_STAMP + " BETWEEN " + fromCommitTime + " AND " + toCommitTime; + TRACER.format("Deleting package unit: {0}", packageUnit); //$NON-NLS-1$ } - DBUtil.select(connection, unitRowHandler, where, CDODBSchema.PACKAGE_UNITS_ID, CDODBSchema.PACKAGE_UNITS_ORIGINAL_TYPE, - CDODBSchema.PACKAGE_UNITS_TIME_STAMP); + InternalCDOPackageInfo[] packageInfos = packageUnit.getPackageInfos(); + monitor.begin(1 + packageInfos.length); - final Map<String, List<InternalCDOPackageInfo>> packageInfos = new HashMap<String, List<InternalCDOPackageInfo>>(); - IDBRowHandler infoRowHandler = new IDBRowHandler() + try { - public boolean handle(int row, final Object... values) + String sql = "DELETE FROM " + CDODBSchema.PACKAGE_UNITS + " WHERE " + CDODBSchema.PACKAGE_UNITS_ID + "=?"; + DBUtil.trace(sql); + + IDBPreparedStatement stmt = connection.prepareStatement(sql, ReuseProbability.LOW); + Async async = null; + + try { - InternalCDOPackageInfo packageInfo = createPackageInfo(); - packageInfo.setPackageURI((String)values[1]); - packageInfo.setParentURI((String)values[2]); + async = monitor.forkAsync(); + stmt.setString(1, packageUnit.getID()); - String unit = (String)values[0]; - List<InternalCDOPackageInfo> list = packageInfos.get(unit); - if (list == null) + if (stmt.execute()) { - list = new ArrayList<InternalCDOPackageInfo>(); - packageInfos.put(unit, list); + throw new DBException("No result set expected"); //$NON-NLS-1$ } - list.add(packageInfo); - return true; + if (stmt.getUpdateCount() == 0) + { + throw new DBException("No row deleted from table " + CDODBSchema.PACKAGE_UNITS); //$NON-NLS-1$ + } + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + DBUtil.close(stmt); + if (async != null) + { + async.stop(); + } } - }; - monitor.begin(); + for (InternalCDOPackageInfo packageInfo : packageInfos) + { + deletePackageInfo(connection, packageInfo, monitor); // Don't fork monitor + } + } + finally + { + monitor.done(); + } + } + + private void deletePackageInfo(IDBConnection connection, InternalCDOPackageInfo packageInfo, OMMonitor monitor) + { + if (TRACER.isEnabled()) + { + TRACER.format("Deleting package info: {0}", packageInfo); //$NON-NLS-1$ + } + + String sql = "DELETE FROM " + CDODBSchema.PACKAGE_INFOS + " WHERE " + CDODBSchema.PACKAGE_INFOS_URI + "=?"; + DBUtil.trace(sql); + + IDBPreparedStatement stmt = connection.prepareStatement(sql, ReuseProbability.LOW); Async async = monitor.forkAsync(); try { - DBUtil.select(connection, infoRowHandler, CDODBSchema.PACKAGE_INFOS_UNIT, CDODBSchema.PACKAGE_INFOS_URI, CDODBSchema.PACKAGE_INFOS_PARENT); + stmt.setString(1, packageInfo.getPackageURI()); + + if (stmt.execute()) + { + throw new DBException("No result set expected"); //$NON-NLS-1$ + } + + if (stmt.getUpdateCount() == 0) + { + throw new DBException("No row deleted from table " + CDODBSchema.PACKAGE_INFOS); //$NON-NLS-1$ + } + } + catch (SQLException ex) + { + throw new DBException(ex); } finally { - async.stop(); - monitor.done(); + DBUtil.close(stmt); + if (async != null) + { + async.stop(); + } } + } - for (Entry<String, InternalCDOPackageUnit> entry : packageUnits.entrySet()) - { - String id = entry.getKey(); - InternalCDOPackageUnit packageUnit = entry.getValue(); + public void rawExport(Connection connection, CDODataOutput out, long fromCommitTime, long toCommitTime) throws IOException + { + // Export package units + String where = " WHERE p_u." + CDODBSchema.PACKAGE_UNITS_ID + "<>'" + CDOModelConstants.CORE_PACKAGE_URI + // + "' AND p_u." + CDODBSchema.PACKAGE_UNITS_ID + "<>'" + CDOModelConstants.RESOURCE_PACKAGE_URI + // + "' AND p_u." + CDODBSchema.PACKAGE_UNITS_ID + "<>'" + CDOModelConstants.TYPES_PACKAGE_URI + // + "' AND p_u." + CDODBSchema.PACKAGE_UNITS_TIME_STAMP + " BETWEEN " + fromCommitTime + " AND " + toCommitTime; + DBUtil.serializeTable(out, connection, CDODBSchema.PACKAGE_UNITS, "p_u", where); - List<InternalCDOPackageInfo> list = packageInfos.get(id); - InternalCDOPackageInfo[] array = list.toArray(new InternalCDOPackageInfo[list.size()]); - packageUnit.setPackageInfos(array); + // Export package infos + String join = ", " + CDODBSchema.PACKAGE_UNITS + " p_u" + where + " AND p_i." + CDODBSchema.PACKAGE_INFOS_UNIT + "=p_u." + CDODBSchema.PACKAGE_UNITS_ID; + DBUtil.serializeTable(out, connection, CDODBSchema.PACKAGE_INFOS, "p_i", join); + } + + public Collection<InternalCDOPackageUnit> rawImport(Connection connection, CDODataInput in, long fromCommitTime, long toCommitTime, OMMonitor monitor) + throws IOException + { + monitor.begin(3); + + try + { + DBUtil.deserializeTable(in, connection, CDODBSchema.PACKAGE_UNITS, monitor.fork()); + DBUtil.deserializeTable(in, connection, CDODBSchema.PACKAGE_INFOS, monitor.fork()); + return readPackageUnits(connection, fromCommitTime, toCommitTime, monitor.fork()); + } + finally + { + monitor.done(); } + } - return packageUnits.values(); + protected IDBStore getStore() + { + return store; + } + + @Override + protected void doBeforeActivate() throws Exception + { + checkState(store, "Store is not set"); //$NON-NLS-1$ + } + + @Override + protected void doDeactivate() throws Exception + { + clearMetaIDMappings(); + super.doDeactivate(); + } + + protected InternalCDOPackageInfo createPackageInfo() + { + return (InternalCDOPackageInfo)CDOModelUtil.createPackageInfo(); + } + + protected InternalCDOPackageUnit createPackageUnit() + { + return (InternalCDOPackageUnit)CDOModelUtil.createPackageUnit(); + } + + private InternalCDOPackageRegistry getPackageRegistry() + { + return (InternalCDOPackageRegistry)store.getRepository().getPackageRegistry(); + } + + private EPackage createEPackage(InternalCDOPackageUnit packageUnit, byte[] bytes) + { + ResourceSet resourceSet = EMFUtil.newEcoreResourceSet(getPackageRegistry()); + return EMFUtil.createEPackage(packageUnit.getID(), bytes, ZIP_PACKAGE_BYTES, resourceSet, false); + } + + private byte[] getEPackageBytes(InternalCDOPackageUnit packageUnit) + { + EPackage ePackage = packageUnit.getTopLevelPackageInfo().getEPackage(); + return EMFUtil.getEPackageBytes(ePackage, ZIP_PACKAGE_BYTES, getPackageRegistry()); } private void cacheMetaIDMapping(EModelElement modelElement, CDOID metaID) diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java index d7fae2b37c..d629db7579 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java @@ -17,20 +17,19 @@ package org.eclipse.emf.cdo.server.internal.db.mapping; import org.eclipse.emf.cdo.common.branch.CDOBranch; -import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; import org.eclipse.emf.cdo.common.id.CDOID; -import org.eclipse.emf.cdo.common.id.CDOIDUtil; import org.eclipse.emf.cdo.common.model.CDOFeatureType; -import org.eclipse.emf.cdo.common.model.EMFUtil; +import org.eclipse.emf.cdo.common.model.CDOPackageInfo; +import org.eclipse.emf.cdo.common.model.CDOPackageUnit; import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; -import org.eclipse.emf.cdo.server.IStoreAccessor.CommitContext; -import org.eclipse.emf.cdo.server.StoreThreadLocal; 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.IClassMapping; import org.eclipse.emf.cdo.server.db.mapping.IListMapping; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; +import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy3; +import org.eclipse.emf.cdo.server.db.mapping.INamingStrategy; import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping; import org.eclipse.emf.cdo.server.internal.db.DBAnnotation; import org.eclipse.emf.cdo.server.internal.db.ObjectIDIterator; @@ -45,8 +44,6 @@ import org.eclipse.net4j.db.DBException; import org.eclipse.net4j.db.DBUtil; import org.eclipse.net4j.db.ddl.IDBSchema; import org.eclipse.net4j.db.ddl.IDBTable; -import org.eclipse.net4j.util.ImplementationError; -import org.eclipse.net4j.util.StringUtil; import org.eclipse.net4j.util.collection.CloseableIterator; import org.eclipse.net4j.util.lifecycle.Lifecycle; import org.eclipse.net4j.util.lifecycle.LifecycleUtil; @@ -55,20 +52,19 @@ import org.eclipse.net4j.util.om.monitor.OMMonitor.Async; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; -import org.eclipse.emf.ecore.EModelElement; import org.eclipse.emf.ecore.ENamedElement; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.util.FeatureMapUtil; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -81,32 +77,16 @@ import java.util.concurrent.ConcurrentMap; * @author Eike Stepper * @since 2.0 */ -public abstract class AbstractMappingStrategy extends Lifecycle implements IMappingStrategy +public abstract class AbstractMappingStrategy extends Lifecycle implements IMappingStrategy3 { - // --------- database name generation strings -------------- - protected static final String NAME_SEPARATOR = "_"; //$NON-NLS-1$ - - protected static final String TYPE_PREFIX_FEATURE = "F"; //$NON-NLS-1$ - - protected static final String TYPE_PREFIX_CLASS = "C"; //$NON-NLS-1$ - - protected static final String TYPE_PREFIX_PACKAGE = "P"; //$NON-NLS-1$ - - protected static final String GENERAL_PREFIX = "X"; //$NON-NLS-1$ - - protected static final String GENERAL_SUFFIX = "0"; //$NON-NLS-1$ - - /** - * Prefix for unsettable feature helper columns - */ - protected static final String CDO_SET_PREFIX = "cdo_set_"; //$NON-NLS-1$ - - protected static final String FEATURE_TABLE_SUFFIX = "_list"; //$NON-NLS-1$ + private static final ThreadLocal<Boolean> SKIP_MAPPING_INITIALIZATION = new ThreadLocal<Boolean>(); private IDBStore store; private Map<String, String> properties; + private INamingStrategy namingStrategy; + private ConcurrentMap<EClass, IClassMapping> classMappings; private boolean allClassMappingsCreated; @@ -135,34 +115,15 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp this.properties = properties; } - public int getMaxTableNameLength() + public INamingStrategy getNamingStrategy() { - String value = getProperties().get(Props.MAX_TABLE_NAME_LENGTH); - return value == null ? store.getDBAdapter().getMaxTableNameLength() : Integer.valueOf(value); + return namingStrategy; } - public int getMaxFieldNameLength() + public void setNamingStrategy(INamingStrategy namingStrategy) { - String value = getProperties().get(Props.MAX_FIELD_NAME_LENGTH); - return value == null ? store.getDBAdapter().getMaxFieldNameLength() : Integer.valueOf(value); - } - - public boolean isQualifiedNames() - { - String value = getProperties().get(Props.QUALIFIED_NAMES); - return value == null ? false : Boolean.valueOf(value); - } - - public boolean isForceNamesWithID() - { - String value = getProperties().get(Props.FORCE_NAMES_WITH_ID); - return value == null ? false : Boolean.valueOf(value); - } - - public String getTableNamePrefix() - { - String value = getProperties().get(Props.TABLE_NAME_PREFIX); - return StringUtil.safe(value); + checkInactive(); + this.namingStrategy = namingStrategy; } public Set<CDOFeatureType> getForceIndexes() @@ -297,167 +258,24 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp protected abstract Collection<EClass> getClassesWithObjectInfo(); - // -- database name demangling methods --------------------------------- - - private String getTableNamePrefix(EModelElement element) - { - String prefix = StringUtil.safe(DBAnnotation.TABLE_NAME_PREFIX.getValue(element)); - if (prefix.length() != 0 && !prefix.endsWith(NAME_SEPARATOR)) - { - prefix += NAME_SEPARATOR; - } - - EObject eContainer = element.eContainer(); - if (eContainer instanceof EModelElement) - { - EModelElement parent = (EModelElement)eContainer; - prefix = getTableNamePrefix(parent) + prefix; - } - - return prefix; - } - public String getTableName(ENamedElement element) { - String name = null; - String typePrefix = null; - - if (element instanceof EClass) - { - typePrefix = TYPE_PREFIX_CLASS; - name = DBAnnotation.TABLE_NAME.getValue(element); - if (name == null) - { - name = isQualifiedNames() ? EMFUtil.getQualifiedName((EClass)element, NAME_SEPARATOR) : element.getName(); - } - } - else if (element instanceof EPackage) - { - typePrefix = TYPE_PREFIX_PACKAGE; - name = DBAnnotation.TABLE_NAME.getValue(element); - if (name == null) - { - name = isQualifiedNames() ? EMFUtil.getQualifiedName((EPackage)element, NAME_SEPARATOR) : element.getName(); - } - } - else - { - throw new ImplementationError("Unknown element: " + element); //$NON-NLS-1$ - } - - String prefix = getTableNamePrefix(); - if (prefix.length() != 0 && !prefix.endsWith(NAME_SEPARATOR)) - { - prefix += NAME_SEPARATOR; - } - - prefix += getTableNamePrefix(element); - - String suffix = typePrefix + getUniqueID(element); - int maxTableNameLength = getMaxTableNameLength(); - - return getName(prefix + name, suffix, maxTableNameLength); + return namingStrategy.getTableName(element); } - public String getTableName(EClass eClass, EStructuralFeature feature) + public String getTableName(EClass containingClass, EStructuralFeature feature) { - String name = DBAnnotation.TABLE_NAME.getValue(eClass); - if (name == null) - { - name = isQualifiedNames() ? EMFUtil.getQualifiedName(eClass, NAME_SEPARATOR) : eClass.getName(); - } - - name += NAME_SEPARATOR; - name += feature.getName(); - name += FEATURE_TABLE_SUFFIX; - - String prefix = getTableNamePrefix(); - if (prefix.length() != 0 && !prefix.endsWith(NAME_SEPARATOR)) - { - prefix += NAME_SEPARATOR; - } - - prefix += getTableNamePrefix(feature); - - String suffix = TYPE_PREFIX_FEATURE + getUniqueID(feature); - int maxTableNameLength = getMaxTableNameLength(); - - return getName(prefix + name, suffix, maxTableNameLength); + return namingStrategy.getTableName(containingClass, feature); } public String getFieldName(EStructuralFeature feature) { - String name = DBAnnotation.COLUMN_NAME.getValue(feature); - if (name == null) - { - name = getName(feature.getName(), TYPE_PREFIX_FEATURE + getUniqueID(feature), getMaxFieldNameLength()); - } - - return name; + return namingStrategy.getFieldName(feature); } public String getUnsettableFieldName(EStructuralFeature feature) { - String name = DBAnnotation.COLUMN_NAME.getValue(feature); - if (name != null) - { - return CDO_SET_PREFIX + name; - } - - return getName(CDO_SET_PREFIX + feature.getName(), TYPE_PREFIX_FEATURE + getUniqueID(feature), getMaxFieldNameLength()); - } - - private String getName(String name, String suffix, int maxLength) - { - if (!store.getDBAdapter().isValidFirstChar(name.charAt(0))) - { - name = GENERAL_PREFIX + name; - } - - boolean forceNamesWithID = isForceNamesWithID(); - if (!forceNamesWithID && store.getDBAdapter().isReservedWord(name)) - { - name = name + GENERAL_SUFFIX; - } - - if (name.length() > maxLength || forceNamesWithID) - { - suffix = NAME_SEPARATOR + suffix.replace('-', 'S'); - int length = Math.min(name.length(), maxLength - suffix.length()); - if (length < 0) - { - // Most likely CDOIDs are client side-assigned, i.e., meta IDs are extrefs. See getUniqueID() - throw new IllegalStateException("Suffix is too long: " + suffix); - } - - name = name.substring(0, length) + suffix; - } - - return name; - } - - private String getUniqueID(ENamedElement element) - { - long timeStamp; - CommitContext commitContext = StoreThreadLocal.getCommitContext(); - if (commitContext != null) - { - timeStamp = commitContext.getBranchPoint().getTimeStamp(); - } - else - { - // This happens outside a commit, i.e. at system init time. - // Ensure that resulting ext refs are not replicated! - timeStamp = CDOBranchPoint.INVALID_DATE; - // timeStamp = getStore().getRepository().getTimeStamp(); - } - - IMetaDataManager metaDataManager = getMetaDataManager(); - CDOID result = metaDataManager.getMetaID(element, timeStamp); - - StringBuilder builder = new StringBuilder(); - CDOIDUtil.write(builder, result); - return builder.toString(); + return namingStrategy.getUnsettableFieldName(feature); } public void createMapping(Connection connection, InternalCDOPackageUnit[] packageUnits, OMMonitor monitor) @@ -471,7 +289,11 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp { async = monitor.forkAsync(); - mapPackageUnits(packageUnits, connection, false); + for (EClass eClass : getMappedClasses(packageUnits)) + { + IClassMapping classMapping = createClassMapping(eClass); + addClassMapping(classMapping); + } } } finally @@ -487,88 +309,73 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp public void removeMapping(Connection connection, InternalCDOPackageUnit[] packageUnits) { - mapPackageUnits(packageUnits, connection, true); - } - - protected Set<IClassMapping> mapPackageUnits(InternalCDOPackageUnit[] packageUnits, Connection connection, boolean unmap) - { - Set<IClassMapping> classMappings = new HashSet<IClassMapping>(); - - if (packageUnits != null && packageUnits.length != 0) + for (EClass eClass : getMappedClasses(packageUnits)) { - for (InternalCDOPackageUnit packageUnit : packageUnits) - { - InternalCDOPackageInfo[] packageInfos = packageUnit.getPackageInfos(); - mapPackageInfos(packageInfos, connection, unmap, classMappings); - } + removeClassMapping(eClass); } - - return classMappings; } - private void mapPackageInfos(InternalCDOPackageInfo[] packageInfos, Connection connection, boolean unmap, Set<IClassMapping> classMappings) + public boolean isMapped(EClass eClass) { - for (InternalCDOPackageInfo packageInfo : packageInfos) - { - EPackage ePackage = packageInfo.getEPackage(); - EClass[] persistentClasses = EMFUtil.getPersistentClasses(ePackage); - mapClasses(connection, unmap, persistentClasses, classMappings); - } + String mappingAnnotation = DBAnnotation.TABLE_MAPPING.getValue(eClass); + return mappingAnnotation == null || mappingAnnotation.equalsIgnoreCase(DBAnnotation.TABLE_MAPPING_NONE); } - private void mapClasses(Connection connection, boolean unmap, EClass[] eClasses, Set<IClassMapping> classMappings) + public List<EClass> getMappedClasses(CDOPackageUnit[] packageUnits) { - for (EClass eClass : eClasses) + List<EClass> result = new ArrayList<EClass>(); + + if (packageUnits != null && packageUnits.length != 0) { - if (!(eClass.isInterface() || eClass.isAbstract())) + for (CDOPackageUnit packageUnit : packageUnits) { - String mappingAnnotation = DBAnnotation.TABLE_MAPPING.getValue(eClass); - - // TODO Maybe we should explicitly report unknown values of the annotation - if (mappingAnnotation != null && mappingAnnotation.equalsIgnoreCase(DBAnnotation.TABLE_MAPPING_NONE)) + for (CDOPackageInfo packageInfo : packageUnit.getPackageInfos()) { - continue; - } - - IClassMapping classMapping = unmap ? removeClassMapping(eClass) : createClassMapping(eClass); - if (classMapping != null) - { - classMappings.add(classMapping); + for (EClassifier classifier : packageInfo.getEPackage().getEClassifiers()) + { + if (classifier instanceof EClass) + { + EClass eClass = (EClass)classifier; + if (isMapped(eClass)) + { + result.add(eClass); + } + } + } } } } + + return result; } - private IClassMapping createClassMapping(EClass eClass) + private void addClassMapping(IClassMapping classMapping) { - IClassMapping classMapping = doCreateClassMapping(eClass); if (classMapping != null) { + EClass eClass = classMapping.getEClass(); classMappings.put(eClass, classMapping); } - - return classMapping; } private IClassMapping removeClassMapping(EClass eClass) { - IClassMapping classMapping = classMappings.get(eClass); + IClassMapping classMapping = classMappings.remove(eClass); if (classMapping != null) { IDBSchema schema = getStore().getDBSchema(); for (IDBTable table : classMapping.getDBTables()) { - schema.removeTable(table.getName()); + if (table != null) + { + schema.removeTable(table.getName()); + } } - - classMappings.remove(eClass); } return classMapping; } - protected abstract IClassMapping doCreateClassMapping(EClass eClass); - public final IClassMapping getClassMapping(EClass eClass) { if (!isMapped(eClass)) @@ -591,6 +398,7 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp if (result == null) { result = createClassMapping(eClass); + addClassMapping(result); } } } @@ -605,18 +413,13 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp public final Map<EClass, IClassMapping> getClassMappings(boolean createOnDemand) { - return doGetClassMappings(createOnDemand); - } - - public final Map<EClass, IClassMapping> doGetClassMappings(boolean createOnDemand) - { if (createOnDemand) { synchronized (classMappings) { if (!allClassMappingsCreated) { - createAllClassMappings(); + ensureAllClassMappings(); allClassMappingsCreated = true; } } @@ -625,7 +428,7 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp return classMappings; } - private void createAllClassMappings() + private void ensureAllClassMappings() { InternalRepository repository = (InternalRepository)getStore().getRepository(); InternalCDOPackageRegistry packageRegistry = repository.getPackageRegistry(false); @@ -645,7 +448,14 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp } } - protected abstract boolean isMapped(EClass eClass); + public void clearClassMappings() + { + synchronized (classMappings) + { + classMappings.clear(); + allClassMappingsCreated = false; + } + } public ITypeMapping createValueMapping(EStructuralFeature feature) { @@ -679,8 +489,23 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp public abstract IListMapping doCreateFeatureMapMapping(EClass containingClass, EStructuralFeature feature); @Override + protected void doActivate() throws Exception + { + super.doActivate(); + + if (namingStrategy == null) + { + namingStrategy = new DefaultNamingStrategy(); + } + + namingStrategy.initialize(this); + LifecycleUtil.activate(namingStrategy); + } + + @Override protected void doDeactivate() throws Exception { + LifecycleUtil.deactivate(namingStrategy); deactivateClassMappings(); super.doDeactivate(); } @@ -717,4 +542,28 @@ public abstract class AbstractMappingStrategy extends Lifecycle implements IMapp String value = mappingStrategy.getProperties().get(Props.EAGER_TABLE_CREATION); return value == null ? false : Boolean.valueOf(value); } + + public static boolean isSkipMappingInitialization() + { + return SKIP_MAPPING_INITIALIZATION.get() == Boolean.TRUE; + } + + public static boolean setSkipMappingInitialization(boolean value) + { + boolean oldValue = isSkipMappingInitialization(); + + if (value != oldValue) + { + if (value) + { + SKIP_MAPPING_INITIALIZATION.set(Boolean.TRUE); + } + else + { + SKIP_MAPPING_INITIALIZATION.remove(); + } + } + + return oldValue; + } } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/DefaultNamingStrategy.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/DefaultNamingStrategy.java new file mode 100644 index 0000000000..90002954c5 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/DefaultNamingStrategy.java @@ -0,0 +1,293 @@ +/* + * 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.internal.db.mapping; + +import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDUtil; +import org.eclipse.emf.cdo.common.model.EMFUtil; +import org.eclipse.emf.cdo.server.IStoreAccessor.CommitContext; +import org.eclipse.emf.cdo.server.StoreThreadLocal; +import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; +import org.eclipse.emf.cdo.server.db.mapping.INamingStrategy; +import org.eclipse.emf.cdo.server.internal.db.DBAnnotation; + +import org.eclipse.net4j.util.StringUtil; +import org.eclipse.net4j.util.factory.ProductCreationException; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EModelElement; +import org.eclipse.emf.ecore.ENamedElement; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EStructuralFeature; + +import java.util.Map; + +/** + * @author Eike Stepper + */ +public class DefaultNamingStrategy implements INamingStrategy +{ + public static final String NAME_SEPARATOR = "_"; //$NON-NLS-1$ + + public static final String TYPE_PREFIX_FEATURE = "F"; //$NON-NLS-1$ + + public static final String TYPE_PREFIX_CLASS = "C"; //$NON-NLS-1$ + + public static final String TYPE_PREFIX_PACKAGE = "P"; //$NON-NLS-1$ + + public static final String GENERAL_PREFIX = "X"; //$NON-NLS-1$ + + public static final String GENERAL_SUFFIX = "0"; //$NON-NLS-1$ + + /** + * Prefix for unsettable feature helper columns. + */ + public static final String CDO_SET_PREFIX = "cdo_set_"; //$NON-NLS-1$ + + public static final String FEATURE_TABLE_SUFFIX = "_list"; //$NON-NLS-1$ + + private IMappingStrategy mappingStrategy; + + public DefaultNamingStrategy() + { + } + + public void initialize(IMappingStrategy mappingStrategy) + { + this.mappingStrategy = mappingStrategy; + } + + public String getTableName(ENamedElement element) + { + String name = null; + String typePrefix = null; + + if (element instanceof EClass) + { + typePrefix = TYPE_PREFIX_CLASS; + name = DBAnnotation.TABLE_NAME.getValue(element); + if (name == null) + { + name = isQualifiedNames() ? EMFUtil.getQualifiedName((EClass)element, NAME_SEPARATOR) : element.getName(); + } + } + else if (element instanceof EPackage) + { + typePrefix = TYPE_PREFIX_PACKAGE; + name = DBAnnotation.TABLE_NAME.getValue(element); + if (name == null) + { + name = isQualifiedNames() ? EMFUtil.getQualifiedName((EPackage)element, NAME_SEPARATOR) : element.getName(); + } + } + else + { + throw new IllegalArgumentException("Unknown element: " + element); //$NON-NLS-1$ + } + + String prefix = getTableNamePrefix(); + if (prefix.length() != 0 && !prefix.endsWith(NAME_SEPARATOR)) + { + prefix += NAME_SEPARATOR; + } + + prefix += getTableNamePrefix(element); + + String suffix = typePrefix + getUniqueID(element); + int maxTableNameLength = getMaxTableNameLength(); + + return getName(prefix + name, suffix, maxTableNameLength); + } + + public String getTableName(EClass eClass, EStructuralFeature feature) + { + String name = DBAnnotation.TABLE_NAME.getValue(eClass); + if (name == null) + { + name = isQualifiedNames() ? EMFUtil.getQualifiedName(eClass, NAME_SEPARATOR) : eClass.getName(); + } + + name += NAME_SEPARATOR; + name += feature.getName(); + name += FEATURE_TABLE_SUFFIX; + + String prefix = getTableNamePrefix(); + if (prefix.length() != 0 && !prefix.endsWith(NAME_SEPARATOR)) + { + prefix += NAME_SEPARATOR; + } + + prefix += getTableNamePrefix(feature); + + String suffix = TYPE_PREFIX_FEATURE + getUniqueID(feature); + int maxTableNameLength = getMaxTableNameLength(); + + return getName(prefix + name, suffix, maxTableNameLength); + } + + public String getFieldName(EStructuralFeature feature) + { + String name = DBAnnotation.COLUMN_NAME.getValue(feature); + if (name == null) + { + name = getName(feature.getName(), TYPE_PREFIX_FEATURE + getUniqueID(feature), getMaxFieldNameLength()); + } + + return name; + } + + public String getUnsettableFieldName(EStructuralFeature feature) + { + String name = DBAnnotation.COLUMN_NAME.getValue(feature); + if (name != null) + { + return CDO_SET_PREFIX + name; + } + + return getName(CDO_SET_PREFIX + feature.getName(), TYPE_PREFIX_FEATURE + getUniqueID(feature), getMaxFieldNameLength()); + } + + protected int getMaxTableNameLength() + { + String value = mappingStrategy.getProperties().get(IMappingStrategy.Props.MAX_TABLE_NAME_LENGTH); + return value == null ? mappingStrategy.getStore().getDBAdapter().getMaxTableNameLength() : Integer.valueOf(value); + } + + protected int getMaxFieldNameLength() + { + String value = mappingStrategy.getProperties().get(IMappingStrategy.Props.MAX_FIELD_NAME_LENGTH); + return value == null ? mappingStrategy.getStore().getDBAdapter().getMaxFieldNameLength() : Integer.valueOf(value); + } + + protected boolean isQualifiedNames() + { + String value = mappingStrategy.getProperties().get(IMappingStrategy.Props.QUALIFIED_NAMES); + return value == null ? false : Boolean.valueOf(value); + } + + protected boolean isForceNamesWithID() + { + String value = mappingStrategy.getProperties().get(IMappingStrategy.Props.FORCE_NAMES_WITH_ID); + return value == null ? false : Boolean.valueOf(value); + } + + protected String getTableNamePrefix() + { + String value = mappingStrategy.getProperties().get(IMappingStrategy.Props.TABLE_NAME_PREFIX); + return StringUtil.safe(value); + } + + protected String getTableNamePrefix(EModelElement element) + { + String prefix = StringUtil.safe(DBAnnotation.TABLE_NAME_PREFIX.getValue(element)); + if (prefix.length() != 0 && !prefix.endsWith(NAME_SEPARATOR)) + { + prefix += NAME_SEPARATOR; + } + + EObject eContainer = element.eContainer(); + if (eContainer instanceof EModelElement) + { + EModelElement parent = (EModelElement)eContainer; + prefix = getTableNamePrefix(parent) + prefix; + } + + return prefix; + } + + protected String getName(String name, String suffix, int maxLength) + { + if (!isValidFirstChar(name)) + { + name = GENERAL_PREFIX + name; + } + + boolean forceNamesWithID = isForceNamesWithID(); + if (!forceNamesWithID && isReservedWord(name)) + { + name = name + GENERAL_SUFFIX; + } + + if (name.length() > maxLength || forceNamesWithID) + { + suffix = NAME_SEPARATOR + suffix.replace('-', 'S'); + int length = Math.min(name.length(), maxLength - suffix.length()); + if (length < 0) + { + // Most likely CDOIDs are client side-assigned, i.e., meta IDs are extrefs. See getUniqueID() + throw new IllegalStateException("Suffix is too long: " + suffix); + } + + name = name.substring(0, length) + suffix; + } + + return name; + } + + protected String getUniqueID(ENamedElement element) + { + long timeStamp; + CommitContext commitContext = StoreThreadLocal.getCommitContext(); + if (commitContext != null) + { + timeStamp = commitContext.getBranchPoint().getTimeStamp(); + } + else + { + // This happens outside a commit, i.e. at system init time. + // Ensure that resulting ext refs are not replicated! + timeStamp = CDOBranchPoint.INVALID_DATE; + // timeStamp = getStore().getRepository().getTimeStamp(); + } + + CDOID result = getMetaID(element, timeStamp); + + StringBuilder builder = new StringBuilder(); + CDOIDUtil.write(builder, result); + return builder.toString(); + } + + protected boolean isValidFirstChar(String name) + { + return mappingStrategy.getStore().getDBAdapter().isValidFirstChar(name.charAt(0)); + } + + protected boolean isReservedWord(String name) + { + return mappingStrategy.getStore().getDBAdapter().isReservedWord(name); + } + + protected CDOID getMetaID(ENamedElement element, long timeStamp) + { + return mappingStrategy.getStore().getMetaDataManager().getMetaID(element, timeStamp); + } + + /** + * @author Eike Stepper + */ + public static final class Factory extends INamingStrategy.Factory + { + private static final String TYPE = "default"; + + public Factory() + { + super(TYPE); + } + + @Override + public INamingStrategy create(Map<String, String> properties) throws ProductCreationException + { + return new DefaultNamingStrategy(); + } + } +} 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 3ef1687ec1..7cf19c5a30 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 @@ -27,7 +27,7 @@ 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.IClassMapping; -import org.eclipse.emf.cdo.server.db.mapping.IListMapping3; +import org.eclipse.emf.cdo.server.db.mapping.IListMapping4; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping; import org.eclipse.emf.cdo.server.internal.db.DBIndexAnnotation; @@ -36,6 +36,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.IDBTable; import org.eclipse.net4j.util.om.trace.ContextTracer; import org.eclipse.emf.ecore.EClass; @@ -46,6 +47,7 @@ import java.sql.SQLException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; @@ -54,7 +56,7 @@ import java.util.Set; /** * @author Stefan Winkler */ -public abstract class AbstractBasicListTableMapping implements IListMapping3, IMappingConstants +public abstract class AbstractBasicListTableMapping implements IListMapping4, IMappingConstants { private IMappingStrategy mappingStrategy; @@ -84,6 +86,17 @@ public abstract class AbstractBasicListTableMapping implements IListMapping3, IM return feature; } + public IDBTable getTable() + { + Iterator<IDBTable> iterator = getDBTables().iterator(); + if (iterator.hasNext()) + { + return iterator.next(); + } + + return null; + } + public void addSimpleChunkWhere(IDBStoreAccessor accessor, CDOID cdoid, StringBuilder builder, int index) { builder.append(LIST_IDX); @@ -444,12 +457,12 @@ public abstract class AbstractBasicListTableMapping implements IListMapping3, IM private void optimizeListIndexes() { /* - * This is an optimization which reduces the amount of modifications on the database to maintain list indexes. For the - * optimization, we let go of the assumption that indexes are zero-based. Instead, we work with an offset at the - * database level which can change with every change to the list (e.g. if the second element is removed from a list with - * 1000 elements, instead of shifting down indexes 2 to 1000 by 1, we shift up index 0 by 1 and have now a list with - * indexes starting at 1 instead of 0. This optimization is applied by modifying the list of Manipulations, which can be - * seen as the database modification plan. + * This is an optimization which reduces the amount of modifications on the database to maintain list indexes. For + * the optimization, we let go of the assumption that indexes are zero-based. Instead, we work with an offset at + * the database level which can change with every change to the list (e.g. if the second element is removed from a + * list with 1000 elements, instead of shifting down indexes 2 to 1000 by 1, we shift up index 0 by 1 and have now + * a list with indexes starting at 1 instead of 0. This optimization is applied by modifying the list of + * Manipulations, which can be seen as the database modification plan. */ // First, get the current offset. @@ -613,8 +626,8 @@ public abstract class AbstractBasicListTableMapping implements IListMapping3, IM if (manipulation.is(MOVE)) { /* - * Step 2: MOVE all elements e (by e.srcIndex) which have e.is(MOVE) to tmpIndex (-1, -2, -3, -4, ...) and store - * tmpIndex in e.tempIndex + * Step 2: MOVE all elements e (by e.srcIndex) which have e.is(MOVE) to tmpIndex (-1, -2, -3, -4, ...) and + * store tmpIndex in e.tempIndex */ manipulation.tmpIndex = getNextTmpIndex(); dbMove(idHandler, manipulation.srcIndex, manipulation.tmpIndex, manipulation.srcIndex); @@ -634,8 +647,8 @@ public abstract class AbstractBasicListTableMapping implements IListMapping3, IM if (manipulation.is(MOVE)) { /* - * Step 4: MOVE all elements e have e.is(MOVE) from e.tempIdx to e.dstIndex (because we have moved them before, moveStmt - * is always initialized + * Step 4: MOVE all elements e have e.is(MOVE) from e.tempIdx to e.dstIndex (because we have moved them + * before, moveStmt is always initialized */ dbMove(idHandler, manipulation.tmpIndex, manipulation.dstIndex, manipulation.srcIndex); @@ -682,16 +695,16 @@ public abstract class AbstractBasicListTableMapping implements IListMapping3, IM protected void writeShifts(IIDHandler idHandler) throws SQLException { /* - * Step 3: shift all elements which have to be shifted up or down because of add, remove or move of other elements to - * their proper position. This has to be done in two phases to avoid collisions, as the index has to be unique and shift - * up operations have to be executed in top to bottom order. + * Step 3: shift all elements which have to be shifted up or down because of add, remove or move of other elements + * to their proper position. This has to be done in two phases to avoid collisions, as the index has to be unique + * and shift up operations have to be executed in top to bottom order. */ LinkedList<Shift> shiftOperations = new LinkedList<Shift>(); /* - * If a necessary shift is detected (source and destination indices differ), firstIndex is set to the current index and - * currentOffset is set to the offset of the shift operation. When a new offset is detected or the range is interrupted, - * we record the range and start a new one if needed. + * If a necessary shift is detected (source and destination indices differ), firstIndex is set to the current + * index and currentOffset is set to the offset of the shift operation. When a new offset is detected or the range + * is interrupted, we record the range and start a new one if needed. */ int rangeStartIndex = NO_INDEX; int rangeOffset = 0; @@ -701,15 +714,16 @@ public abstract class AbstractBasicListTableMapping implements IListMapping3, IM for (Manipulation manipulation : manipulations) { /* - * Shift applies only to elements which are not moved, inserted or deleted (i.e. only plain SET and NONE are affected) + * Shift applies only to elements which are not moved, inserted or deleted (i.e. only plain SET and NONE are + * affected) */ if (manipulation.types == NONE || manipulation.types == SET) { int elementOffset = manipulation.dstIndex - manipulation.srcIndex; /* - * First make sure if we have to close a previous range. This is the case, if the current element's offset differs from - * the rangeOffset and a range is open. + * First make sure if we have to close a previous range. This is the case, if the current element's offset + * differs from the rangeOffset and a range is open. */ if (elementOffset != rangeOffset && rangeStartIndex != NO_INDEX) { @@ -722,8 +736,9 @@ public abstract class AbstractBasicListTableMapping implements IListMapping3, IM } /* - * At this point, either a range is open, which means that the current element also fits in the range (i.e. the offsets - * match) or no range is open. In the latter case, we have to open one if the current element's offset is not 0. + * At this point, either a range is open, which means that the current element also fits in the range (i.e. + * the offsets match) or no range is open. In the latter case, we have to open one if the current element's + * offset is not 0. */ if (elementOffset != 0 && rangeStartIndex == NO_INDEX) { @@ -755,8 +770,8 @@ public abstract class AbstractBasicListTableMapping implements IListMapping3, IM } /* - * Now process the operations. Move down operations can be performed directly, move up operations need to be performed - * later in the reverse direction + * Now process the operations. Move down operations can be performed directly, move up operations need to be + * performed later in the reverse direction */ ListIterator<Shift> operationIt = shiftOperations.listIterator(); writeShiftsDown(idHandler, operationIt); diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractFeatureMapTableMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractFeatureMapTableMapping.java index d91023c222..5c6c9c7ac0 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractFeatureMapTableMapping.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractFeatureMapTableMapping.java @@ -22,6 +22,7 @@ import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.common.revision.CDORevisionUtil; import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext; import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk; +import org.eclipse.emf.cdo.server.StoreThreadLocal; import org.eclipse.emf.cdo.server.db.IDBStore; import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader; @@ -30,6 +31,7 @@ import org.eclipse.emf.cdo.server.db.IMetaDataManager; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping; import org.eclipse.emf.cdo.server.internal.db.bundle.OM; +import org.eclipse.emf.cdo.server.internal.db.mapping.AbstractMappingStrategy; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.net4j.db.DBException; @@ -41,6 +43,7 @@ import org.eclipse.net4j.db.IDBPreparedStatement.ReuseProbability; import org.eclipse.net4j.db.ddl.IDBField; import org.eclipse.net4j.db.ddl.IDBIndex; import org.eclipse.net4j.db.ddl.IDBIndex.Type; +import org.eclipse.net4j.db.ddl.IDBSchema; import org.eclipse.net4j.db.ddl.IDBTable; import org.eclipse.net4j.util.ImplementationError; import org.eclipse.net4j.util.collection.MoveableList; @@ -107,7 +110,14 @@ public abstract class AbstractFeatureMapTableMapping extends AbstractBasicListTa { super(mappingStrategy, eClass, feature); initDBTypes(); - initTable(); + + IDBStoreAccessor accessor = null; + if (AbstractMappingStrategy.isEagerTableCreation(mappingStrategy)) + { + accessor = (IDBStoreAccessor)StoreThreadLocal.getAccessor(); + } + + initTable(accessor); initSQLStrings(); } @@ -123,36 +133,21 @@ public abstract class AbstractFeatureMapTableMapping extends AbstractBasicListTa return ITypeMapping.Registry.INSTANCE; } - private void initTable() + public void setTable(IDBTable table) + { + this.table = table; + } + + public void initTable(IDBStoreAccessor accessor) { String tableName = getMappingStrategy().getTableName(getContainingClass(), getFeature()); - DBType idType = getMappingStrategy().getStore().getIDHandler().getDBType(); - int idLength = getMappingStrategy().getStore().getIDColumnLength(); IDBDatabase database = getMappingStrategy().getStore().getDatabase(); table = database.getSchema().getTable(tableName); if (table == null) { - table = database.getSchemaTransaction().getWorkingCopy().addTable(tableName); - - IDBIndex index = table.addIndexEmpty(Type.NON_UNIQUE); - for (FieldInfo fieldInfo : getKeyFields()) - { - IDBField field = table.addField(fieldInfo.getName(), fieldInfo.getType(), fieldInfo.getPrecision()); - index.addIndexField(field); - } - - // Add field for list index - table.addField(FEATUREMAP_IDX, DBType.INTEGER); - - // Add field for FeatureMap tag (MetaID for Feature in CDO registry) - table.addField(FEATUREMAP_TAG, idType, idLength); - - // Create columns for all DBTypes - initTypeColumns(true); - - table.addIndex(Type.NON_UNIQUE, FEATUREMAP_IDX); - table.addIndex(Type.NON_UNIQUE, FEATUREMAP_TAG); + IDBSchema workingCopy = database.getSchemaTransaction().getWorkingCopy(); + table = createTable(workingCopy, tableName); } else { @@ -160,6 +155,33 @@ public abstract class AbstractFeatureMapTableMapping extends AbstractBasicListTa } } + public IDBTable createTable(IDBSchema schema, String tableName) + { + IDBTable table = schema.addTable(tableName); + + IDBIndex index = table.addIndexEmpty(Type.NON_UNIQUE); + for (FieldInfo fieldInfo : getKeyFields()) + { + IDBField field = table.addField(fieldInfo.getName(), fieldInfo.getType(), fieldInfo.getPrecision()); + index.addIndexField(field); + } + + // Add field for list index + table.addField(FEATUREMAP_IDX, DBType.INTEGER); + + // Add field for FeatureMap tag (MetaID for Feature in CDO registry) + DBType idType = getMappingStrategy().getStore().getIDHandler().getDBType(); + int idLength = getMappingStrategy().getStore().getIDColumnLength(); + table.addField(FEATUREMAP_TAG, idType, idLength); + + // Create columns for all DBTypes + initTypeColumns(true); + + table.addIndex(Type.NON_UNIQUE, FEATUREMAP_IDX); + table.addIndex(Type.NON_UNIQUE, FEATUREMAP_TAG); + return table; + } + private void initTypeColumns(boolean create) { for (DBType type : getDBTypes()) @@ -284,7 +306,8 @@ public abstract class AbstractFeatureMapTableMapping extends AbstractBasicListTa return dbTypes; } - protected final IDBTable getTable() + @Override + public final IDBTable getTable() { return table; } @@ -591,7 +614,8 @@ public abstract class AbstractFeatureMapTableMapping extends AbstractBasicListTa public final boolean queryXRefs(IDBStoreAccessor accessor, String mainTableName, String mainTableWhere, QueryXRefsContext context, String idString) { /* - * must never be called (a feature map is not associated with an EReference feature, so XRefs are nor supported here) + * must never be called (a feature map is not associated with an EReference feature, so XRefs are nor supported + * here) */ throw new ImplementationError("Should never be called!"); } 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 fbd69b3ee6..0f01db5c7f 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 @@ -36,7 +36,8 @@ import org.eclipse.emf.cdo.server.StoreThreadLocal; import org.eclipse.emf.cdo.server.db.IDBStore; import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; import org.eclipse.emf.cdo.server.db.IIDHandler; -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.IListMapping3; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; @@ -71,7 +72,6 @@ import org.eclipse.net4j.util.om.trace.ContextTracer; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; -import org.eclipse.emf.ecore.util.FeatureMapUtil; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -80,7 +80,6 @@ import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -91,7 +90,7 @@ import java.util.Set; * @author Eike Stepper * @since 2.0 */ -public abstract class AbstractHorizontalClassMapping implements IClassMapping, IMappingConstants, IDeactivateable +public abstract class AbstractHorizontalClassMapping implements IClassMapping2, IMappingConstants, IDeactivateable { protected static final int UNSET_LIST = -1; @@ -120,123 +119,97 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I this.mappingStrategy = mappingStrategy; this.eClass = eClass; - IDBStoreAccessor accessor = null; - if (AbstractHorizontalMappingStrategy.isEagerTableCreation(mappingStrategy)) + if (!AbstractMappingStrategy.isSkipMappingInitialization()) { - accessor = (IDBStoreAccessor)StoreThreadLocal.getAccessor(); + IDBStoreAccessor accessor = null; + if (AbstractMappingStrategy.isEagerTableCreation(mappingStrategy)) + { + accessor = (IDBStoreAccessor)StoreThreadLocal.getAccessor(); + } + + initTable(accessor); } + } - initTable(accessor); + public void setTable(IDBTable table) + { + this.table = table; } - protected void initTable(IDBStoreAccessor accessor) + public void loadTable() { - IDBStore store = mappingStrategy.getStore(); - IDBDatabase database = store.getDatabase(); - String tableName = mappingStrategy.getTableName(eClass); + valueMappings = null; + listMappings = null; + listSizeFields = null; + unsettableFields = null; - table = database.getSchema().getTable(tableName); - if (table == null) + EStructuralFeature[] allPersistentFeatures = CDOModelUtil.getClassInfo(eClass).getAllPersistentFeatures(); + List<EStructuralFeature> unsettableFeatures = new ArrayList<EStructuralFeature>(); + + for (EStructuralFeature feature : allPersistentFeatures) { - if (accessor != null) + String fieldName = mappingStrategy.getFieldName(feature); + if (feature.isMany()) { - IDBSchemaTransaction schemaTransaction = database.openSchemaTransaction(); - - try + IListMapping listMapping = createListMapping(feature); + if (listMapping != null) { - DBType idType = store.getIDHandler().getDBType(); - int idLength = store.getIDColumnLength(); - - IDBSchema workingCopy = schemaTransaction.getWorkingCopy(); - IDBTable table = workingCopy.addTable(tableName); - table.addField(ATTRIBUTES_ID, idType, idLength, true); - table.addField(ATTRIBUTES_VERSION, DBType.INTEGER, true); - - IDBField branchField = addBranchField(table); - - table.addField(ATTRIBUTES_CREATED, DBType.BIGINT, true); - table.addField(ATTRIBUTES_REVISED, DBType.BIGINT, true); - table.addField(ATTRIBUTES_RESOURCE, idType, idLength, true); - addContainerField(table, idType, idLength); - table.addField(ATTRIBUTES_FEATURE, DBType.INTEGER, true); - - IDBIndex primaryKey = table.addIndex(IDBIndex.Type.PRIMARY_KEY, ATTRIBUTES_ID, ATTRIBUTES_VERSION); - if (branchField != null) + if (listMapping instanceof IListMapping3) { - primaryKey.addIndexField(branchField); + ((IListMapping3)listMapping).setClassMapping(this); } - table.addIndex(IDBIndex.Type.NON_UNIQUE, ATTRIBUTES_REVISED); + addListMapping(listMapping); - EStructuralFeature[] allPersistentFeatures = CDOModelUtil.getClassInfo(eClass).getAllPersistentFeatures(); - Map<EStructuralFeature, ITypeMapping> valueMappings = new HashMap<EStructuralFeature, ITypeMapping>(); - List<EStructuralFeature> unsettableFeatures = new ArrayList<EStructuralFeature>(); - - for (EStructuralFeature feature : allPersistentFeatures) - { - String fieldName = mappingStrategy.getFieldName(feature); - if (feature.isMany()) - { - IListMapping mapping = createListMapping(feature); - if (mapping != null) - { - // Add field for list sizes. - table.addField(fieldName, DBType.INTEGER); - } - } - else - { - ITypeMapping valueMapping = mappingStrategy.createValueMapping(feature); - valueMapping.createDBField(table, fieldName); - valueMappings.put(feature, valueMapping); - - Set<CDOFeatureType> forceIndexes = AbstractMappingStrategy.getForceIndexes(mappingStrategy); - if (CDOFeatureType.matchesCombination(feature, forceIndexes)) - { - IDBField field = table.getField(fieldName); - if (!table.hasIndexFor(field)) - { - IDBIndex index = table.addIndex(IDBIndex.Type.NON_UNIQUE, field); - DBUtil.setOptional(index, true); // Creation might fail for unsupported column type! - } - } - - if (feature.isUnsettable()) - { - unsettableFeatures.add(feature); - } - } - } + IDBField listSizeField = table.getField(fieldName); + addListSizeFiled(feature, listSizeField); + } + } + else + { + ITypeMapping valueMapping = mappingStrategy.createValueMapping(feature); + valueMapping.setDBField(table, fieldName); + addValueMapping(valueMapping); - // Add unsettable fields to end of table. - for (EStructuralFeature feature : unsettableFeatures) - { - String fieldName = mappingStrategy.getUnsettableFieldName(feature); - table.addField(fieldName, DBType.BOOLEAN); - } + if (feature.isUnsettable()) + { + unsettableFeatures.add(feature); + } + } + } - // Create optional feature indices. - for (List<EStructuralFeature> features : DBIndexAnnotation.getIndices(eClass, allPersistentFeatures)) - { - int size = features.size(); - IDBField[] fields = new IDBField[size]; + // Register unsettable fields. + if (!unsettableFeatures.isEmpty()) + { + unsettableFields = new LinkedHashMap<EStructuralFeature, IDBField>(); + for (EStructuralFeature feature : unsettableFeatures) + { + String fieldName = mappingStrategy.getUnsettableFieldName(feature); + IDBField field = table.getField(fieldName); + unsettableFields.put(feature, field); + } + } - for (int i = 0; i < size; i++) - { - EStructuralFeature feature = features.get(i); + ensureValueAndListMappings(); + } - ITypeMapping valueMapping = valueMappings.get(feature); - IDBField field = valueMapping.getField(); - fields[i] = field; - } + public void initTable(IDBStoreAccessor accessor) + { + IDBStore store = mappingStrategy.getStore(); + IDBDatabase database = store.getDatabase(); + String tableName = mappingStrategy.getTableName(eClass); - if (!table.hasIndexFor(fields)) - { - IDBIndex index = table.addIndex(IDBIndex.Type.NON_UNIQUE, fields); - DBUtil.setOptional(index, true); // Creation might fail for unsupported column type! - } - } + table = database.getSchema().getTable(tableName); + if (table == null) + { + if (accessor != null) + { + IDBSchemaTransaction schemaTransaction = database.openSchemaTransaction(); + try + { + IDBSchema workingCopy = schemaTransaction.getWorkingCopy(); + table = createTable(workingCopy, tableName); schemaTransaction.commit(); } finally @@ -250,99 +223,236 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I } else { - valueMappings = null; - listMappings = null; - listSizeFields = null; - unsettableFields = null; + loadTable(); + initSQLStrings(); + } + } + + public IDBTable createTable(IDBSchema schema, String tableName) + { + IDBStore store = mappingStrategy.getStore(); + DBType idType = store.getIDHandler().getDBType(); + int idLength = store.getIDColumnLength(); - EStructuralFeature[] allPersistentFeatures = CDOModelUtil.getClassInfo(eClass).getAllPersistentFeatures(); - List<EStructuralFeature> unsettableFeatures = new ArrayList<EStructuralFeature>(); + IDBTable table = schema.addTable(tableName); + table.addField(ATTRIBUTES_ID, idType, idLength, true); + table.addField(ATTRIBUTES_VERSION, DBType.INTEGER, true); - for (EStructuralFeature feature : allPersistentFeatures) - { - String fieldName = mappingStrategy.getFieldName(feature); - if (feature.isMany()) - { - IListMapping mapping = createListMapping(feature); - if (mapping != null) - { - if (mapping instanceof IListMapping3) - { - ((IListMapping3)mapping).setClassMapping(this); - } + IDBField branchField = addBranchField(table); - if (listMappings == null) - { - listMappings = new ArrayList<IListMapping>(); - } + table.addField(ATTRIBUTES_CREATED, DBType.BIGINT, true); + table.addField(ATTRIBUTES_REVISED, DBType.BIGINT, true); + table.addField(ATTRIBUTES_RESOURCE, idType, idLength, true); + addContainerField(table, idType, idLength); + table.addField(ATTRIBUTES_FEATURE, DBType.INTEGER, true); + + IDBIndex primaryKey = table.addIndex(IDBIndex.Type.PRIMARY_KEY, ATTRIBUTES_ID, ATTRIBUTES_VERSION); + if (branchField != null) + { + primaryKey.addIndexField(branchField); + } - listMappings.add(mapping); + table.addIndex(IDBIndex.Type.NON_UNIQUE, ATTRIBUTES_REVISED); - IDBField listSizeField = table.getField(fieldName); + createFeatureMappings(table, true, CDOModelUtil.getClassInfo(eClass).getAllPersistentFeatures()); + ensureValueAndListMappings(); + return table; + } - if (listSizeFields == null) - { - listSizeFields = new LinkedHashMap<EStructuralFeature, IDBField>(); - } + public IFeatureMapping[] createFeatureMappings(IDBTable table, boolean updateClassMapping, EStructuralFeature... features) + { + List<IFeatureMapping> result = new ArrayList<IFeatureMapping>(); + Map<EStructuralFeature, IDBField> unsettableFields = new LinkedHashMap<EStructuralFeature, IDBField>(); - listSizeFields.put(feature, listSizeField); - } - } - else + for (EStructuralFeature feature : features) + { + String fieldName = mappingStrategy.getFieldName(feature); + if (feature.isMany()) + { + IListMapping listMapping = createListMapping(feature); + if (listMapping != null) { - ITypeMapping mapping = mappingStrategy.createValueMapping(feature); - mapping.setDBField(table, fieldName); + result.add(listMapping); - if (valueMappings == null) + if (updateClassMapping) { - valueMappings = new ArrayList<ITypeMapping>(); + addListMapping(listMapping); } - valueMappings.add(mapping); + // Add field for list sizes. + IDBField listSizeField = table.addField(fieldName, DBType.INTEGER); - if (feature.isUnsettable()) + if (updateClassMapping) { - unsettableFeatures.add(feature); + addListSizeFiled(feature, listSizeField); } } } - - // Register unsettable fields. - if (!unsettableFeatures.isEmpty()) + else { - unsettableFields = new LinkedHashMap<EStructuralFeature, IDBField>(); - for (EStructuralFeature feature : unsettableFeatures) + ITypeMapping valueMapping = mappingStrategy.createValueMapping(feature); + valueMapping.createDBField(table, fieldName); + result.add(valueMapping); + + if (updateClassMapping) + { + addValueMapping(valueMapping); + } + + IDBField field = table.getField(fieldName); + + Set<CDOFeatureType> forceIndexes = AbstractMappingStrategy.getForceIndexes(mappingStrategy); + if (CDOFeatureType.matchesCombination(feature, forceIndexes)) + { + if (!table.hasIndexFor(field)) + { + IDBIndex index = table.addIndex(IDBIndex.Type.NON_UNIQUE, field); + DBUtil.setOptional(index, true); // Creation might fail for unsupported column type! + } + } + + if (feature.isUnsettable()) { - String fieldName = mappingStrategy.getUnsettableFieldName(feature); - IDBField field = table.getField(fieldName); unsettableFields.put(feature, field); } } + } - if (valueMappings == null) + // Add unsettable fields to end of table. + if (!unsettableFields.isEmpty()) + { + for (EStructuralFeature feature : unsettableFields.keySet()) { - valueMappings = Collections.emptyList(); + String fieldName = mappingStrategy.getUnsettableFieldName(feature); + table.addField(fieldName, DBType.BOOLEAN); } - if (listMappings == null) + if (updateClassMapping) { - listMappings = Collections.emptyList(); + this.unsettableFields = unsettableFields; } + } - initSQLStrings(); + // Create optional feature indices. + for (List<EStructuralFeature> indexedFeatures : DBIndexAnnotation.getIndices(eClass, features)) + { + int size = indexedFeatures.size(); + IDBField[] fields = new IDBField[size]; + + for (int i = 0; i < size; i++) + { + EStructuralFeature feature = indexedFeatures.get(i); + + ITypeMapping valueMapping = getValueMapping(feature); + fields[i] = valueMapping.getField(); + } + + if (!table.hasIndexFor(fields)) + { + IDBIndex index = table.addIndex(IDBIndex.Type.NON_UNIQUE, fields); + DBUtil.setOptional(index, true); // Creation might fail for unsupported column type! + } } + + return result.toArray(new IFeatureMapping[result.size()]); } - private IListMapping createListMapping(EStructuralFeature feature) + public IFeatureMapping[] getFeatureMappings() + { + List<IFeatureMapping> featureMappings = new ArrayList<IFeatureMapping>(); + + if (valueMappings != null) + { + featureMappings.addAll(valueMappings); + } + + if (listMappings != null) + { + featureMappings.addAll(listMappings); + } + + return featureMappings.toArray(new IFeatureMapping[featureMappings.size()]); + } + + public IFeatureMapping getFeatureMapping(EStructuralFeature feature) { - if (FeatureMapUtil.isFeatureMap(feature)) + if (feature.isMany()) { - return mappingStrategy.createFeatureMapMapping(eClass, feature); + return getFeatureMapping(feature, listMappings); } + return getFeatureMapping(feature, valueMappings); + } + + private IFeatureMapping getFeatureMapping(EStructuralFeature feature, List<? extends IFeatureMapping> featureMappings) + { + if (featureMappings != null) + { + for (IFeatureMapping featureMapping : featureMappings) + { + if (featureMapping.getFeature() == feature) + { + return featureMapping; + } + } + } + + return null; + } + + private void addValueMapping(ITypeMapping mapping) + { + if (valueMappings == null) + { + valueMappings = new ArrayList<ITypeMapping>(); + } + + valueMappings.add(mapping); + } + + private void addListMapping(IListMapping mapping) + { + if (listMappings == null) + { + listMappings = new ArrayList<IListMapping>(); + } + + listMappings.add(mapping); + } + + private void addListSizeFiled(EStructuralFeature feature, IDBField field) + { + if (listSizeFields == null) + { + listSizeFields = new LinkedHashMap<EStructuralFeature, IDBField>(); + } + + listSizeFields.put(feature, field); + } + + private IListMapping createListMapping(EStructuralFeature feature) + { + // if (FeatureMapUtil.isFeatureMap(feature)) + // { + // return mappingStrategy.createFeatureMapMapping(eClass, feature); + // } + return mappingStrategy.createListMapping(eClass, feature); } + private void ensureValueAndListMappings() + { + if (valueMappings == null) + { + valueMappings = Collections.emptyList(); + } + + if (listMappings == null) + { + listMappings = Collections.emptyList(); + } + } + protected void initSQLStrings() { // ----------- Select all revisions (for handleRevisions) --- @@ -528,12 +638,12 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I return eClass; } - protected final Map<EStructuralFeature, IDBField> getUnsettableFields() + public final Map<EStructuralFeature, IDBField> getUnsettableFields() { return unsettableFields; } - protected final Map<EStructuralFeature, IDBField> getListSizeFields() + public final Map<EStructuralFeature, IDBField> getListSizeFields() { return listSizeFields; } @@ -563,15 +673,18 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I public final IListMapping getListMapping(EStructuralFeature feature) { - for (IListMapping mapping : listMappings) + if (listMappings != null) { - if (mapping.getFeature() == feature) + for (IListMapping mapping : listMappings) { - return mapping; + if (mapping.getFeature() == feature) + { + return mapping; + } } } - throw new IllegalArgumentException("List mapping for feature " + feature + " does not exist"); //$NON-NLS-1$ //$NON-NLS-2$ + return null; } protected final IDBTable getTable() @@ -1019,6 +1132,11 @@ public abstract class AbstractHorizontalClassMapping implements IClassMapping, I if (ref.isMany()) { IListMapping listMapping = getListMapping(ref); + if (listMapping == null) + { + return true; + } + String where = getListXRefsWhere(context); boolean more = listMapping.queryXRefs(accessor, tableName, where, context, idString); diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalMappingStrategy.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalMappingStrategy.java index f29dc96e26..7916d5dc01 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalMappingStrategy.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalMappingStrategy.java @@ -359,9 +359,9 @@ public abstract class AbstractHorizontalMappingStrategy extends AbstractMappingS } @Override - protected boolean isMapped(EClass eClass) + public boolean isMapped(EClass eClass) { - return !eClass.isAbstract() && !eClass.isInterface(); + return !eClass.isAbstract() && !eClass.isInterface() && super.isMapped(eClass); } @Override diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractListTableMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractListTableMapping.java index 28b23aeadd..041325671f 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractListTableMapping.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractListTableMapping.java @@ -26,6 +26,7 @@ import org.eclipse.emf.cdo.server.db.IIDHandler; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping; import org.eclipse.emf.cdo.server.internal.db.bundle.OM; +import org.eclipse.emf.cdo.server.internal.db.mapping.AbstractMappingStrategy; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.net4j.db.DBException; @@ -88,22 +89,29 @@ public abstract class AbstractListTableMapping extends AbstractBasicListTableMap { super(mappingStrategy, eClass, feature); - IDBStoreAccessor accessor = null; - if (AbstractHorizontalMappingStrategy.isEagerTableCreation(mappingStrategy)) + if (!AbstractMappingStrategy.isSkipMappingInitialization()) { - accessor = (IDBStoreAccessor)StoreThreadLocal.getAccessor(); + IDBStoreAccessor accessor = null; + if (AbstractMappingStrategy.isEagerTableCreation(mappingStrategy)) + { + accessor = (IDBStoreAccessor)StoreThreadLocal.getAccessor(); + } + + initTable(accessor); } + } - initTable(accessor); + public void setTable(IDBTable table) + { + this.table = table; } - protected void initTable(IDBStoreAccessor accessor) + public void initTable(IDBStoreAccessor accessor) { IMappingStrategy mappingStrategy = getMappingStrategy(); EStructuralFeature feature = getFeature(); String tableName = mappingStrategy.getTableName(getContainingClass(), feature); - typeMapping = mappingStrategy.createValueMapping(feature); IDBDatabase database = mappingStrategy.getStore().getDatabase(); table = database.getSchema().getTable(tableName); @@ -116,32 +124,7 @@ public abstract class AbstractListTableMapping extends AbstractBasicListTableMap try { IDBSchema workingCopy = schemaTransaction.getWorkingCopy(); - IDBTable table = workingCopy.addTable(tableName); - - IDBIndex primaryKey = table.addIndexEmpty(Type.PRIMARY_KEY); - for (FieldInfo info : getKeyFields()) - { - IDBField field = table.addField(info.getName(), info.getType(), info.getPrecision(), true); - primaryKey.addIndexField(field); - } - - // Add field for list index. - IDBField listIndexField = table.addField(LIST_IDX, DBType.INTEGER, true); - primaryKey.addIndexField(listIndexField); - - // Add field for value. - typeMapping.createDBField(table, LIST_VALUE); - - if (needsIndexOnValueField(feature)) - { - IDBField field = table.getField(LIST_VALUE); - - if (!table.hasIndexFor(field)) - { - IDBIndex index = table.addIndex(IDBIndex.Type.NON_UNIQUE, field); - DBUtil.setOptional(index, true); // Creation might fail for unsupported column type! - } - } + createTable(workingCopy, tableName); schemaTransaction.commit(); } @@ -156,11 +139,46 @@ public abstract class AbstractListTableMapping extends AbstractBasicListTableMap } else { + typeMapping = mappingStrategy.createValueMapping(feature); typeMapping.setDBField(table, LIST_VALUE); initSQLStrings(); } } + public IDBTable createTable(IDBSchema schema, String tableName) + { + IDBTable table = schema.addTable(tableName); + + IDBIndex primaryKey = table.addIndexEmpty(Type.PRIMARY_KEY); + for (FieldInfo info : getKeyFields()) + { + IDBField field = table.addField(info.getName(), info.getType(), info.getPrecision(), true); + primaryKey.addIndexField(field); + } + + // Add field for list index. + IDBField listIndexField = table.addField(LIST_IDX, DBType.INTEGER, true); + primaryKey.addIndexField(listIndexField); + + // Add field for value. + EStructuralFeature feature = getFeature(); + typeMapping = getMappingStrategy().createValueMapping(feature); + typeMapping.createDBField(table, LIST_VALUE); + + if (needsIndexOnValueField(feature)) + { + IDBField field = table.getField(LIST_VALUE); + + if (!table.hasIndexFor(field)) + { + IDBIndex index = table.addIndex(IDBIndex.Type.NON_UNIQUE, field); + DBUtil.setOptional(index, true); // Creation might fail for unsupported column type! + } + } + + return table; + } + protected void initSQLStrings() { String tableName = table.getName(); @@ -245,12 +263,13 @@ public abstract class AbstractListTableMapping extends AbstractBasicListTableMap return Collections.singleton(table); } - protected final IDBTable getTable() + @Override + public final IDBTable getTable() { return table; } - protected final ITypeMapping getTypeMapping() + public final ITypeMapping getTypeMapping() { return typeMapping; } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditFeatureMapTableMappingWithRanges.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditFeatureMapTableMappingWithRanges.java index 4825a7d290..8ec86c5071 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditFeatureMapTableMappingWithRanges.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditFeatureMapTableMappingWithRanges.java @@ -36,6 +36,7 @@ import org.eclipse.emf.cdo.common.revision.delta.CDOUnsetFeatureDelta; import org.eclipse.emf.cdo.server.IRepository; import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext; import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk; +import org.eclipse.emf.cdo.server.StoreThreadLocal; import org.eclipse.emf.cdo.server.db.IDBStore; import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader; @@ -44,6 +45,7 @@ import org.eclipse.emf.cdo.server.db.mapping.IListMappingDeltaSupport; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping; import org.eclipse.emf.cdo.server.internal.db.bundle.OM; +import org.eclipse.emf.cdo.server.internal.db.mapping.AbstractMappingStrategy; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.net4j.db.DBException; @@ -53,6 +55,7 @@ import org.eclipse.net4j.db.IDBDatabase; import org.eclipse.net4j.db.IDBPreparedStatement; import org.eclipse.net4j.db.IDBPreparedStatement.ReuseProbability; import org.eclipse.net4j.db.ddl.IDBIndex.Type; +import org.eclipse.net4j.db.ddl.IDBSchema; import org.eclipse.net4j.db.ddl.IDBTable; import org.eclipse.net4j.util.ImplementationError; import org.eclipse.net4j.util.collection.MoveableList; @@ -141,7 +144,14 @@ public class AuditFeatureMapTableMappingWithRanges extends AbstractBasicListTabl { super(mappingStrategy, eClass, feature); initDBTypes(); - initTable(); + + IDBStoreAccessor accessor = null; + if (AbstractMappingStrategy.isEagerTableCreation(mappingStrategy)) + { + accessor = (IDBStoreAccessor)StoreThreadLocal.getAccessor(); + } + + initTable(accessor); initSQLStrings(); } @@ -152,7 +162,12 @@ public class AuditFeatureMapTableMappingWithRanges extends AbstractBasicListTabl dbTypes = new ArrayList<DBType>(registry.getDefaultFeatureMapDBTypes()); } - private void initTable() + public void setTable(IDBTable table) + { + this.table = table; + } + + public void initTable(IDBStoreAccessor accessor) { String tableName = getMappingStrategy().getTableName(getContainingClass(), getFeature()); IDBStore store = getMappingStrategy().getStore(); @@ -185,6 +200,11 @@ public class AuditFeatureMapTableMappingWithRanges extends AbstractBasicListTabl } } + public IDBTable createTable(IDBSchema schema, String tableName) + { + throw new UnsupportedOperationException(); + } + private void initTypeColumns(boolean create) { for (DBType type : getDBTypes()) @@ -367,7 +387,8 @@ public class AuditFeatureMapTableMappingWithRanges extends AbstractBasicListTabl return Collections.singleton(table); } - protected final IDBTable getTable() + @Override + public final IDBTable getTable() { return table; } @@ -700,8 +721,8 @@ public class AuditFeatureMapTableMappingWithRanges extends AbstractBasicListTabl CDOBranch main = getMappingStrategy().getStore().getRepository().getBranchManager().getMainBranch(); // get revision from cache to find out version number - CDORevision revision = getMappingStrategy().getStore().getRepository().getRevisionManager().getRevision(id, main.getHead(), /* chunksize = */0, - CDORevision.DEPTH_NONE, true); + CDORevision revision = getMappingStrategy().getStore().getRepository().getRevisionManager().getRevision(id, main.getHead(), + /* chunksize = */0, CDORevision.DEPTH_NONE, true); // set cdo_revision_removed for all list items (so we have no NULL values) clearList(accessor, id, revision.getVersion(), FINAL_VERSION); diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditListTableMappingWithRanges.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditListTableMappingWithRanges.java index 8a27cfa925..4f385ce213 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditListTableMappingWithRanges.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditListTableMappingWithRanges.java @@ -43,6 +43,7 @@ import org.eclipse.emf.cdo.server.db.mapping.IListMappingUnitSupport; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping; import org.eclipse.emf.cdo.server.internal.db.bundle.OM; +import org.eclipse.emf.cdo.server.internal.db.mapping.AbstractMappingStrategy; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.emf.cdo.spi.server.InternalRepository; @@ -128,7 +129,7 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi super(mappingStrategy, eClass, feature); IDBStoreAccessor accessor = null; - if (AbstractHorizontalMappingStrategy.isEagerTableCreation(mappingStrategy)) + if (AbstractMappingStrategy.isEagerTableCreation(mappingStrategy)) { accessor = (IDBStoreAccessor)StoreThreadLocal.getAccessor(); } @@ -136,14 +137,14 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi initTable(accessor); } - private void initTable(IDBStoreAccessor accessor) + public void setTable(IDBTable table) { - String tableName = getMappingStrategy().getTableName(getContainingClass(), getFeature()); - typeMapping = getMappingStrategy().createValueMapping(getFeature()); + this.table = table; + } - IDBStore store = getMappingStrategy().getStore(); - DBType idType = store.getIDHandler().getDBType(); - int idLength = store.getIDColumnLength(); + public void initTable(IDBStoreAccessor accessor) + { + String tableName = getMappingStrategy().getTableName(getContainingClass(), getFeature()); IDBDatabase database = getMappingStrategy().getStore().getDatabase(); table = database.getSchema().getTable(tableName); @@ -155,19 +156,7 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi try { - IDBSchema workingCopy = schemaTransaction.getWorkingCopy(); - IDBTable table = workingCopy.addTable(tableName); - - table.addField(LIST_REVISION_ID, idType, idLength, true); - table.addField(LIST_REVISION_VERSION_ADDED, DBType.INTEGER); - table.addField(LIST_REVISION_VERSION_REMOVED, DBType.INTEGER); - table.addField(LIST_IDX, DBType.INTEGER, true); - - // TODO think about indexes - table.addIndex(Type.NON_UNIQUE, LIST_REVISION_ID, LIST_REVISION_VERSION_ADDED, LIST_REVISION_VERSION_REMOVED, LIST_IDX); - - typeMapping.createDBField(table, LIST_VALUE); - + table = createTable(schemaTransaction.getWorkingCopy(), tableName); schemaTransaction.commit(); } finally @@ -181,11 +170,32 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi } else { + typeMapping = getMappingStrategy().createValueMapping(getFeature()); typeMapping.setDBField(table, LIST_VALUE); initSQLStrings(); } } + public IDBTable createTable(IDBSchema schema, String tableName) + { + IDBStore store = getMappingStrategy().getStore(); + DBType idType = store.getIDHandler().getDBType(); + int idLength = store.getIDColumnLength(); + + IDBTable table = schema.addTable(tableName); + table.addField(LIST_REVISION_ID, idType, idLength, true); + table.addField(LIST_REVISION_VERSION_ADDED, DBType.INTEGER); + table.addField(LIST_REVISION_VERSION_REMOVED, DBType.INTEGER); + table.addField(LIST_IDX, DBType.INTEGER, true); + + // TODO think about indexes + table.addIndex(Type.NON_UNIQUE, LIST_REVISION_ID, LIST_REVISION_VERSION_ADDED, LIST_REVISION_VERSION_REMOVED, LIST_IDX); + + typeMapping = getMappingStrategy().createValueMapping(getFeature()); + typeMapping.createDBField(table, LIST_VALUE); + return table; + } + private void initSQLStrings() { String tableName = getTable().getName(); @@ -332,7 +342,8 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi return Collections.singleton(table); } - protected final IDBTable getTable() + @Override + public final IDBTable getTable() { return table; } @@ -599,8 +610,8 @@ public class AuditListTableMappingWithRanges extends AbstractBasicListTableMappi CDOBranch main = getMappingStrategy().getStore().getRepository().getBranchManager().getMainBranch(); // get revision from cache to find out version number - CDORevision revision = getMappingStrategy().getStore().getRepository().getRevisionManager().getRevision(id, main.getHead(), /* chunksize = */0, - CDORevision.DEPTH_NONE, true); + CDORevision revision = getMappingStrategy().getStore().getRepository().getRevisionManager().getRevision(id, main.getHead(), + /* chunksize = */0, CDORevision.DEPTH_NONE, true); // set cdo_revision_removed for all list items (so we have no NULL values) clearList(accessor, id, revision.getVersion(), FINAL_VERSION); diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/BranchingFeatureMapTableMappingWithRanges.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/BranchingFeatureMapTableMappingWithRanges.java index 5db1697cf3..65858dacc0 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/BranchingFeatureMapTableMappingWithRanges.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/BranchingFeatureMapTableMappingWithRanges.java @@ -32,6 +32,7 @@ import org.eclipse.emf.cdo.common.revision.delta.CDOUnsetFeatureDelta; import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext; import org.eclipse.emf.cdo.server.IStoreChunkReader; import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk; +import org.eclipse.emf.cdo.server.StoreThreadLocal; import org.eclipse.emf.cdo.server.db.IDBStore; import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader; @@ -40,6 +41,7 @@ import org.eclipse.emf.cdo.server.db.mapping.IListMappingDeltaSupport; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping; import org.eclipse.emf.cdo.server.internal.db.bundle.OM; +import org.eclipse.emf.cdo.server.internal.db.mapping.AbstractMappingStrategy; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager; import org.eclipse.emf.cdo.spi.server.InternalRepository; @@ -51,6 +53,7 @@ import org.eclipse.net4j.db.IDBDatabase; import org.eclipse.net4j.db.IDBPreparedStatement; import org.eclipse.net4j.db.IDBPreparedStatement.ReuseProbability; import org.eclipse.net4j.db.ddl.IDBIndex.Type; +import org.eclipse.net4j.db.ddl.IDBSchema; import org.eclipse.net4j.db.ddl.IDBTable; import org.eclipse.net4j.util.ImplementationError; import org.eclipse.net4j.util.collection.MoveableList; @@ -137,7 +140,14 @@ public class BranchingFeatureMapTableMappingWithRanges extends AbstractBasicList { super(mappingStrategy, eClass, feature); initDBTypes(); - initTable(); + + IDBStoreAccessor accessor = null; + if (AbstractMappingStrategy.isEagerTableCreation(mappingStrategy)) + { + accessor = (IDBStoreAccessor)StoreThreadLocal.getAccessor(); + } + + initTable(accessor); initSQLStrings(); } @@ -148,18 +158,24 @@ public class BranchingFeatureMapTableMappingWithRanges extends AbstractBasicList dbTypes = new ArrayList<DBType>(registry.getDefaultFeatureMapDBTypes()); } - private void initTable() + public void setTable(IDBTable table) + { + this.table = table; + } + + public void initTable(IDBStoreAccessor accessor) { String tableName = getMappingStrategy().getTableName(getContainingClass(), getFeature()); IDBStore store = getMappingStrategy().getStore(); DBType idType = store.getIDHandler().getDBType(); int idLength = store.getIDColumnLength(); - IDBDatabase database = getMappingStrategy().getStore().getDatabase(); + IDBDatabase database = store.getDatabase(); table = database.getSchema().getTable(tableName); if (table == null) { - table = database.getSchemaTransaction().getWorkingCopy().addTable(tableName); + IDBSchema workingCopy = database.getSchemaTransaction().getWorkingCopy(); + table = workingCopy.addTable(tableName); table.addField(FEATUREMAP_REVISION_ID, idType, idLength); table.addField(LIST_REVISION_BRANCH, DBType.INTEGER); table.addField(FEATUREMAP_VERSION_ADDED, DBType.INTEGER); @@ -186,6 +202,11 @@ public class BranchingFeatureMapTableMappingWithRanges extends AbstractBasicList } } + public IDBTable createTable(IDBSchema schema, String tableName) + { + throw new UnsupportedOperationException(); + } + private void initTypeColumns(boolean create) { for (DBType type : getDBTypes()) @@ -372,7 +393,8 @@ public class BranchingFeatureMapTableMappingWithRanges extends AbstractBasicList return dbTypes; } - protected final IDBTable getTable() + @Override + public final IDBTable getTable() { return table; } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/BranchingListTableMappingWithRanges.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/BranchingListTableMappingWithRanges.java index 8aa6f61f7f..8af5b7bc95 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/BranchingListTableMappingWithRanges.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/BranchingListTableMappingWithRanges.java @@ -42,6 +42,7 @@ import org.eclipse.emf.cdo.server.db.mapping.IListMappingDeltaSupport; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping; import org.eclipse.emf.cdo.server.internal.db.bundle.OM; +import org.eclipse.emf.cdo.server.internal.db.mapping.AbstractMappingStrategy; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager; import org.eclipse.emf.cdo.spi.server.InternalRepository; @@ -125,7 +126,7 @@ public class BranchingListTableMappingWithRanges extends AbstractBasicListTableM super(mappingStrategy, eClass, feature); IDBStoreAccessor accessor = null; - if (AbstractHorizontalMappingStrategy.isEagerTableCreation(mappingStrategy)) + if (AbstractMappingStrategy.isEagerTableCreation(mappingStrategy)) { accessor = (IDBStoreAccessor)StoreThreadLocal.getAccessor(); } @@ -133,14 +134,14 @@ public class BranchingListTableMappingWithRanges extends AbstractBasicListTableM initTable(accessor); } - private void initTable(IDBStoreAccessor accessor) + public void setTable(IDBTable table) { - String tableName = getMappingStrategy().getTableName(getContainingClass(), getFeature()); - typeMapping = getMappingStrategy().createValueMapping(getFeature()); + this.table = table; + } - IDBStore store = getMappingStrategy().getStore(); - DBType idType = store.getIDHandler().getDBType(); - int idLength = store.getIDColumnLength(); + public void initTable(IDBStoreAccessor accessor) + { + String tableName = getMappingStrategy().getTableName(getContainingClass(), getFeature()); IDBDatabase database = getMappingStrategy().getStore().getDatabase(); table = database.getSchema().getTable(tableName); @@ -153,18 +154,7 @@ public class BranchingListTableMappingWithRanges extends AbstractBasicListTableM try { IDBSchema workingCopy = schemaTransaction.getWorkingCopy(); - IDBTable table = workingCopy.addTable(tableName); - table.addField(LIST_REVISION_ID, idType, idLength, true); - table.addField(LIST_REVISION_BRANCH, DBType.INTEGER, true); - table.addField(LIST_REVISION_VERSION_ADDED, DBType.INTEGER); - table.addField(LIST_REVISION_VERSION_REMOVED, DBType.INTEGER); - table.addField(LIST_IDX, DBType.INTEGER, true); - - // TODO think about indexes - table.addIndex(Type.NON_UNIQUE, LIST_REVISION_ID, LIST_REVISION_BRANCH, LIST_REVISION_VERSION_ADDED, LIST_REVISION_VERSION_REMOVED, LIST_IDX); - - typeMapping.createDBField(table, LIST_VALUE); - + table = createTable(workingCopy, tableName); schemaTransaction.commit(); } finally @@ -178,11 +168,33 @@ public class BranchingListTableMappingWithRanges extends AbstractBasicListTableM } else { + typeMapping = getMappingStrategy().createValueMapping(getFeature()); typeMapping.setDBField(table, LIST_VALUE); initSQLStrings(); } } + public IDBTable createTable(IDBSchema schema, String tableName) + { + IDBStore store = getMappingStrategy().getStore(); + DBType idType = store.getIDHandler().getDBType(); + int idLength = store.getIDColumnLength(); + + IDBTable table = schema.addTable(tableName); + table.addField(LIST_REVISION_ID, idType, idLength, true); + table.addField(LIST_REVISION_BRANCH, DBType.INTEGER, true); + table.addField(LIST_REVISION_VERSION_ADDED, DBType.INTEGER); + table.addField(LIST_REVISION_VERSION_REMOVED, DBType.INTEGER); + table.addField(LIST_IDX, DBType.INTEGER, true); + + // TODO think about indexes + table.addIndex(Type.NON_UNIQUE, LIST_REVISION_ID, LIST_REVISION_BRANCH, LIST_REVISION_VERSION_ADDED, LIST_REVISION_VERSION_REMOVED, LIST_IDX); + + typeMapping = getMappingStrategy().createValueMapping(getFeature()); + typeMapping.createDBField(table, LIST_VALUE); + return table; + } + private void initSQLStrings() { String tableName = getTable().getName(); @@ -312,7 +324,8 @@ public class BranchingListTableMappingWithRanges extends AbstractBasicListTableM return Collections.singleton(table); } - protected final IDBTable getTable() + @Override + public final IDBTable getTable() { return table; } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/DelegatingObjectTypeMapper.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/DelegatingObjectTypeMapper.java index 453b6c2920..ac4e7d2a81 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/DelegatingObjectTypeMapper.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/DelegatingObjectTypeMapper.java @@ -10,12 +10,14 @@ */ package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal; +import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.model.CDOClassifierRef; import org.eclipse.emf.cdo.common.protocol.CDODataInput; import org.eclipse.emf.cdo.common.protocol.CDODataOutput; import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; import org.eclipse.emf.cdo.server.db.IIDHandler; +import org.eclipse.emf.cdo.server.db.IMetaDataManager; import org.eclipse.emf.cdo.server.internal.db.IObjectTypeMapper; import org.eclipse.net4j.util.lifecycle.LifecycleUtil; @@ -71,6 +73,16 @@ public abstract class DelegatingObjectTypeMapper extends AbstractObjectTypeMappe return delegate.putObjectType(accessor, timeStamp, id, type); } + public int changeObjectType(IDBStoreAccessor accessor, EClass oldType, EClass newType) + { + IMetaDataManager metaDataManager = getMetaDataManager(); + CDOID oldClassID = metaDataManager.getMetaID(oldType, CDOBranchPoint.UNSPECIFIED_DATE); + CDOID newClassID = metaDataManager.getMetaID(newType, CDOBranchPoint.UNSPECIFIED_DATE); + doChangeObjectType(accessor, oldClassID, newClassID); + + return delegate.changeObjectType(accessor, oldType, newType); + } + public boolean removeObjectType(IDBStoreAccessor accessor, CDOID id) { doRemoveObjectType(accessor, id); @@ -125,5 +137,7 @@ public abstract class DelegatingObjectTypeMapper extends AbstractObjectTypeMappe protected abstract boolean doPutObjectType(IDBStoreAccessor accessor, CDOID id, CDOID type); + protected abstract void doChangeObjectType(IDBStoreAccessor accessor, CDOID oldType, CDOID newType); + protected abstract boolean doRemoveObjectType(IDBStoreAccessor accessor, CDOID id); } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditClassMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditClassMapping.java index 25d4309151..5589d8a460 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditClassMapping.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditClassMapping.java @@ -961,7 +961,10 @@ public class HorizontalAuditClassMapping extends AbstractHorizontalClassMapping delta.applyTo(newRevision); IListMappingDeltaSupport listMapping = (IListMappingDeltaSupport)getListMapping(delta.getFeature()); - listMapping.processDelta(accessor, id, branchId, oldVersion, oldVersion + 1, created, delta); + if (listMapping != null) + { + listMapping.processDelta(accessor, id, branchId, oldVersion, oldVersion + 1, created, delta); + } } public void visit(CDOContainerFeatureDelta delta) diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditMappingStrategy.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditMappingStrategy.java index 449da9a94a..84eecf8d45 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditMappingStrategy.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditMappingStrategy.java @@ -42,8 +42,7 @@ public class HorizontalAuditMappingStrategy extends AbstractHorizontalMappingStr return false; } - @Override - protected IClassMapping doCreateClassMapping(EClass eClass) + public IClassMapping createClassMapping(EClass eClass) { return new HorizontalAuditClassMapping(this, eClass); } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditMappingStrategyWithRanges.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditMappingStrategyWithRanges.java index cb7330b329..9bb7a6fe91 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditMappingStrategyWithRanges.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditMappingStrategyWithRanges.java @@ -35,7 +35,7 @@ public class HorizontalAuditMappingStrategyWithRanges extends HorizontalAuditMap } @Override - protected IClassMapping doCreateClassMapping(EClass eClass) + public IClassMapping createClassMapping(EClass eClass) { return new HorizontalAuditClassMapping(this, eClass); } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalBranchingClassMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalBranchingClassMapping.java index 0d7287c44f..af4cc79805 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalBranchingClassMapping.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalBranchingClassMapping.java @@ -1042,7 +1042,10 @@ public class HorizontalBranchingClassMapping extends AbstractHorizontalClassMapp delta.applyTo(newRevision); IListMappingDeltaSupport listMapping = (IListMappingDeltaSupport)getListMapping(delta.getFeature()); - listMapping.processDelta(accessor, id, targetBranch.getID(), oldVersion, newVersion, created, delta); + if (listMapping != null) + { + listMapping.processDelta(accessor, id, targetBranch.getID(), oldVersion, newVersion, created, delta); + } } public void visit(CDOContainerFeatureDelta delta) diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalBranchingMappingStrategy.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalBranchingMappingStrategy.java index fab24dc878..41c17414bc 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalBranchingMappingStrategy.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalBranchingMappingStrategy.java @@ -56,8 +56,7 @@ public class HorizontalBranchingMappingStrategy extends AbstractHorizontalMappin return false; } - @Override - protected IClassMapping doCreateClassMapping(EClass eClass) + public IClassMapping createClassMapping(EClass eClass) { return new HorizontalBranchingClassMapping(this, eClass); } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalBranchingMappingStrategyWithRanges.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalBranchingMappingStrategyWithRanges.java index 4879b8ec9e..e3f36e9175 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalBranchingMappingStrategyWithRanges.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalBranchingMappingStrategyWithRanges.java @@ -66,7 +66,7 @@ public class HorizontalBranchingMappingStrategyWithRanges extends HorizontalBran } @Override - protected IClassMapping doCreateClassMapping(EClass eClass) + public IClassMapping createClassMapping(EClass eClass) { return new HorizontalBranchingClassMapping(this, eClass); } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalMappingStrategy.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalMappingStrategy.java index bb3dbd3f9c..f3d70ec43c 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalMappingStrategy.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalMappingStrategy.java @@ -13,6 +13,7 @@ package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal; import org.eclipse.emf.cdo.common.branch.CDOBranch; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.model.CDOClassifierRef; +import org.eclipse.emf.cdo.common.model.CDOPackageUnit; import org.eclipse.emf.cdo.common.protocol.CDODataInput; import org.eclipse.emf.cdo.common.protocol.CDODataOutput; import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; @@ -25,6 +26,8 @@ import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; import org.eclipse.emf.cdo.server.db.mapping.IListMapping; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; +import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy3; +import org.eclipse.emf.cdo.server.db.mapping.INamingStrategy; import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping; import org.eclipse.emf.cdo.spi.common.commit.CDOChangeSetSegment; import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit; @@ -42,13 +45,14 @@ import org.eclipse.emf.ecore.EStructuralFeature; import java.io.IOException; import java.sql.Connection; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; /** * @author Eike Stepper */ -public class HorizontalMappingStrategy extends Lifecycle implements IMappingStrategy +public class HorizontalMappingStrategy extends Lifecycle implements IMappingStrategy3 { private Map<String, String> properties; @@ -230,6 +234,41 @@ public class HorizontalMappingStrategy extends Lifecycle implements IMappingStra return delegate.getListJoin(attrTable, listTable); } + public INamingStrategy getNamingStrategy() + { + return ((IMappingStrategy3)delegate).getNamingStrategy(); + } + + public void setNamingStrategy(INamingStrategy namingStrategy) + { + ((IMappingStrategy3)delegate).setNamingStrategy(namingStrategy); + } + + public String getUnsettableFieldName(EStructuralFeature feature) + { + return ((IMappingStrategy3)delegate).getUnsettableFieldName(feature); + } + + public boolean isMapped(EClass eClass) + { + return ((IMappingStrategy3)delegate).isMapped(eClass); + } + + public List<EClass> getMappedClasses(CDOPackageUnit[] packageUnits) + { + return ((IMappingStrategy3)delegate).getMappedClasses(packageUnits); + } + + public IClassMapping createClassMapping(EClass eClass) + { + return ((IMappingStrategy3)delegate).createClassMapping(eClass); + } + + public void clearClassMappings() + { + ((IMappingStrategy3)delegate).clearClassMappings(); + } + @Override protected void doActivate() throws Exception { diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalNonAuditClassMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalNonAuditClassMapping.java index 88f115837d..a4de6f791e 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalNonAuditClassMapping.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalNonAuditClassMapping.java @@ -592,7 +592,10 @@ public class HorizontalNonAuditClassMapping extends AbstractHorizontalClassMappi try { IListMappingDeltaSupport listMapping = (IListMappingDeltaSupport)getListMapping(feature); - listMapping.processDelta(accessor, id, branchId, oldVersion, oldVersion + 1, created, delta); + if (listMapping != null) + { + listMapping.processDelta(accessor, id, branchId, oldVersion, oldVersion + 1, created, delta); + } } catch (NewListSizeResult result) { diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalNonAuditMappingStrategy.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalNonAuditMappingStrategy.java index 0b489f46e9..4a4aa63a68 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalNonAuditMappingStrategy.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalNonAuditMappingStrategy.java @@ -63,8 +63,7 @@ public class HorizontalNonAuditMappingStrategy extends AbstractHorizontalMapping return new NonAuditFeatureMapTableMapping(this, containingClass, feature); } - @Override - protected IClassMapping doCreateClassMapping(EClass eClass) + public IClassMapping createClassMapping(EClass eClass) { return new HorizontalNonAuditClassMapping(this, eClass); } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeCache.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeCache.java index ded575c320..e27bb4ff1d 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeCache.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeCache.java @@ -49,6 +49,12 @@ public class ObjectTypeCache extends DelegatingObjectTypeMapper } @Override + protected void doChangeObjectType(IDBStoreAccessor accessor, CDOID oldType, CDOID newType) + { + memoryCache.clear(); + } + + @Override protected boolean doRemoveObjectType(IDBStoreAccessor accessor, CDOID id) { return memoryCache.remove(id) != null; diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeTable.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeTable.java index 53e2ce347b..513b3d9984 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeTable.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeTable.java @@ -13,6 +13,7 @@ */ package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal; +import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.model.CDOClassifierRef; import org.eclipse.emf.cdo.common.protocol.CDODataInput; @@ -20,6 +21,7 @@ import org.eclipse.emf.cdo.common.protocol.CDODataOutput; import org.eclipse.emf.cdo.server.db.IDBStore; import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; import org.eclipse.emf.cdo.server.db.IIDHandler; +import org.eclipse.emf.cdo.server.db.IMetaDataManager; import org.eclipse.emf.cdo.server.internal.db.CDODBSchema; import org.eclipse.emf.cdo.spi.server.InternalRepository; @@ -55,6 +57,8 @@ public class ObjectTypeTable extends AbstractObjectTypeMapper implements IMappin private String sqlInsert; + private String sqlUpdate; + private String sqlSelect; public ObjectTypeTable() @@ -142,6 +146,35 @@ public class ObjectTypeTable extends AbstractObjectTypeMapper implements IMappin } } + public int changeObjectType(IDBStoreAccessor accessor, EClass oldType, EClass newType) + { + IDBStore store = getMappingStrategy().getStore(); + IIDHandler idHandler = store.getIDHandler(); + IMetaDataManager metaDataManager = getMetaDataManager(); + IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlUpdate, ReuseProbability.HIGH); + + try + { + idHandler.setCDOID(stmt, 1, metaDataManager.getMetaID(newType, CDOBranchPoint.UNSPECIFIED_DATE)); + idHandler.setCDOID(stmt, 2, metaDataManager.getMetaID(oldType, CDOBranchPoint.UNSPECIFIED_DATE)); + + if (DBUtil.isTracerEnabled()) + { + DBUtil.trace(stmt.toString()); + } + + return stmt.executeUpdate(); + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + DBUtil.close(stmt); + } + } + public final boolean removeObjectType(IDBStoreAccessor accessor, CDOID id) { IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); @@ -242,6 +275,7 @@ public class ObjectTypeTable extends AbstractObjectTypeMapper implements IMappin sqlSelect = "SELECT " + ATTRIBUTES_CLASS + " FROM " + table + " WHERE " + ATTRIBUTES_ID + "=?"; sqlInsert = "INSERT INTO " + table + "(" + ATTRIBUTES_ID + "," + ATTRIBUTES_CLASS + "," + ATTRIBUTES_CREATED + ") VALUES (?, ?, ?)"; + sqlUpdate = "UPDATE " + table + " SET " + ATTRIBUTES_CLASS + "=? WHERE " + ATTRIBUTES_CLASS + "=?"; sqlDelete = "DELETE FROM " + table + " WHERE " + ATTRIBUTES_ID + "=?"; } |