diff options
84 files changed, 6126 insertions, 7370 deletions
diff --git a/features/org.eclipse.emf.cdo.server.product-feature/rootfiles/configuration/cdo-server.xml b/features/org.eclipse.emf.cdo.server.product-feature/rootfiles/configuration/cdo-server.xml index 3511572e8f..7cde0d1348 100644 --- a/features/org.eclipse.emf.cdo.server.product-feature/rootfiles/configuration/cdo-server.xml +++ b/features/org.eclipse.emf.cdo.server.product-feature/rootfiles/configuration/cdo-server.xml @@ -1,10 +1,14 @@ <?xml version="1.0" encoding="UTF-8"?> <cdoServer> - <!--acceptor type="http"/ --> + <!-- + <acceptor type="http"/> + --> <acceptor type="tcp" listenAddr="0.0.0.0" port="2036"> - <!-- negotiator type="challenge" description="/temp/users.db"/ --> + <!-- + <negotiator type="challenge" description="/temp/users.db"/> + --> </acceptor> <repository name="repo1"> @@ -21,39 +25,33 @@ <property name="toOneReferences" value="LIKE_ATTRIBUTES"/> </mappingStrategy> - <!-- Old setting <jdbcDelegate type="statement" /> - is now replaced by preparedStatement: --> - <jdbcDelegate type="preparedStatement" > - <!-- to explicitly force prepared statement caching (e.g., if statement pooling is not supported - by the JDBC driver, use - <property name="cacheStatements" value="enabled" /> - Else, the implicit default is: - <property name="cacheStatements" value="guess" /> - Which guesses the correct setting based on the JDBC driver's metadata. - Also supported is the third setting "disabled". - --> - </jdbcDelegate> <dbAdapter name="derby-embedded"/> <dataSource class="org.apache.derby.jdbc.EmbeddedDataSource" databaseName="/temp/cdodb1" createDatabase="create"/> - <!--<dbAdapter name="hsqldb"/> + <!-- + <dbAdapter name="hsqldb"/> <dataSource class="org.eclipse.net4j.db.hsqldb.HSQLDBDataSource" database="jdbc:hsqldb:mem:cdodb1" - user="sa"/>--> + user="sa"/> + --> - <!--<dbAdapter name="mysql"/> + <!-- + <dbAdapter name="mysql"/> <dataSource class="com.mysql.jdbc.jdbc2.optional.MysqlDataSource" url="jdbc:mysql://localhost/cdodb1" - user="sa"/>--> + user="sa"/> + --> - <!--<dbAdapter name="postgresql"/> + <!-- + <dbAdapter name="postgresql"/> <dataSource class="org.postgresql.ds.PGSimpleDataSource" url="jdbc:postgresql://localhost:5432/cdo" databaseName="cdo" user="cdo" - password="cdo"/>--> + password="cdo"/> + --> </store> </repository> 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 51ca5023cf..2cf0fda3bd 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 @@ -17,4 +17,5 @@ Export-Package: org.eclipse.emf.cdo.server.db;version="2.0.0", org.eclipse.emf.cdo.server.internal.db;version="2.0.0";x-friends:="org.eclipse.emf.cdo.tests", org.eclipse.emf.cdo.server.internal.db.bundle;version="2.0.0";x-internal:=true, org.eclipse.emf.cdo.server.internal.db.jdbc;version="2.0.0";x-friends:="org.eclipse.emf.cdo.tests", - org.eclipse.emf.cdo.server.internal.db.mapping;version="2.0.0";x-friends:="org.eclipse.emf.cdo.tests" + org.eclipse.emf.cdo.server.internal.db.mapping;version="2.0.0";x-friends:="org.eclipse.emf.cdo.tests", + org.eclipse.emf.cdo.server.internal.db.mapping.horizontal;version="2.0.0";x-friends:="org.eclipse.emf.cdo.tests" diff --git a/plugins/org.eclipse.emf.cdo.server.db/plugin.xml b/plugins/org.eclipse.emf.cdo.server.db/plugin.xml index acd168a01a..4a30c67ec8 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/plugin.xml +++ b/plugins/org.eclipse.emf.cdo.server.db/plugin.xml @@ -14,7 +14,6 @@ <plugin> <extension-point id="mappingStrategies" name="CDO Mapping Strategies" schema="schema/mappingStrategies.exsd"/> - <extension-point id="jdbcDelegateProviders" name="CDO JDBC Delegate Providers" schema="schema/delegateProviders.exsd"/> <extension point="org.eclipse.emf.cdo.server.storeFactories"> @@ -27,25 +26,12 @@ <extension point="org.eclipse.emf.cdo.server.db.mappingStrategies"> <mappingStrategy - class="org.eclipse.emf.cdo.server.internal.db.mapping.HorizontalMappingStrategy" + class="org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalAuditMappingStrategy" type="horizontal"> </mappingStrategy> <mappingStrategy - class="org.eclipse.emf.cdo.server.internal.db.mapping.VerticalMappingStrategy" - type="vertical"> + class="org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalNonAuditMappingStrategy" + type="horizontalNonAudit"> </mappingStrategy> </extension> - - <extension - point="org.eclipse.emf.cdo.server.db.jdbcDelegateProviders"> - <jdbcDelegateProvider - class="org.eclipse.emf.cdo.server.internal.db.jdbc.StatementJDBCDelegateProvider" - type="statement"> - </jdbcDelegateProvider> - <jdbcDelegateProvider - class="org.eclipse.emf.cdo.server.internal.db.jdbc.PreparedStatementJDBCDelegateProvider" - type="preparedStatement"> - </jdbcDelegateProvider> - </extension> - </plugin> diff --git a/plugins/org.eclipse.emf.cdo.server.db/schema/delegateProviders.exsd b/plugins/org.eclipse.emf.cdo.server.db/schema/delegateProviders.exsd deleted file mode 100644 index 048126191d..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/schema/delegateProviders.exsd +++ /dev/null @@ -1,109 +0,0 @@ -<?xml version='1.0' encoding='UTF-8'?> -<!-- Schema file written by PDE --> -<schema targetNamespace="org.eclipse.emf.cdo.server.db" xmlns="http://www.w3.org/2001/XMLSchema"> -<annotation> - <appinfo> - <meta.schema plugin="org.eclipse.emf.cdo.server.db" id="jdbcDelegateProviders" name="CDO JDBC Delegate Providers"/> - </appinfo> - <documentation> - [Enter description of this extension point.] - </documentation> - </annotation> - - <element name="extension"> - <annotation> - <appinfo> - <meta.element /> - </appinfo> - </annotation> - <complexType> - <sequence> - <element ref="jdbcDelegateProvider" minOccurs="1" maxOccurs="unbounded"/> - </sequence> - <attribute name="point" type="string" use="required"> - <annotation> - <documentation> - - </documentation> - </annotation> - </attribute> - <attribute name="id" type="string"> - <annotation> - <documentation> - - </documentation> - </annotation> - </attribute> - <attribute name="name" type="string"> - <annotation> - <documentation> - - </documentation> - <appinfo> - <meta.attribute translatable="true"/> - </appinfo> - </annotation> - </attribute> - </complexType> - </element> - - <element name="jdbcDelegateProvider"> - <complexType> - <attribute name="type" type="string" use="required"> - <annotation> - <documentation> - - </documentation> - </annotation> - </attribute> - <attribute name="class" type="string" use="required"> - <annotation> - <documentation> - - </documentation> - <appinfo> - <meta.attribute kind="java" basedOn=":org.eclipse.emf.cdo.server.db.IJDBCDelegateProvider"/> - </appinfo> - </annotation> - </attribute> - </complexType> - </element> - - <annotation> - <appinfo> - <meta.section type="since"/> - </appinfo> - <documentation> - [Enter the first release in which this extension point appears.] - </documentation> - </annotation> - - <annotation> - <appinfo> - <meta.section type="examples"/> - </appinfo> - <documentation> - [Enter extension point usage example here.] - </documentation> - </annotation> - - <annotation> - <appinfo> - <meta.section type="apiInfo"/> - </appinfo> - <documentation> - [Enter API information here.] - </documentation> - </annotation> - - <annotation> - <appinfo> - <meta.section type="implementation"/> - </appinfo> - <documentation> - [Enter information about supplied implementation of this extension point.] - </documentation> - </annotation> - - -</schema> 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 06a2caebec..9d43f88d09 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 @@ -7,6 +7,9 @@ * * Contributors: * Eike Stepper - initial API and implementation + * Stefan Winkler - 271444: [DB] Multiple refactorings + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 + * */ package org.eclipse.emf.cdo.server.db; @@ -14,21 +17,29 @@ import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.id.CDOIDUtil; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; import org.eclipse.emf.cdo.server.internal.db.DBStore; +import org.eclipse.emf.cdo.server.internal.db.SmartPreparedStatementCache; import org.eclipse.emf.cdo.server.internal.db.bundle.OM; -import org.eclipse.emf.cdo.server.internal.db.jdbc.PreparedStatementJDBCDelegateProvider; -import org.eclipse.emf.cdo.server.internal.db.jdbc.StatementJDBCDelegateProvider; -import org.eclipse.emf.cdo.server.internal.db.mapping.HorizontalMappingStrategy; +import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalAuditMappingStrategy; +import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalNonAuditMappingStrategy; +import org.eclipse.net4j.db.DBUtil; import org.eclipse.net4j.db.IDBAdapter; import org.eclipse.net4j.db.IDBConnectionProvider; import org.eclipse.net4j.util.ObjectUtil; import org.eclipse.net4j.util.WrappedException; +import org.eclipse.net4j.util.om.trace.ContextTracer; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.Platform; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + /** * @author Eike Stepper */ @@ -37,12 +48,12 @@ public final class CDODBUtil /** * @since 2.0 */ - public static final String EXT_POINT_MAPPING_STRATEGIES = "mappingStrategies"; + public static final int DEFAULT_STATEMENT_CACHE_CAPACITY = 200; /** * @since 2.0 */ - public static final String EXT_POINT_JDBC_DELEGATE_PROVIDERS = "jdbcDelegateProviders"; + public static final String EXT_POINT_MAPPING_STRATEGIES = "mappingStrategies"; private CDODBUtil() { @@ -52,13 +63,12 @@ public final class CDODBUtil * @since 2.0 */ public static IDBStore createStore(IMappingStrategy mappingStrategy, IDBAdapter dbAdapter, - IDBConnectionProvider dbConnectionProvider, IJDBCDelegateProvider delegateProvider) + IDBConnectionProvider dbConnectionProvider) { DBStore store = new DBStore(); store.setMappingStrategy(mappingStrategy); store.setDBAdapter(dbAdapter); store.setDbConnectionProvider(dbConnectionProvider); - store.setJDBCDelegateProvider(delegateProvider); mappingStrategy.setStore(store); return store; } @@ -68,23 +78,15 @@ public final class CDODBUtil */ public static IMappingStrategy createHorizontalMappingStrategy() { - return new HorizontalMappingStrategy(); - } - - /** - * @since 2.0 - */ - public static IJDBCDelegateProvider createStatementJDBCDelegateProvider() - { - return new StatementJDBCDelegateProvider(); + return new HorizontalAuditMappingStrategy(); } /** * @since 2.0 */ - public static IJDBCDelegateProvider createPreparedStatementJDBCDelegateProvider() + public static IMappingStrategy createHorizontalNonAuditMappingStrategy() { - return new PreparedStatementJDBCDelegateProvider(); + return new HorizontalNonAuditMappingStrategy(); } /** @@ -121,71 +123,172 @@ public final class CDODBUtil } /** + * Get the long value of a CDOID (by delegating to {@link CDOIDUtil#getLong(org.eclipse.emf.cdo.common.id.CDOID)}) In + * addition, provide a check for external IDs which are not supported by the DBStore + * + * @param id + * the ID to convert to long + * @return the long value of the ID + * @throws IllegalArgumentException + * if the ID is not convertibla * @since 2.0 */ - public static IJDBCDelegateProvider createDelegateProvider(String type) + public static long getLong(CDOID id) { - IExtensionRegistry registry = Platform.getExtensionRegistry(); - IConfigurationElement[] elements = registry.getConfigurationElementsFor(OM.BUNDLE_ID, - EXT_POINT_JDBC_DELEGATE_PROVIDERS); - for (final IConfigurationElement element : elements) + if (id != null && id.getType() == CDOID.Type.EXTERNAL_OBJECT) + { + throw new IllegalArgumentException("DBStore does not support external references: " + id); + } + + return CDOIDUtil.getLong(id); + } + + /** + * Execute update on the given prepared statement and handle common cases of return values. + * + * @param stmt + * the prepared statement + * @param exactlyOne + * if <code>true</code>, the update count is checked to be <code>1</code>. Else the update result is only + * checked so that the update was successful (i.e. result code != Statement.EXECUTE_FAILED). + * @return the update count / execution result as returned by {@link PreparedStatement#executeUpdate()}. Can be used + * by the caller to perform more advanced checks. + * @throws SQLException + * if {@link PreparedStatement#executeUpdate()} throws it. + * @throws IllegalStateException + * if the check indicated by <code>excatlyOne</code> indicates an error. + * @since 2.0 + */ + public static int sqlUpdate(PreparedStatement stmt, boolean exactlyOne) throws SQLException + { + DBUtil.trace(stmt.toString()); + int result = stmt.executeUpdate(); + + // basic check of update result + if (exactlyOne && result != 1) { - if ("jdbcDelegateProvider".equals(element.getName())) + throw new IllegalStateException(stmt.toString() + " returned Update count " + result + " (expected: 1)"); + } + + if (result == Statement.EXECUTE_FAILED) + { + throw new IllegalStateException(stmt.toString() + " returned EXECUTE_FAILED."); + } + + return result; + } + + /** + * For debugging purposes ONLY! + * + * @deprecated Should only be used when debugging. + * @since 2.0 + */ + @Deprecated + public static void sqlDump(Connection conn, String sql) + { + ContextTracer TRACER = new ContextTracer(OM.DEBUG, CDODBUtil.class); + ResultSet rs = null; + try + { + TRACER.format("Dumping output of {0}", sql); + rs = conn.createStatement().executeQuery(sql); + int numCol = rs.getMetaData().getColumnCount(); + + StringBuilder row = new StringBuilder(); + for (int c = 1; c <= numCol; c++) { - String typeAttr = element.getAttribute("type"); - if (ObjectUtil.equals(typeAttr, type)) + row.append(String.format("%10s | ", rs.getMetaData().getColumnLabel(c))); + } + + TRACER.trace(row.toString()); + + row = new StringBuilder(); + for (int c = 1; c <= numCol; c++) + { + row.append("-----------+--"); + } + + TRACER.trace(row.toString()); + + while (rs.next()) + { + row = new StringBuilder(); + for (int c = 1; c <= numCol; c++) { - try - { - return (IJDBCDelegateProvider)element.createExecutableExtension("class"); - } - catch (CoreException ex) - { - throw WrappedException.wrap(ex); - } + row.append(String.format("%10s | ", rs.getString(c))); } + + TRACER.trace(row.toString()); } - } - return null; + row = new StringBuilder(); + for (int c = 1; c <= numCol; c++) + { + row.append("-----------+-"); + } + + TRACER.trace(row.toString()); + } + catch (SQLException ex) + { + // NOP + } + finally + { + if (rs != null) + { + try + { + rs.close(); + } + catch (SQLException ex) + { + // NOP + } + } + } } /** - * Get the long value of a CDOID (by delegating to {@link CDOIDUtil#getLong(org.eclipse.emf.cdo.common.id.CDOID)}) In - * addition, provide a check for external IDs which are not supported by the DBStore + * For debugging purposes ONLY! * - * @param id - * the ID to convert to long - * @return the long value of the ID - * @throws IllegalArgumentException - * if the ID is not convertibla + * @deprecated Should only be used when debugging. * @since 2.0 */ - public static long getLong(CDOID id) + @Deprecated + public static void sqlDump(IDBConnectionProvider connectionProvider, String sql) { - if (id != null && id.getType() == CDOID.Type.EXTERNAL_OBJECT) + Connection connection = connectionProvider.getConnection(); + + try { - throw new IllegalArgumentException("DBStore does not support external references: " + id); + sqlDump(connection, sql); + } + finally + { + DBUtil.close(connection); } + } - return CDOIDUtil.getLong(id); + /** + * Creates a prepared statement cache with the {@link CDODBUtil#DEFAULT_STATEMENT_CACHE_CAPACITY default capacity}. + * + * @since 2.0 + * @see CDODBUtil#createStatementCache(int) + */ + public static IPreparedStatementCache createStatementCache() + { + return createStatementCache(DEFAULT_STATEMENT_CACHE_CAPACITY); } - // public static CDODBStoreManager getStoreManager(IDBAdapter dbAdapter, - // DataSource dataSource) - // { - // CDODBStoreManager storeManager = new CDODBStoreManager(dbAdapter, - // dataSource); - // storeManager.initDatabase(); - // return storeManager; - // } - // - // public static CDODBStoreManager getStoreManager() - // { - // Properties properties = OM.BUNDLE.getConfigProperties(); - // String adapterName = properties.getProperty("store.adapterName", "derby-embedded"); - // IDBAdapter dbAdapter = DBUtil.getDBAdapter(adapterName); - // DataSource dataSource = DBUtil.createDataSource(properties, "datasource"); - // return getStoreManager(dbAdapter, dataSource); - // } + /** + * Creates a prepared statement cache with the given capacity. + * + * @since 2.0 + */ + public static IPreparedStatementCache createStatementCache(int capacity) + { + return new SmartPreparedStatementCache(capacity); + } } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStore.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStore.java index 3a51ec57b7..0613a904f4 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStore.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStore.java @@ -7,6 +7,8 @@ * * Contributors: * Eike Stepper - initial API and implementation + * Stefan Winkler - 271444: [DB] Multiple refactorings + * https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 */ package org.eclipse.emf.cdo.server.db; @@ -19,11 +21,8 @@ import org.eclipse.net4j.db.IDBAdapter; import org.eclipse.net4j.db.IDBConnectionProvider; import org.eclipse.net4j.db.ddl.IDBSchema; -import org.eclipse.emf.ecore.EModelElement; - /** * @author Eike Stepper - * @noimplement This interface is not intended to be implemented by clients. */ public interface IDBStore extends IStore { @@ -44,20 +43,17 @@ public interface IDBStore extends IStore /** * @since 2.0 */ - public long getMetaID(EModelElement modelElement); - - /** - * @since 2.0 - */ - public EModelElement getMetaInstance(long id); + public IDBStoreAccessor getReader(ISession session); /** * @since 2.0 */ - public IDBStoreAccessor getReader(ISession session); + public IDBStoreAccessor getWriter(ITransaction transaction); /** + * Get the meta data manager associated with this DBStore. + * * @since 2.0 */ - public IDBStoreAccessor getWriter(ITransaction transaction); + public IMetaDataManager getMetaDataManager(); } 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 53eeb07cfd..4837553cf7 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 @@ -4,7 +4,7 @@ * 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 */ @@ -12,16 +12,19 @@ package org.eclipse.emf.cdo.server.db; import org.eclipse.emf.cdo.server.IStoreAccessor; +import java.sql.Connection; + /** * @author Eike Stepper - * @noimplement This interface is not intended to be implemented by clients. */ public interface IDBStoreAccessor extends IStoreAccessor { public IDBStore getStore(); + public Connection getConnection(); + /** * @since 2.0 */ - public IJDBCDelegate getJDBCDelegate(); + public IPreparedStatementCache getStatementCache(); } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreChunkReader.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreChunkReader.java index a987beccc8..ff4fd4e613 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreChunkReader.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IDBStoreChunkReader.java @@ -14,7 +14,6 @@ import org.eclipse.emf.cdo.server.IStoreChunkReader; /** * @author Eike Stepper - * @noimplement This interface is not intended to be implemented by clients. */ public interface IDBStoreChunkReader extends IStoreChunkReader { diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IJDBCDelegate.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IJDBCDelegate.java deleted file mode 100644 index e456e1fc40..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IJDBCDelegate.java +++ /dev/null @@ -1,181 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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: - * Stefan Winkler - initial API and implementation - * Eike Stepper - maintenance - * Stefan Winkler - https://bugs.eclipse.org/bugs/show_bug.cgi?id=259402 - */ -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.IStoreChunkReader.Chunk; -import org.eclipse.emf.cdo.server.db.mapping.IAttributeMapping; -import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; -import org.eclipse.emf.cdo.server.db.mapping.IReferenceMapping; -import org.eclipse.emf.cdo.server.internal.db.jdbc.AbstractJDBCDelegate; -import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; - -import org.eclipse.net4j.db.IDBConnectionProvider; -import org.eclipse.net4j.util.collection.Pair; -import org.eclipse.net4j.util.om.monitor.OMMonitor; - -import java.sql.PreparedStatement; -import java.sql.Statement; -import java.util.List; - -/** - * Interface for all JDBC related activities regarding revisions. - * - * @author Stefan Winkler - * @since 2.0 - * @noimplement This interface is not intended to be implemented by clients. Please extend the abstract class - * {@link AbstractJDBCDelegate} instead. - */ -public interface IJDBCDelegate extends IDBConnectionProvider -{ - // -------------------------------------------------------------- - // General methods - // -------------------------------------------------------------- - - /** - * Get the one omnipresent statement object of this JDBC delegate - */ - public Statement getStatement(); - - /** - * Get a prepared statement. The caller is responsible of closing it. - */ - public PreparedStatement getPreparedStatement(String sql); - - public void setStoreAccessor(IDBStoreAccessor storeAccessor); - - /** - * Do any outstanding writes (e.g. execute batches). Called any number of times - but at least once immediately before - * commit(). - * - * @see IStoreAccessor#write(org.eclipse.emf.cdo.server.IStoreAccessor.CommitContext, OMMonitor) - */ - public void flush(OMMonitor monitor); - - /** - * Do a commit on the JDBC connection. - */ - public void commit(OMMonitor monitor); - - /** - * Do a rollback on the JDBC connection. - */ - public void rollback(); - - // -------------------------------------------------------------- - // Writing Revisions / Attributes - // -------------------------------------------------------------- - - /** - * Insert an attribute row. - */ - public void insertAttributes(InternalCDORevision revision, IClassMapping classMapping); - - /** - * Update an attribute row. - */ - public void updateAttributes(InternalCDORevision revision, IClassMapping classMapping); - - /** - * Update an attribute row. - */ - public void updateAttributes(CDOID id, int newVersion, long created, - List<Pair<IAttributeMapping, Object>> attributeChanges, IClassMapping classMapping); - - /** - * Update an attribute row (including containment and resource attributes). - */ - public void updateAttributes(CDOID id, int newVersion, long created, CDOID newContainerId, - int newContainingFeatureId, CDOID newResourceId, List<Pair<IAttributeMapping, Object>> attributeChanges, - IClassMapping classMapping); - - /** - * Set the revised date of a specific revision's previous version. - */ - public void updateRevisedForReplace(InternalCDORevision revision, IClassMapping classMapping); - - /** - * Set the revised date of all unrevised rows of cdoid - */ - public void updateRevisedForDetach(CDOID id, long revised, IClassMapping classMapping); - - /** - * Remove an attribute row. - */ - public void deleteAttributes(CDOID id, IClassMapping classMapping); - - // -------------------------------------------------------------- - // Writing References - // -------------------------------------------------------------- - - /** - * Insert a reference row. - */ - public void insertReference(CDOID id, int version, int index, CDOID targetId, IReferenceMapping referenceMapping); - - /** - * Insert a reference row shifting all subsequent indices one position up. - */ - public void insertReferenceRow(CDOID id, int newVersion, int index, CDOID value, IReferenceMapping referenceMapping); - - /** - * Move one reference row shifting all subsequent indices in between accordingly. - */ - public void moveReferenceRow(CDOID id, int newVersion, int oldPosition, int newPosition, - IReferenceMapping referenceMapping); - - /** - * Remove a reference row shifting all subsequent indices one position down. - */ - public void removeReferenceRow(CDOID id, int index, int newVersion, IReferenceMapping referenceMapping); - - /** - * Update the value of a reference row. - */ - public void updateReference(CDOID id, int newVersion, int index, CDOID value, IReferenceMapping referenceMapping); - - /** - * Delete all reference rows of a cdoid. - */ - public void deleteReferences(CDOID id, IReferenceMapping referenceMapping); - - /** - * Update the version number of all references of a CDOID to newVersion. - */ - public void updateReferenceVersion(CDOID id, int newVersion, IReferenceMapping referenceMapping); - - // -------------------------------------------------------------- - // Reading - // -------------------------------------------------------------- - - /** - * Select a revision's attributes - * - * @return <code>true</code> if the revision attributes have been successfully loaded.<br> - * <code>false</code> if the revision does not exist in the database. - */ - public boolean selectRevisionAttributes(InternalCDORevision revision, IClassMapping classMapping, String where); - - /** - * Select a revision's references (or a part thereof) - */ - public void selectRevisionReferences(InternalCDORevision revision, IReferenceMapping referenceMapping, - int referenceChunk); - - /** - * Select a revision's reference's chunks - */ - public void selectRevisionReferenceChunks(IDBStoreChunkReader chunkReader, List<Chunk> chunks, - IReferenceMapping referenceMapping, String where); -} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IJDBCDelegateProvider.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IJDBCDelegateProvider.java deleted file mode 100644 index 4aec6409eb..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IJDBCDelegateProvider.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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: - * Stefan Winkler - initial API and implementation - * Eike Stepper - maintenance - */ -package org.eclipse.emf.cdo.server.db; - -import java.util.Map; - -/** - * Wraps the creation of JDBCDelegates. - * - * @author Stefan Winkler - * @since 2.0 - */ -public interface IJDBCDelegateProvider -{ - /** - * Creates and returns a JDBC delegate. - * <p> - * This is part of the org.eclipse.emf.cdo.server.db.jdbcDelegateProviders extension point. - */ - public IJDBCDelegate getJDBCDelegate(); - - /** - * Set configuration properties - */ - public void setProperties(Map<String, String> properties); -} 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 new file mode 100644 index 0000000000..247b0916af --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IMetaDataManager.java @@ -0,0 +1,96 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 + * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 + */ +package org.eclipse.emf.cdo.server.db; + +import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit; + +import org.eclipse.net4j.db.DBType; +import org.eclipse.net4j.util.om.monitor.OMMonitor; + +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EModelElement; +import org.eclipse.emf.ecore.EPackage; + +import java.sql.Connection; +import java.util.Collection; + +/** + * @author Eike Stepper + * @since 2.0 + */ +public interface IMetaDataManager +{ + /** + * Returns the meta ID of the given {@link EModelElement}. <code> getMetaID(getMetaInstance(x))</code> yields + * <code>x</code> + * + * @param modelElement + * the element + * @return the corresponding ID + * @since 2.0 + */ + public long getMetaID(EModelElement modelElement); + + /** + * Returns the {@link EModelElement} referred to by the given ID. <code> getMetaInstance(getMetaID(m))</code> yields + * <code>m</code> + * + * @since 2.0 + */ + public EModelElement getMetaInstance(long id); + + /** + * Loads a package unit from the database. + * + * @param connection + * the DB connection to read from. + * @param packageUnit + * the package unit to load. + * @return the loaded package unit. + * @since 2.0 + */ + public EPackage[] loadPackageUnit(Connection connection, InternalCDOPackageUnit packageUnit); + +/** + * Reads information about package units present in the database. + * @param connection the DB connection to read from. + * @return a collection of package unit information records which can be + * passed to {@link IMetaDataManager#loadPackageUnit(Connection, InternalCDOPackageUnit)) + * in order to read the EPackage. + * + * @since 2.0 + */ + public Collection<InternalCDOPackageUnit> readPackageUnits(Connection connection); + + /** + * Write package units to the database. + * + * @param connection + * the DB connection to write to. + * @param packageUnits + * the package units to write. + * @param monitor + * the monitor to indicate progress. + * @since 2.0 + */ + public void writePackageUnits(Connection connection, InternalCDOPackageUnit[] packageUnits, OMMonitor monitor); + + /** + * Get the DB type associated with the given {@link EClassifier}. + * + * @param eType + * the type to look up. + * @return the {@link DBType} of the given {@link EClassifier}. + * @since 2.0 + */ + public DBType getDBType(EClassifier eType); +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IObjectTypeCache.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IObjectTypeCache.java index 152eb82ca8..b7f86154c5 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IObjectTypeCache.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IObjectTypeCache.java @@ -7,6 +7,7 @@ * * Contributors: * Eike Stepper - initial API and implementation + * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 */ package org.eclipse.emf.cdo.server.db; @@ -15,6 +16,8 @@ import org.eclipse.emf.cdo.common.model.CDOClassifierRef; import org.eclipse.emf.ecore.EClass; +import java.sql.Connection; + /** * @author Eike Stepper */ @@ -34,4 +37,14 @@ public interface IObjectTypeCache * @since 2.0 */ public void removeObjectType(IDBStoreAccessor accessor, CDOID id); + + /** + * Return the maximum object id managed by this cache. + * + * @param connection + * the DB connection to use. + * @return the maximum object id. + * @since 2.0 + */ + public long getMaxId(Connection connection); } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IPreparedStatementCache.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IPreparedStatementCache.java new file mode 100644 index 0000000000..256d50fa28 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/IPreparedStatementCache.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 + * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 + */ +package org.eclipse.emf.cdo.server.db; + +import java.sql.Connection; +import java.sql.PreparedStatement; + +/** + * @author Stefan Winkler + * @since 2.0 + */ +public interface IPreparedStatementCache +{ + public void setConnection(Connection connection); + + public PreparedStatement getPreparedStatement(String sql, ReuseProbability reuseProbability); + + public void releasePreparedStatement(PreparedStatement ps); + + /** + * An enum for the degree of probability to which a prepared statement is reused later on. This is used for managing + * the cache of prepared statements so that statements which are more likely reused are kept in the cache longer. Rule + * of thumb: + * <ul> + * <li>For global statements which are used regularly (such as lookup object in cdo_objects) use {@value #MAX}. + * <li>For constant object-specific statements which are used regularly use {@value #HIGH}. + * <li>For object-specific statements which are assembled from constants which are used regularly use {@value #MEDIUM}. + * <li>For all other dynamic statements, like queries, use {@value #LOW} + * </ul> + * + * @author Stefan Winkler + * @since 2.0 + */ + public static enum ReuseProbability + { + MAX, HIGH, MEDIUM, LOW; + } +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IAttributeMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IAttributeMapping.java deleted file mode 100644 index aee4967bbf..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IAttributeMapping.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 - * Stefan Winkler - https://bugs.eclipse.org/bugs/show_bug.cgi?id=259402 - */ -package org.eclipse.emf.cdo.server.db.mapping; - -import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; - -import org.eclipse.net4j.db.ddl.IDBField; - -import java.sql.ResultSet; - -/** - * @author Eike Stepper - * @since 2.0 - */ -public interface IAttributeMapping extends IFeatureMapping -{ - public IDBField getField(); - - public void appendValue(StringBuilder builder, InternalCDORevision revision); - - public void appendValue(StringBuilder builder, Object value); - - public void extractValue(ResultSet resultSet, int column, InternalCDORevision revision); - - public Object getRevisionValue(InternalCDORevision revision); -} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMapping.java index 7877c715ed..2367cf8add 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMapping.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMapping.java @@ -4,77 +4,125 @@ * 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 - * Stefan Winkler - https://bugs.eclipse.org/bugs/show_bug.cgi?id=259402 + * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 */ package org.eclipse.emf.cdo.server.db.mapping; import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; -import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta; import org.eclipse.net4j.db.ddl.IDBTable; +import org.eclipse.net4j.util.ImplementationError; import org.eclipse.net4j.util.om.monitor.OMMonitor; -import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EStructuralFeature; -import java.util.List; -import java.util.Set; +import java.sql.PreparedStatement; +import java.util.Collection; /** + * Basic interface for class mappings. + * * @author Eike Stepper + * @author Stefan Winkler * @since 2.0 */ public interface IClassMapping { - public IMappingStrategy getMappingStrategy(); - - public EClass getEClass(); - - public IDBTable getTable(); - - public Set<IDBTable> getAffectedTables(); - - public boolean hasFullRevisionInfo(); - - public IFeatureMapping getFeatureMapping(EStructuralFeature feature); - - public List<IAttributeMapping> getAttributeMappings(); - - public List<IReferenceMapping> getReferenceMappings(); - - public IAttributeMapping getAttributeMapping(EStructuralFeature feature); - - public IReferenceMapping getReferenceMapping(EStructuralFeature feature); + /** + * Returns all DB tables which are used by this class and all its contained features. + * + * @return a collection of all tables of this class and all its contained features. + */ + public Collection<IDBTable> getDBTables(); - public void writeRevision(IDBStoreAccessor accessor, InternalCDORevision revision, OMMonitor monitor); + /** + * Get the mapping of the many-valued feature. + * + * @param feature + * the feature for which the mapping should be returned. <code>feature.isMany()</code> has to be + * <code>true</code>. + * @return the list mapping corresponding to the feature. + */ + public IListMapping getListMapping(EStructuralFeature feature); - public void writeRevisionDelta(IDBStoreAccessor accessor, InternalCDORevisionDelta delta, long created, - OMMonitor monitor); + /** + * Read the current version of a revision. + * + * @param dbStoreAccessor + * the accessor to use. + * @param revision + * the revision object into which the data should be read. The revision has to be have its ID set to the + * requested object's ID. The version is ignored, as the version parameter is used to determine the version + * to be read. + * @param listChunk + * the chunk size to read attribute lists. + * @return <code>true</code>, if the revision has been found and read correctly. <code>false</code> if the revision + * could not be found. In this case, the content of <code>revision</code> is undefined. + */ + public boolean readRevision(IDBStoreAccessor dbStoreAccessor, InternalCDORevision revision, int listChunk); - public void detachObject(IDBStoreAccessor accessor, CDOID id, long revised, OMMonitor monitor); + /** + * Write the revision data to the database. + * + * @param dbStoreAccessor + * the accessor to use. + * @param revision + * the revision to write. + * @param monitor + * the monitor to indicate progress. + */ + public void writeRevision(IDBStoreAccessor dbStoreAccessor, InternalCDORevision revision, OMMonitor monitor); /** - * @return <code>true</code> if the revision has been loaded sucessfully.<br> - * <code>false</code> if the revision does not exist in the DB. + * Removes an object from the database. In the case of auditing support the object is just marked as revised, else it + * it permanently deleted. + * + * @param dbStoreAccessor + * the accessor to use. + * @param id + * the ID of the object to remove. + * @param revised + * the timeStamp when this object became detached. + * @param monitor + * the monitor to indicate progress. */ - public boolean readRevision(IDBStoreAccessor accessor, InternalCDORevision revision, int referenceChunk); + public void detachObject(IDBStoreAccessor dbStoreAccessor, CDOID id, long revised, OMMonitor monitor); /** - * @return <code>true</code> if the revision has been loaded sucessfully.<br> - * <code>false</code> if the revision does not exist in the DB. + * Create a prepared statement which returns all IDs of instances of the corresponding class. + * + * @param accessor + * the accessor to use to create the statement + * @return the prepared statement ready to be executed using <code>result.executeQuery()</code>. */ - public boolean readRevisionByTime(IDBStoreAccessor accessor, InternalCDORevision revision, long timeStamp, - int referenceChunk); + public PreparedStatement createObjectIdStatement(IDBStoreAccessor accessor); /** - * @return <code>true</code> if the revision has been loaded sucessfully.<br> - * <code>false</code> if the revision does not exist in the DB. + * Create a prepared statement which returns all IDs of instances of the corresponding class. + * + * @param accessor + * the accessor to use to create the statement + * @param folderId + * the ID of the containing folder. <code>0</code> means none. + * @param name + * the name of the resource node to look up + * @param exactMatch + * if <code>true</code>, <code>name</code> must match exactly, otherwise all resource nodes starting with + * <code>name</code> are returned. + * @param timeStamp + * a timestamp in the past if past versions should be looked up. In case of no audit support, this must be + * {@link CDORevision#UNSPECIFIED_DATE}. + * @return the prepared statement ready to be executed using <code>result.executeQuery()</code>. + * @throws ImplementationError + * if called on a mapping which does not map an <code>EClass instanceof CDOResourceNode</code>. */ - public boolean readRevisionByVersion(IDBStoreAccessor accessor, InternalCDORevision revision, int version, - int referenceChunk); + public PreparedStatement createResourceQueryStatement(IDBStoreAccessor accessor, CDOID folderId, String name, + boolean exactMatch, long timeStamp); + } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMappingAuditSupport.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMappingAuditSupport.java new file mode 100644 index 0000000000..e7120b459f --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMappingAuditSupport.java @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 + * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 + */ +package org.eclipse.emf.cdo.server.db.mapping; + +import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; + +/** + * Interface which complements {@link IClassMapping} with methods to facilitate + * audit support. + * + * @see {@link IMappingStrategy#hasAuditSupport() + * + * @author Eike Stepper + * @author Stefan Winkler + * + * @since 2.0 + */ +public interface IClassMappingAuditSupport +{ + + /** + * Read a specific version of a revision. If this method returns <code>true</code> it is guaranteed that + * <code>revision.getVersion() == version</code> + * + * @param dbStoreAccessor + * the accessor to use. + * @param revision + * the revision object into which the data should be read. The revision has to be have its ID set to the + * requested object's ID. The version is ignored, as the version parameter is used to determine the version + * to be read. + * @param version + * the version which should be read. + * @param listChunk + * the chunk size to read attribute lists. + * @return <code>true</code>, if the revision has been found and read correctly. <code>false</code> if the revision + * could not be found. In this case, the content of <code>revision</code> is undefined. + */ + public boolean readRevisionByVersion(IDBStoreAccessor dbStoreAccessor, InternalCDORevision revision, int version, + int listChunk); + + /** + * Read a specific past version of a revision. If this method returns <code>true</code> it is guaranteed that + * <code>revision.getCreated() <= timeStamp && (getRevised() == 0 || getRevised() >= timeStamp))</code> + * + * @param dbStoreAccessor + * the accessor to use. + * @param revision + * the revision object into which the data should be read. The revision has to be have its ID set to the + * requested object's ID. The version is ignored, as the version parameter is used to determine the version + * to be read. + * @param timeStamp + * the timeStamp which should be used to determine the revision's version. + * @param listChunk + * the chunk size to read attribute lists. + * @return <code>true</code>, if the revision has been found and read correctly. <code>false</code> if the revision + * could not be found. In this case, the content of <code>revision</code> is undefined. + */ + public boolean readRevisionByTime(IDBStoreAccessor dbStoreAccessor, InternalCDORevision revision, long timeStamp, + int listChunk); + +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMappingDeltaSupport.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMappingDeltaSupport.java new file mode 100644 index 0000000000..c602528342 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IClassMappingDeltaSupport.java @@ -0,0 +1,46 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 + * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 + */ +package org.eclipse.emf.cdo.server.db.mapping; + +import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta; + +import org.eclipse.net4j.util.om.monitor.OMMonitor; + +/** + * Interface which complements {@link IClassMapping} with methods to facilitate + * revision delta support. + * + * @see {@link IMappingStrategy#hasDeltaSupport() + * + * @author Eike Stepper + * @author Stefan Winkler + * @since 2.0 + */ +public interface IClassMappingDeltaSupport +{ + + /** + * Write a revision delta. + * + * @param dbStoreAccessor + * the accessor to use. + * @param delta + * the delta to write. + * @param created + * the creation timestamp of the new version + * @param monitor + * the monitor to report progress. + */ + public void writeRevisionDelta(IDBStoreAccessor dbStoreAccessor, InternalCDORevisionDelta delta, long created, + OMMonitor monitor); +} 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 deleted file mode 100644 index 8315a82e89..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IFeatureMapping.java +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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; - -/** - * @author Eike Stepper - * @since 2.0 - */ -public interface IFeatureMapping -{ - public IClassMapping getClassMapping(); - - 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 new file mode 100644 index 0000000000..c26ce2b807 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMapping.java @@ -0,0 +1,99 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 + * Stefan Winkler - major refactoring + */ +package org.eclipse.emf.cdo.server.db.mapping; + +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk; +import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; +import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader; +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; + +/** + * Interface for mapping features with <code>isMany() == true</code>. + * + * @author Eike Stepper + * @author Stefan Winkler + * @since 2.0 + */ +public interface IListMapping +{ + /** + * 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. + */ + public Collection<IDBTable> getDBTables(); + + /** + * Write a complete list of values to the database. + * + * @param accessor + * the accessor to use. + * @param revision + * the revision containing the list to be written. + */ + public void writeValues(IDBStoreAccessor accessor, InternalCDORevision revision); + + /** + * Read the list size and the complete list or the first part of it. + * + * @param accessor + * the accessor to use. + * @param revision + * the revision into which the list values should be read. + * @param listChunk + * indicating the lazy loading behavior: {@link CDORevision#UNCHUNKED} means that the whole list should be + * read. Else, if <code>listChunk >= 0</code>, the list is filled with + * {@link InternalCDORevision#UNINITIALIZED} and only the first <code>listChunk</code> values are read. + */ + public void readValues(IDBStoreAccessor accessor, InternalCDORevision revision, int listChunk); + + /** + * Used to load-on-demand chunks of a list. + * + * @param dbStoreChunkReader + * the chunkReader to use + * @param chunks + * the chunks to read + * @param where + * the where-clause to use in order to read the chunks. + */ + public void readChunks(IDBStoreChunkReader dbStoreChunkReader, List<Chunk> chunks, String where); + + /** + * Hook with which a list mapping is notified that a containing object has been revised. Can be implemented in order + * to clean up lists of revised objects. + * + * @param accessor + * the accessor to use. + * @param id + * the ID of the object which has been revised. + * @param revised + * the timestamp at which the object was revised. + */ + public void objectRevised(IDBStoreAccessor accessor, CDOID id, long revised); +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMappingDeltaSupport.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMappingDeltaSupport.java new file mode 100644 index 0000000000..0bf019fa6f --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IListMappingDeltaSupport.java @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 + * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 + */ +package org.eclipse.emf.cdo.server.db.mapping; + +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.revision.delta.CDOListFeatureDelta; +import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; + +/** + * Interface to complement {@link IListMapping} in order to provide list delta processing support. + * + * @author Eike Stepper + * @author Stefan Winkler + * @since 2.0 + */ +public interface IListMappingDeltaSupport +{ + /** + * Process a set of CDOFeatureDeltas for a many-valued feature. + * + * @param accessor + * the accessor to use + * @param id + * the ID of the revision affected + * @param oldVersion + * the original version of the revision + * @param newVersion + * the new revision of the revision (after the change) + * @param created + * the creation date for the new revision + * @param delta + * the {@link CDOListFeatureDelta} which contains the list deltas. + */ + public void processDelta(IDBStoreAccessor accessor, CDOID id, int oldVersion, int newVersion, long created, + CDOListFeatureDelta delta); +} 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 dabd735285..b89e07a92b 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 @@ -1,5 +1,5 @@ /** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, Germany) and others. + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 @@ -7,25 +7,38 @@ * * Contributors: * Eike Stepper - initial API and implementation + * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 */ package org.eclipse.emf.cdo.server.db.mapping; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.model.CDOClassifierRef; -import org.eclipse.emf.cdo.server.IStoreAccessor; +import org.eclipse.emf.cdo.server.IStoreAccessor.QueryResourcesContext; import org.eclipse.emf.cdo.server.db.IDBStore; import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; +import org.eclipse.emf.cdo.server.internal.db.DBStore; +import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit; import org.eclipse.net4j.db.IDBAdapter; import org.eclipse.net4j.util.collection.CloseableIterator; +import org.eclipse.net4j.util.om.monitor.OMMonitor; import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.ENamedElement; +import org.eclipse.emf.ecore.EStructuralFeature; import java.sql.Connection; import java.util.Map; /** + * The mapping strategy acts as a connection between the DBStore and the database management (and OR-mapping) classes. + * The {@link DBStore} uses methods of this interface to create and lookup mappings (or mappers, as they could also be + * named as such) and to get properties and informations about the mappings used. The mapping classes (e.g., instances + * of IClassMapping and IListMapping) also use this class as a central point of information and as a resource of common + * functionalities. + * * @author Eike Stepper + * @author Stefan Winkler * @since 2.0 */ public interface IMappingStrategy @@ -59,30 +72,161 @@ public interface IMappingStrategy */ public static final String PROP_FORCE_NAMES_WITH_ID = "forceNamesWithID"; - public static final String PROP_TO_MANY_REFERENCE_MAPPING = "toManyReferenceMapping"; + /** + * @return the store, this MappingStrategy instance belongs to. + */ + public IDBStore getStore(); - public static final String PROP_TO_ONE_REFERENCE_MAPPING = "toOneReferenceMapping"; + /** + * Set the store to which this MappingStrategy instance belongs. Should only be called by the {@link DBStore}, and + * only once to initialize the connection between {@link DBStore} and mapping strategy. + * + * @param dbStore + * the DBStore instance to which this MappingStrategy instance belongs. + */ + public void setStore(IDBStore dbStore); - public String getType(); + /** + * Factory for value mappings of single-valued attributes. + * + * @param feature + * the feature for which a mapping should be created. It must hold <code>feature.isMany() == false</code>. + * @return the mapping created. + */ + public ITypeMapping createValueMapping(EStructuralFeature feature); - public IDBStore getStore(); + /** + * Factory for value mappings of multi-valued-attributes. + * + * @param containingClass + * the class containing the feature. + * @param feature + * the feature for which a mapping should be created. It must hold <code>feature.isMany() == true</code>. + * @return + */ + public IListMapping createListMapping(EClass containingClass, EStructuralFeature feature); - public void setStore(IDBStore store); + /** + * 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); - public Map<String, String> getProperties(); + /** + * 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 containeng 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); - public void setProperties(Map<String, String> properties); + /** + * 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); + /** + * Create and initialize the mapping infrastructure for the given packages. Should be called from the DBStore or the + * DBStoreAccessor. + * + * @param connection + * the connection to use. + * @param packageUnits + * the packages whose elements should be mapped. + * @param monitor + * the monitor to report progress. + */ + public void createMapping(Connection connection, InternalCDOPackageUnit[] packageUnits, OMMonitor monitor); + + /** + * Look up an existing class mapping for the given class. Before this method is called, the class mapping must have + * been initialized by calling {@link #createMapping(Connection, InternalCDOPackageUnit[], OMMonitor)} on its + * containing package. + * + * @param eClass + * the class to look up. + * @return the class mapping. + */ public IClassMapping getClassMapping(EClass eClass); - public CloseableIterator<CDOID> readObjectIDs(IDBStoreAccessor accessor); + /** + * Query if this mapping supports revision deltas. <br> + * If this method returns <code>true</code>, it is guaranteed that all class mappings returned by + * {@link #getClassMapping(EClass)} implement {@link IClassMappingDeltaSupport}. + * + * @return <code>true</code> if revision deltas are supported, <code>false</code> else. + */ + public boolean hasDeltaSupport(); - public CDOClassifierRef readObjectType(IDBStoreAccessor accessor, CDOID id); + /** + * Query if this mapping supports audits. <br> + * If this method returns <code>true</code>, it is guaranteed that all class mappings returned by + * {@link #getClassMapping(EClass)} implement {@link IClassMappingAuditSupport}. + * + * @return <code>true</code> if audits are supported, <code>false</code> else. + */ + public boolean hasAuditSupport(); - public void queryResources(IDBStoreAccessor accessor, IStoreAccessor.QueryResourcesContext context); + /** + * Execute a resource query. + * + * @param dbStoreAccessor + * the accessor to use. + * @param context + * the context from which the query parameters are read and to which the result is written. + */ + public void queryResources(IDBStoreAccessor dbStoreAccessor, QueryResourcesContext context); /** - * Returns the maximum CDOID value. + * Read the type (i.e. class) of the object referred to by a given ID. + * + * @param dbStoreAccessor + * the accessor to use to look up the type. + * @param id + * the ID of the object for which the type is to be determined. + * @return the type of the object. + */ + public CDOClassifierRef readObjectType(IDBStoreAccessor dbStoreAccessor, CDOID id); + + /** + * Get an iterator over all instances of objects in the store. + * + * @param dbStoreAccessor + * the accessor to use. + * @return the iterator. + */ + public CloseableIterator<CDOID> readObjectIDs(IDBStoreAccessor dbStoreAccessor); + + /** + * Return the maximum object id used in the store. This is used by the DBStore if a previous crash is discovered + * during the startup process. Should only be called by the DBStore and only during startup. + * + * @param dbAdapter + * the dbAdapter to use to access the database + * @param connection + * the connection to use to access the database + * @return the maximum object id used in the store. */ public long repairAfterCrash(IDBAdapter dbAdapter, Connection connection); + + /** + * Set configuration properties for this mapping strategy. Should only be called by the factory creating the mapping + * strategy instance. + * + * @param properties + * the configuration properties to set. + */ + public void setProperties(Map<String, String> properties); } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IReferenceMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IReferenceMapping.java deleted file mode 100644 index deb57c43bc..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/IReferenceMapping.java +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 - * Stefan Winkler - https://bugs.eclipse.org/bugs/show_bug.cgi?id=259402 - */ -package org.eclipse.emf.cdo.server.db.mapping; - -import org.eclipse.emf.cdo.common.id.CDOID; -import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk; -import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; -import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader; -import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; - -import org.eclipse.net4j.db.ddl.IDBTable; - -import java.util.List; - -/** - * @author Eike Stepper - * @since 2.0 - */ -public interface IReferenceMapping extends IFeatureMapping -{ - public IDBTable getTable(); - - public boolean isWithFeature(); - - /** - * Write a list of references completely - */ - public void writeReference(IDBStoreAccessor accessor, InternalCDORevision revision); - - /** - * Write one element of the list of references - */ - public void writeReferenceEntry(IDBStoreAccessor accessor, CDOID id, int version, int idx, CDOID targetId); - - /** - * Insert a single reference (entry) and move all subsequent entries of the list upwards - */ - public void insertReferenceEntry(IDBStoreAccessor accessor, CDOID id, int newVersion, int index, CDOID value); - - /** - * Moves a single reference (entry) from <code>oldPosition</code> to <code>newPosition</code> and update the list - * indexes of the entries in between. - */ - public void moveReferenceEntry(IDBStoreAccessor accessor, CDOID id, int newVersion, int oldPosition, int newPosition); - - /** - * Remove a single reference (entry) and move all subsequent entries of the list downwards to fill the gap. - */ - public void removeReferenceEntry(IDBStoreAccessor accessor, CDOID id, int index, int newVersion); - - /** - * Updates the value and version of a single reference (entry). - */ - public void updateReference(IDBStoreAccessor accessor, CDOID id, int newVersion, int index, CDOID value); - - /** - * Updates the version of all entries of a reference (list) to <code>newVersion</code>. - */ - public void updateReferenceVersion(IDBStoreAccessor accessor, CDOID id, int newVersion); - - /** - * Clears the list of references for the revision with ID <code>id</code>. - */ - public void deleteReference(IDBStoreAccessor accessor, CDOID id); - - public void readReference(IDBStoreAccessor accessor, InternalCDORevision revision, int referenceChunk); - - public void readChunks(IDBStoreChunkReader chunkReader, List<Chunk> chunks, String string); -} 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 new file mode 100644 index 0000000000..c16756cc06 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/db/mapping/ITypeMapping.java @@ -0,0 +1,120 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 + * Stefan Winkler - major refactoring + */ +package org.eclipse.emf.cdo.server.db.mapping; + +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; + +import org.eclipse.net4j.db.ddl.IDBField; +import org.eclipse.net4j.db.ddl.IDBTable; + +import org.eclipse.emf.ecore.EStructuralFeature; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * Mapping of single values to and from the database. + * + * @author Eike Stepper + * @author Stefan Winkler + * @since 2.0 + */ +public interface ITypeMapping +{ + /** + * @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(); + + /** + * Creates the DBField and adds it to the given table. The name of the DBField is derived from the feature. + * + * @param table + * the table to add this field to. + */ + public void createDBField(IDBTable table); + + /** + * Creates the DBField and adds it to the given table. The name of the DBField is explicitly determined by the + * corresponding parameter. + * + * @param table + * the table to add this field to. + * @param fieldName + * the name for the DBField. + */ + public void createDBField(IDBTable table, String fieldName); + + /** + * Set the given value to the JDBC {@link PreparedStatement} using an appropriate <code>setXxx</code> method. + * + * @param stmt + * the prepared statement to set the value + * @param index + * the index to use for the <code>setXxx</code> method. + * @param value + * the value to set. + * @throws SQLException + * if the <code>setXxx</code> throws it. + */ + public void setValue(PreparedStatement stmt, int index, Object value) throws SQLException; + + /** + * Set a value of the given revision to the JDBC {@link PreparedStatement} using an appropriate <code>setXxx</code> + * method. The feature from which the value is taken is determined by {@link #getFeature()}. + * + * @param stmt + * the prepared statement to set the value + * @param index + * the index to use for the <code>setXxx</code> method. + * @param revision + * the revision to get the value to set from. + * @throws SQLException + * if the <code>setXxx</code> throws it. + */ + public void setValueFromRevision(PreparedStatement stmt, int index, InternalCDORevision value) throws SQLException; + + /** + * Read a value from a {@link ResultSet} and convert it from the DB to the CDO representation. + * + * @param resultSet + * the result set to read from + * @param i + * the column index in the result set to read from + * @return the read value + * @throws SQLException + * if reading the value throws an SQLException + */ + public Object readValue(ResultSet resultSet, int i) throws SQLException; + + /** + * Read a value from a {@link ResultSet}, convert it from the DB to the CDO representation and set it to the feature + * of the revision. The feature is determined by getFeature() + * + * @param resultSet + * the result set to read from + * @param i + * the column index in the result set to read from + * @param revision + * the revision to which the value should be set. + * @throws SQLException + * if reading the value throws an SQLException + */ + public void readValueToRevision(ResultSet resultSet, int i, InternalCDORevision revision) throws SQLException; + +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/AbstractPreparedStatementCache.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/AbstractPreparedStatementCache.java new file mode 100644 index 0000000000..003cb58797 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/AbstractPreparedStatementCache.java @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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: + * Stefan Winkler - initial API and implementation + */ +package org.eclipse.emf.cdo.server.internal.db; + +import org.eclipse.emf.cdo.server.db.IPreparedStatementCache; + +import org.eclipse.net4j.util.lifecycle.Lifecycle; + +import java.sql.Connection; + +/** + * @author Stefan Winkler + * @since 2.0 + */ +public abstract class AbstractPreparedStatementCache extends Lifecycle implements IPreparedStatementCache +{ + private Connection connection; + + public AbstractPreparedStatementCache() + { + } + + public final Connection getConnection() + { + return connection; + } + + public final void setConnection(Connection connection) + { + checkInactive(); + this.connection = connection; + } + + @Override + protected void doBeforeActivate() + { + checkState(connection, "Must have valid connection to start."); + } +} 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 5d72877b26..a772fe809c 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 @@ -1,5 +1,5 @@ /** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, Germany) and others. + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 @@ -7,6 +7,8 @@ * * Contributors: * Eike Stepper - initial API and implementation + * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 + * */ package org.eclipse.emf.cdo.server.internal.db; @@ -120,17 +122,17 @@ public class CDODBSchema extends DBSchema public static final String ATTRIBUTES_FEATURE = "cdo_feature"; /** - * Field names of reference tables + * Field names of list tables */ - public static final String REFERENCES_FEATURE = "cdo_feature"; + public static final String LIST_FEATURE = "cdo_feature"; - public static final String REFERENCES_SOURCE = "cdo_source"; + public static final String LIST_REVISION_ID = "cdo_source"; - public static final String REFERENCES_VERSION = "cdo_version"; + public static final String LIST_REVISION_VERSION = "cdo_version"; - public static final String REFERENCES_IDX = "cdo_idx"; + public static final String LIST_IDX = "cdo_idx"; - public static final String REFERENCES_TARGET = "cdo_target"; + public static final String LIST_VALUE = "cdo_value"; private CDODBSchema() { diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStore.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStore.java index 599f0316d6..5078fb3277 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStore.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStore.java @@ -4,29 +4,25 @@ * 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 * Stefan Winkler - https://bugs.eclipse.org/bugs/show_bug.cgi?id=259402 + * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 */ package org.eclipse.emf.cdo.server.internal.db; -import org.eclipse.emf.cdo.common.id.CDOID; -import org.eclipse.emf.cdo.common.id.CDOIDMeta; -import org.eclipse.emf.cdo.common.id.CDOIDUtil; import org.eclipse.emf.cdo.server.ISession; import org.eclipse.emf.cdo.server.ITransaction; import org.eclipse.emf.cdo.server.IView; import org.eclipse.emf.cdo.server.db.IDBStore; -import org.eclipse.emf.cdo.server.db.IJDBCDelegateProvider; +import org.eclipse.emf.cdo.server.db.IMetaDataManager; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; import org.eclipse.emf.cdo.server.internal.db.bundle.OM; -import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageRegistry; import org.eclipse.emf.cdo.spi.server.LongIDStore; import org.eclipse.emf.cdo.spi.server.StoreAccessorPool; import org.eclipse.net4j.db.DBException; -import org.eclipse.net4j.db.DBType; import org.eclipse.net4j.db.DBUtil; import org.eclipse.net4j.db.IDBAdapter; import org.eclipse.net4j.db.IDBConnectionProvider; @@ -37,19 +33,11 @@ import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump; import org.eclipse.net4j.util.lifecycle.LifecycleUtil; import org.eclipse.net4j.util.om.monitor.ProgressDistributor; -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.EClassifier; -import org.eclipse.emf.ecore.EEnum; -import org.eclipse.emf.ecore.EModelElement; -import org.eclipse.emf.ecore.EcorePackage; -import org.eclipse.emf.ecore.InternalEObject; - import javax.sql.DataSource; import java.sql.Connection; +import java.sql.SQLException; import java.text.MessageFormat; -import java.util.HashMap; -import java.util.Map; import java.util.Set; /** @@ -71,8 +59,6 @@ public class DBStore extends LongIDStore implements IDBStore private IDBConnectionProvider dbConnectionProvider; - private IJDBCDelegateProvider jdbcDelegateProvider; - @ExcludeFromDump private transient ProgressDistributor accessorWriteDistributor = new ProgressDistributor.Geometric() { @@ -95,50 +81,13 @@ public class DBStore extends LongIDStore implements IDBStore @ExcludeFromDump private transient StoreAccessorPool writerPool = new StoreAccessorPool(this, null); - private static Map<EClassifier, DBType> typeMap = new HashMap<EClassifier, DBType>(); - - static - { - typeMap.put(EcorePackage.eINSTANCE.getEDate(), DBType.TIMESTAMP); - typeMap.put(EcorePackage.eINSTANCE.getEString(), DBType.VARCHAR); - - typeMap.put(EcorePackage.eINSTANCE.getEBoolean(), DBType.BOOLEAN); - typeMap.put(EcorePackage.eINSTANCE.getEByte(), DBType.SMALLINT); - typeMap.put(EcorePackage.eINSTANCE.getEChar(), DBType.CHAR); - typeMap.put(EcorePackage.eINSTANCE.getEDouble(), DBType.DOUBLE); - typeMap.put(EcorePackage.eINSTANCE.getEFloat(), DBType.FLOAT); - typeMap.put(EcorePackage.eINSTANCE.getEInt(), DBType.INTEGER); - typeMap.put(EcorePackage.eINSTANCE.getELong(), DBType.BIGINT); - typeMap.put(EcorePackage.eINSTANCE.getEShort(), DBType.SMALLINT); - - typeMap.put(EcorePackage.eINSTANCE.getEBooleanObject(), DBType.BOOLEAN); - typeMap.put(EcorePackage.eINSTANCE.getEByteObject(), DBType.SMALLINT); - typeMap.put(EcorePackage.eINSTANCE.getECharacterObject(), DBType.CHAR); - typeMap.put(EcorePackage.eINSTANCE.getEDoubleObject(), DBType.DOUBLE); - typeMap.put(EcorePackage.eINSTANCE.getEFloatObject(), DBType.FLOAT); - typeMap.put(EcorePackage.eINSTANCE.getEIntegerObject(), DBType.INTEGER); - typeMap.put(EcorePackage.eINSTANCE.getELongObject(), DBType.BIGINT); - typeMap.put(EcorePackage.eINSTANCE.getEShortObject(), DBType.SMALLINT); - } + private transient IMetaDataManager metaDataManager; public DBStore() { - super(TYPE, set(ChangeFormat.REVISION, ChangeFormat.DELTA), set(RevisionTemporality.AUDITING, - RevisionTemporality.NONE), set(RevisionParallelism.NONE)); - setRevisionTemporality(RevisionTemporality.AUDITING); - } - - @Override - public Set<ChangeFormat> getSupportedChangeFormats() - { - if (getRevisionTemporality() == RevisionTemporality.AUDITING) - { - return set(ChangeFormat.REVISION); - } - else - { - return set(ChangeFormat.REVISION, ChangeFormat.DELTA); - } + super(TYPE, set(ChangeFormat.REVISION, ChangeFormat.DELTA), // + set(RevisionTemporality.AUDITING, RevisionTemporality.NONE), // + set(RevisionParallelism.NONE)); } public IMappingStrategy getMappingStrategy() @@ -150,6 +99,8 @@ public class DBStore extends LongIDStore implements IDBStore { this.mappingStrategy = mappingStrategy; mappingStrategy.setStore(this); + + setRevisionTemporality(mappingStrategy.hasAuditSupport() ? RevisionTemporality.AUDITING : RevisionTemporality.NONE); } public IDBAdapter getDBAdapter() @@ -169,7 +120,6 @@ public class DBStore extends LongIDStore implements IDBStore public void setDbConnectionProvider(IDBConnectionProvider dbConnectionProvider) { - // TODO Need to update provider in JDBCWrapper, too? this.dbConnectionProvider = dbConnectionProvider; } @@ -178,16 +128,6 @@ public class DBStore extends LongIDStore implements IDBStore dbConnectionProvider = DBUtil.createConnectionProvider(dataSource); } - public IJDBCDelegateProvider getJDBCDelegateProvider() - { - return jdbcDelegateProvider; - } - - public void setJDBCDelegateProvider(IJDBCDelegateProvider provider) - { - jdbcDelegateProvider = provider; - } - public ProgressDistributor getAccessorWriteDistributor() { return accessorWriteDistributor; @@ -234,33 +174,19 @@ public class DBStore extends LongIDStore implements IDBStore return new DBStoreAccessor(this, transaction); } - public long getMetaID(EModelElement modelElement) + protected Connection getConnection() { - InternalCDOPackageRegistry packageRegistry = (InternalCDOPackageRegistry)getRepository().getPackageRegistry(); + Connection connection = dbConnectionProvider.getConnection(); try { - CDOID cdoid = packageRegistry.getMetaInstanceMapper().lookupMetaInstanceID((InternalEObject)modelElement); - return ((CDOIDMeta)cdoid).getLongValue(); + connection.setAutoCommit(false); } - catch (RuntimeException ex) + catch (SQLException ex) { - packageRegistry.getMetaInstanceMapper().lookupMetaInstanceID((InternalEObject)modelElement); - throw ex; + throw new DBException(ex); } - } - - public EModelElement getMetaInstance(long id) - { - CDOIDMeta cdoid = CDOIDUtil.createMeta(id); - InternalCDOPackageRegistry packageRegistry = (InternalCDOPackageRegistry)getRepository().getPackageRegistry(); - InternalEObject metaInstance = packageRegistry.getMetaInstanceMapper().lookupMetaInstance(cdoid); - return (EModelElement)metaInstance; - } - public Connection getConnection() - { - Connection connection = dbConnectionProvider.getConnection(); if (connection == null) { throw new DBException("No connection from connection provider: " + dbConnectionProvider); @@ -286,13 +212,22 @@ public class DBStore extends LongIDStore implements IDBStore checkNull(mappingStrategy, "mappingStrategy is null"); checkNull(dbAdapter, "dbAdapter is null"); checkNull(dbConnectionProvider, "dbConnectionProvider is null"); + + checkState(getRevisionTemporality() == RevisionTemporality.AUDITING == mappingStrategy.hasAuditSupport(), + "AuditSupport of MappingStrategy and Store does not match. Please check configuration."); } @Override protected void doActivate() throws Exception { super.doActivate(); + + dbSchema = createSchema(); + metaDataManager = new MetaDataManager(this); + LifecycleUtil.activate(metaDataManager); + Connection connection = getConnection(); + LifecycleUtil.activate(mappingStrategy); try { @@ -306,8 +241,7 @@ public class DBStore extends LongIDStore implements IDBStore reStart(connection); } - LifecycleUtil.activate(mappingStrategy); - dbSchema = createSchema(); + connection.commit(); } finally { @@ -370,6 +304,7 @@ public class DBStore extends LongIDStore implements IDBStore { throw new DBException("No row updated in table " + CDODBSchema.REPOSITORY); } + } @Override @@ -377,6 +312,9 @@ public class DBStore extends LongIDStore implements IDBStore { Connection connection = null; + LifecycleUtil.deactivate(metaDataManager); + metaDataManager = null; + try { connection = getConnection(); @@ -405,6 +343,8 @@ public class DBStore extends LongIDStore implements IDBStore { throw new DBException("No row updated in table " + CDODBSchema.REPOSITORY); } + + connection.commit(); } finally { @@ -432,24 +372,21 @@ public class DBStore extends LongIDStore implements IDBStore return System.currentTimeMillis(); } - public static DBType getDBType(EClassifier type) + public IMetaDataManager getMetaDataManager() { - if (type instanceof EClass) - { - return DBType.BIGINT; - } + return metaDataManager; + } - if (type instanceof EEnum) + @Override + public Set<ChangeFormat> getSupportedChangeFormats() + { + if (mappingStrategy.hasDeltaSupport()) { - return DBType.INTEGER; + return set(ChangeFormat.DELTA); } - - DBType dbType = typeMap.get(type); - if (dbType != null) + else { - return dbType; + return set(ChangeFormat.REVISION); } - - return DBType.VARCHAR; } } 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 c8ac86f85e..31f09eb153 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 @@ -8,31 +8,28 @@ * Contributors: * Eike Stepper - initial API and implementation * Stefan Winkler - https://bugs.eclipse.org/bugs/show_bug.cgi?id=259402 + * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 */ package org.eclipse.emf.cdo.server.internal.db; import org.eclipse.emf.cdo.common.CDOQueryInfo; import org.eclipse.emf.cdo.common.id.CDOID; -import org.eclipse.emf.cdo.common.id.CDOIDMeta; -import org.eclipse.emf.cdo.common.id.CDOIDMetaRange; -import org.eclipse.emf.cdo.common.id.CDOIDUtil; import org.eclipse.emf.cdo.common.model.CDOClassifierRef; -import org.eclipse.emf.cdo.common.model.CDOModelUtil; 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.common.revision.CDORevisionUtil; import org.eclipse.emf.cdo.server.IQueryContext; import org.eclipse.emf.cdo.server.IRepository; import org.eclipse.emf.cdo.server.ISession; +import org.eclipse.emf.cdo.server.IStoreAccessor; import org.eclipse.emf.cdo.server.ITransaction; -import org.eclipse.emf.cdo.server.IStore.RevisionTemporality; +import org.eclipse.emf.cdo.server.db.CDODBUtil; import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; -import org.eclipse.emf.cdo.server.db.IJDBCDelegate; +import org.eclipse.emf.cdo.server.db.IPreparedStatementCache; import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; +import org.eclipse.emf.cdo.server.db.mapping.IClassMappingAuditSupport; +import org.eclipse.emf.cdo.server.db.mapping.IClassMappingDeltaSupport; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; import org.eclipse.emf.cdo.server.internal.db.bundle.OM; -import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageInfo; import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta; @@ -40,8 +37,6 @@ import org.eclipse.emf.cdo.spi.server.LongIDStoreAccessor; import org.eclipse.net4j.db.DBException; import org.eclipse.net4j.db.DBUtil; -import org.eclipse.net4j.db.IDBRowHandler; -import org.eclipse.net4j.db.ddl.IDBTable; import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump; import org.eclipse.net4j.util.collection.CloseableIterator; import org.eclipse.net4j.util.lifecycle.LifecycleUtil; @@ -55,16 +50,12 @@ import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EStructuralFeature; -import java.sql.PreparedStatement; +import java.sql.Connection; import java.sql.SQLException; -import java.util.ArrayList; +import java.sql.Statement; import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Map.Entry; +import java.util.Timer; +import java.util.TimerTask; /** * @author Eike Stepper @@ -73,9 +64,11 @@ public class DBStoreAccessor extends LongIDStoreAccessor implements IDBStoreAcce { private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, DBStoreAccessor.class); - private static final boolean ZIP_PACKAGE_BYTES = true; + private Connection connection = null; - private IJDBCDelegate jdbcDelegate; + private IPreparedStatementCache statementCache = null; + + private Timer connectionKeepAliveTimer = null; @ExcludeFromDump @SuppressWarnings("unchecked") @@ -91,31 +84,19 @@ public class DBStoreAccessor extends LongIDStoreAccessor implements IDBStoreAcce { public void runLoop(int index, CommitContext commitContext, OMMonitor monitor) throws Exception { - jdbcDelegate.flush(monitor.fork()); + // TODO - reenable when reimplementing stmt caching + // flush(monitor.fork()); } }); public DBStoreAccessor(DBStore store, ISession session) throws DBException { super(store, session); - initJDBCDelegate(); } public DBStoreAccessor(DBStore store, ITransaction transaction) throws DBException { super(store, transaction); - initJDBCDelegate(); - } - - private void initJDBCDelegate() - { - jdbcDelegate = getStore().getJDBCDelegateProvider().getJDBCDelegate(); - jdbcDelegate.setStoreAccessor(this); - } - - public IJDBCDelegate getJDBCDelegate() - { - return jdbcDelegate; } @Override @@ -124,81 +105,14 @@ public class DBStoreAccessor extends LongIDStoreAccessor implements IDBStoreAcce return (DBStore)super.getStore(); } - public DBStoreChunkReader createChunkReader(InternalCDORevision revision, EStructuralFeature feature) + public IPreparedStatementCache getStatementCache() { - return new DBStoreChunkReader(this, revision, feature); - } - - public final Collection<InternalCDOPackageUnit> readPackageUnits() - { - final Map<String, InternalCDOPackageUnit> packageUnits = new HashMap<String, InternalCDOPackageUnit>(); - IDBRowHandler unitRowHandler = new IDBRowHandler() - { - public boolean handle(int row, final Object... values) - { - InternalCDOPackageUnit packageUnit = createPackageUnit(); - packageUnit.setOriginalType(CDOPackageUnit.Type.values()[(Integer)values[1]]); - packageUnit.setTimeStamp((Long)values[2]); - packageUnits.put((String)values[0], packageUnit); - return true; - } - }; - - DBUtil.select(jdbcDelegate.getConnection(), unitRowHandler, CDODBSchema.PACKAGE_UNITS_ID, - CDODBSchema.PACKAGE_UNITS_ORIGINAL_TYPE, CDODBSchema.PACKAGE_UNITS_TIME_STAMP); - - final Map<String, List<InternalCDOPackageInfo>> packageInfos = new HashMap<String, List<InternalCDOPackageInfo>>(); - IDBRowHandler infoRowHandler = new IDBRowHandler() - { - public boolean handle(int row, final Object... values) - { - long metaLB = (Long)values[3]; - long metaUB = (Long)values[4]; - CDOIDMetaRange metaIDRange = metaLB == 0 ? null : CDOIDUtil.createMetaRange(CDOIDUtil.createMeta(metaLB), - (int)(metaUB - metaLB) + 1); - - InternalCDOPackageInfo packageInfo = createPackageInfo(); - packageInfo.setPackageURI((String)values[1]); - packageInfo.setParentURI((String)values[2]); - packageInfo.setMetaIDRange(metaIDRange); - - 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; - } - }; - - DBUtil.select(jdbcDelegate.getConnection(), infoRowHandler, CDODBSchema.PACKAGE_INFOS_UNIT, - CDODBSchema.PACKAGE_INFOS_URI, CDODBSchema.PACKAGE_INFOS_PARENT, CDODBSchema.PACKAGE_INFOS_META_LB, - CDODBSchema.PACKAGE_INFOS_META_UB); - - for (Entry<String, InternalCDOPackageUnit> entry : packageUnits.entrySet()) - { - String id = entry.getKey(); - InternalCDOPackageUnit packageUnit = entry.getValue(); - - List<InternalCDOPackageInfo> list = packageInfos.get(id); - InternalCDOPackageInfo[] array = list.toArray(new InternalCDOPackageInfo[list.size()]); - packageUnit.setPackageInfos(array); - } - - return packageUnits.values(); + return statementCache; } - public final EPackage[] loadPackageUnit(InternalCDOPackageUnit packageUnit) + public DBStoreChunkReader createChunkReader(InternalCDORevision revision, EStructuralFeature feature) { - String where = CDODBSchema.PACKAGE_UNITS_ID.getName() + "='" + packageUnit.getID() + "'"; - Object[] values = DBUtil.select(jdbcDelegate.getConnection(), where, CDODBSchema.PACKAGE_UNITS_PACKAGE_DATA); - byte[] bytes = (byte[])values[0]; - EPackage ePackage = createEPackage(packageUnit, bytes); - return EMFUtil.getAllPackages(ePackage); + return new DBStoreChunkReader(this, revision, feature); } public CloseableIterator<CDOID> readObjectIDs() @@ -221,7 +135,25 @@ public class DBStoreAccessor extends LongIDStoreAccessor implements IDBStoreAcce return getStore().getMappingStrategy().readObjectType(this, id); } - public InternalCDORevision readRevision(CDOID id, int referenceChunk, AdditionalRevisionCache cache) + protected EClass getObjectType(CDOID id) + { + EClass result = getStore().getRepository().getRevisionManager().getObjectType(id); + if (result == null) + { + CDOClassifierRef type = readObjectType(id); + if (type == null) + { + return null; + } + + IRepository repository = getStore().getRepository(); + CDOPackageRegistry packageRegistry = repository.getPackageRegistry(); + result = (EClass)type.resolve(packageRegistry); + } + return result; + } + + public InternalCDORevision readRevision(CDOID id, int listChunk, AdditionalRevisionCache cache) { if (TRACER.isEnabled()) { @@ -238,7 +170,7 @@ public class DBStoreAccessor extends LongIDStoreAccessor implements IDBStoreAcce IMappingStrategy mappingStrategy = getStore().getMappingStrategy(); IClassMapping mapping = mappingStrategy.getClassMapping(eClass); - if (mapping.readRevision(this, revision, referenceChunk)) + if (mapping.readRevision(this, revision, listChunk)) { return revision; } @@ -247,9 +179,15 @@ public class DBStoreAccessor extends LongIDStoreAccessor implements IDBStoreAcce return null; } - public InternalCDORevision readRevisionByTime(CDOID id, int referenceChunk, AdditionalRevisionCache cache, - long timeStamp) + public InternalCDORevision readRevisionByTime(CDOID id, int listChunk, AdditionalRevisionCache cache, long timeStamp) { + IMappingStrategy mappingStrategy = getStore().getMappingStrategy(); + + if (!mappingStrategy.hasAuditSupport()) + { + throw new UnsupportedOperationException("Mapping strategy does not support audits."); + } + if (TRACER.isEnabled()) { TRACER.format("Selecting revision: {0}, timestamp={1,date} {1,time}", id, timeStamp); @@ -258,9 +196,8 @@ public class DBStoreAccessor extends LongIDStoreAccessor implements IDBStoreAcce EClass eClass = getObjectType(id); InternalCDORevision revision = (InternalCDORevision)CDORevisionUtil.create(eClass, id); - IMappingStrategy mappingStrategy = getStore().getMappingStrategy(); - IClassMapping mapping = mappingStrategy.getClassMapping(eClass); - if (mapping.readRevisionByTime(this, revision, timeStamp, referenceChunk)) + IClassMappingAuditSupport mapping = (IClassMappingAuditSupport)mappingStrategy.getClassMapping(eClass); + if (mapping.readRevisionByTime(this, revision, timeStamp, listChunk)) { return revision; } @@ -269,29 +206,54 @@ public class DBStoreAccessor extends LongIDStoreAccessor implements IDBStoreAcce return null; } - public InternalCDORevision readRevisionByVersion(CDOID id, int referenceChunk, AdditionalRevisionCache cache, - int version) + public InternalCDORevision readRevisionByVersion(CDOID id, int listChunk, AdditionalRevisionCache cache, int version) { - if (TRACER.isEnabled()) - { - TRACER.format("Selecting revision: {0}, version={1}", id, version); - } + IMappingStrategy mappingStrategy = getStore().getMappingStrategy(); EClass eClass = getObjectType(id); InternalCDORevision revision = (InternalCDORevision)CDORevisionUtil.create(eClass, id); - - IMappingStrategy mappingStrategy = getStore().getMappingStrategy(); IClassMapping mapping = mappingStrategy.getClassMapping(eClass); - if (mapping.readRevisionByVersion(this, revision, version, referenceChunk)) + + boolean success = false; + + if (mappingStrategy.hasAuditSupport()) { - return revision; + if (TRACER.isEnabled()) + { + TRACER.format("Selecting revision: {0}, version={1}", id, version); + } + + // if audit support is present, just use the audit method + success = ((IClassMappingAuditSupport)mapping).readRevisionByVersion(this, revision, version, listChunk); } + else + { + // if audit support is not present, we still have to provide a method + // to readRevisionByVersion because TransactionCommitContext.computeDirtyObject + // needs to lookup the base revision for a change. Hence we emulate this + // behavior by getting the current revision and asserting that the version + // has not changed. This is valid because if the version has changed, + // we are in trouble because of a conflict anyways. + if (TRACER.isEnabled()) + { + TRACER.format("Selecting current base revision: {0}", id); + } - // Reading failed - revision does not exist. - return null; + success = mapping.readRevision(this, revision, listChunk); + + if (success && revision.getVersion() != version) + { + throw new IllegalStateException("Can only retrieve current version " + revision.getVersion() + " for " + id + + " - version requested was " + version + "."); + } + } + + return success ? revision : null; } /** + * TODO: implement as query when query implementation is done? + * * @since 2.0 */ public void queryResources(QueryResourcesContext context) @@ -309,20 +271,6 @@ public class DBStoreAccessor extends LongIDStoreAccessor implements IDBStoreAcce throw new UnsupportedOperationException(); } - protected EClass getObjectType(CDOID id) - { - // TODO Replace calls to getObjectType by optimized calls to RevisionManager.getObjectType (cache!) - CDOClassifierRef type = readObjectType(id); - if (type == null) - { - return null; - } - - IRepository repository = getStore().getRepository(); - CDOPackageRegistry packageRegistry = repository.getPackageRegistry(); - return (EClass)type.resolve(packageRegistry); - } - public CloseableIterator<Object> createQueryIterator(CDOQueryInfo queryInfo) { throw new UnsupportedOperationException(); @@ -330,6 +278,7 @@ public class DBStoreAccessor extends LongIDStoreAccessor implements IDBStoreAcce public void refreshRevisions() { + // TODO is this empty on purpose or should it be implemented (how?) } @Override @@ -339,177 +288,14 @@ public class DBStoreAccessor extends LongIDStoreAccessor implements IDBStoreAcce distributor.run(ops, context, monitor); } - public final void writePackageUnits(InternalCDOPackageUnit[] packageUnits, OMMonitor monitor) - { - try - { - monitor.begin(2); - fillSystemTables(packageUnits, monitor.fork()); - createModelTables(packageUnits, monitor.fork()); - } - finally - { - monitor.done(); - } - } - - private void fillSystemTables(InternalCDOPackageUnit[] packageUnits, OMMonitor monitor) - { - try - { - monitor.begin(packageUnits.length); - for (InternalCDOPackageUnit packageUnit : packageUnits) - { - fillSystemTables(packageUnit, monitor.fork()); - } - } - finally - { - monitor.done(); - } - } - - private void fillSystemTables(InternalCDOPackageUnit packageUnit, OMMonitor monitor) - { - try - { - InternalCDOPackageInfo[] packageInfos = packageUnit.getPackageInfos(); - monitor.begin(1 + packageInfos.length); - - if (TRACER.isEnabled()) - { - TRACER.format("Writing package unit: {0}", packageUnit); - } - - String sql = "INSERT INTO " + CDODBSchema.PACKAGE_UNITS + " VALUES (?, ?, ?, ?)"; - DBUtil.trace(sql); - PreparedStatement pstmt = null; - Async async = monitor.forkAsync(); - - try - { - pstmt = jdbcDelegate.getPreparedStatement(sql); - pstmt.setString(1, packageUnit.getID()); - pstmt.setInt(2, packageUnit.getOriginalType().ordinal()); - pstmt.setLong(3, packageUnit.getTimeStamp()); - pstmt.setBytes(4, getEPackageBytes(packageUnit)); - - if (pstmt.execute()) - { - throw new DBException("No result set expected"); - } - - if (pstmt.getUpdateCount() == 0) - { - throw new DBException("No row inserted into table " + CDODBSchema.PACKAGE_UNITS); - } - } - catch (SQLException ex) - { - throw new DBException(ex); - } - finally - { - DBUtil.close(pstmt); - async.stop(); - } - - for (InternalCDOPackageInfo packageInfo : packageInfos) - { - fillSystemTables(packageInfo, monitor); // Don't fork monitor - } - } - finally - { - monitor.done(); - } - } - - private byte[] getEPackageBytes(InternalCDOPackageUnit packageUnit) - { - EPackage ePackage = packageUnit.getTopLevelPackageInfo().getEPackage(); - CDOPackageRegistry packageRegistry = getStore().getRepository().getPackageRegistry(); - return EMFUtil.getEPackageBytes(ePackage, ZIP_PACKAGE_BYTES, packageRegistry); - } - - private EPackage createEPackage(InternalCDOPackageUnit packageUnit, byte[] bytes) - { - CDOPackageRegistry packageRegistry = getStore().getRepository().getPackageRegistry(); - return EMFUtil.createEPackage(packageUnit.getID(), bytes, ZIP_PACKAGE_BYTES, packageRegistry); - } - - private void fillSystemTables(InternalCDOPackageInfo packageInfo, OMMonitor monitor) - { - if (TRACER.isEnabled()) - { - TRACER.format("Writing package info: {0}", packageInfo); - } - - String packageURI = packageInfo.getPackageURI(); - String parentURI = packageInfo.getParentURI(); - String unitID = packageInfo.getPackageUnit().getID(); - CDOIDMetaRange metaIDRange = packageInfo.getMetaIDRange(); - long metaLB = metaIDRange == null ? 0L : ((CDOIDMeta)metaIDRange.getLowerBound()).getLongValue(); - long metaUB = metaIDRange == null ? 0L : ((CDOIDMeta)metaIDRange.getUpperBound()).getLongValue(); - - String sql = "INSERT INTO " + CDODBSchema.PACKAGE_INFOS + " VALUES (?, ?, ?, ?, ?)"; - DBUtil.trace(sql); - PreparedStatement pstmt = null; - Async async = monitor.forkAsync(); - - try - { - pstmt = jdbcDelegate.getPreparedStatement(sql); - pstmt.setString(1, packageURI); - pstmt.setString(2, parentURI); - pstmt.setString(3, unitID); - pstmt.setLong(4, metaLB); - pstmt.setLong(5, metaUB); - - if (pstmt.execute()) - { - throw new DBException("No result set expected"); - } - - if (pstmt.getUpdateCount() == 0) - { - throw new DBException("No row inserted into table " + CDODBSchema.PACKAGE_INFOS); - } - } - catch (SQLException ex) - { - throw new DBException(ex); - } - finally - { - DBUtil.close(pstmt); - async.stop(); - } - } - - private void createModelTables(InternalCDOPackageUnit[] packageUnits, OMMonitor monitor) - { - monitor.begin(); - Async async = monitor.forkAsync(); - - try - { - Set<IDBTable> affectedTables = mapPackageUnits(packageUnits); - getStore().getDBAdapter().createTables(affectedTables, jdbcDelegate.getConnection()); - } - finally - { - async.stop(); - monitor.done(); - } - } - @Override protected void writeRevisionDeltas(InternalCDORevisionDelta[] revisionDeltas, long created, OMMonitor monitor) { - if (!(getStore().getRevisionTemporality() == RevisionTemporality.NONE)) + IMappingStrategy mappingStrategy = getStore().getMappingStrategy(); + + if (!mappingStrategy.hasDeltaSupport()) { - throw new UnsupportedOperationException("Revision Deltas are only supported in non-auditing mode!"); + throw new UnsupportedOperationException("Mapping strategy does not support revision deltas."); } monitor.begin(revisionDeltas.length); @@ -529,7 +315,8 @@ public class DBStoreAccessor extends LongIDStoreAccessor implements IDBStoreAcce protected void writeRevisionDelta(InternalCDORevisionDelta delta, long created, OMMonitor monitor) { EClass eClass = getObjectType(delta.getID()); - IClassMapping mapping = getStore().getMappingStrategy().getClassMapping(eClass); + IClassMappingDeltaSupport mapping = (IClassMappingDeltaSupport)getStore().getMappingStrategy().getClassMapping( + eClass); mapping.writeRevisionDelta(this, delta, created, monitor); } @@ -594,118 +381,143 @@ public class DBStoreAccessor extends LongIDStoreAccessor implements IDBStoreAcce mapping.detachObject(this, id, revised, monitor); } - /** - * TODO Move this somehow to DBAdapter - */ - protected Boolean getBoolean(Object value) + public Connection getConnection() { - if (value == null) + return connection; + } + + public final void commit(OMMonitor monitor) + { + monitor.begin(); + Async async = monitor.forkAsync(); + + if (TRACER.isEnabled()) { - return null; + TRACER.format("--- DB COMMIT ---"); } - if (value instanceof Boolean) + try { - return (Boolean)value; + getConnection().commit(); } - - if (value instanceof Number) + catch (SQLException ex) { - return ((Number)value).intValue() != 0; + throw new DBException(ex); } - - throw new IllegalArgumentException("Not a boolean value: " + value); - } - - protected Set<IDBTable> mapPackageUnits(InternalCDOPackageUnit[] packageUnits) - { - Set<IDBTable> affectedTables = new HashSet<IDBTable>(); - if (packageUnits != null && packageUnits.length != 0) + finally { - for (InternalCDOPackageUnit packageUnit : packageUnits) - { - mapPackageInfos(packageUnit.getPackageInfos(), affectedTables); - } + async.stop(); + monitor.done(); } - - return affectedTables; } - protected void mapPackageInfos(InternalCDOPackageInfo[] packageInfos, Set<IDBTable> affectedTables) + @Override + protected final void rollback(IStoreAccessor.CommitContext commitContext) { - for (InternalCDOPackageInfo packageInfo : packageInfos) + if (TRACER.isEnabled()) { - EPackage ePackage = packageInfo.getEPackage(); - if (!CDOModelUtil.isCorePackage(ePackage)) - { - EClass[] persistentClasses = EMFUtil.getPersistentClasses(ePackage); - Set<IDBTable> tables = mapClasses(persistentClasses); - affectedTables.addAll(tables); - } + TRACER.format("--- DB ROLLBACK ---"); } - } - protected Set<IDBTable> mapClasses(EClass... eClasses) - { - Set<IDBTable> affectedTables = new HashSet<IDBTable>(); - if (eClasses != null && eClasses.length != 0) + try { - IMappingStrategy mappingStrategy = getStore().getMappingStrategy(); - for (EClass eClass : eClasses) - { - IClassMapping mapping = mappingStrategy.getClassMapping(eClass); - if (mapping != null) - { - affectedTables.addAll(mapping.getAffectedTables()); - } - } + getConnection().rollback(); + } + catch (SQLException ex) + { + throw new DBException(ex); } - - return affectedTables; } - protected InternalCDOPackageUnit createPackageUnit() + @Override + protected void doActivate() throws Exception { - return (InternalCDOPackageUnit)CDOModelUtil.createPackageUnit(); + connection = getStore().getConnection(); + + connectionKeepAliveTimer = new Timer("Connection-Keep-Alive-" + toString()); + connectionKeepAliveTimer.schedule(new ConnectionKeepAliveTask(), ConnectionKeepAliveTask.EXECUTION_PERIOD, + ConnectionKeepAliveTask.EXECUTION_PERIOD); + + // TODO - make this configurable? + statementCache = CDODBUtil.createStatementCache(); + statementCache.setConnection(connection); + + LifecycleUtil.activate(statementCache); } - protected InternalCDOPackageInfo createPackageInfo() + @Override + protected void doDeactivate() throws Exception { - return (InternalCDOPackageInfo)CDOModelUtil.createPackageInfo(); + LifecycleUtil.deactivate(statementCache); + + connectionKeepAliveTimer.cancel(); + connectionKeepAliveTimer = null; + + DBUtil.close(connection); + connection = null; } - public final void commit(OMMonitor monitor) + @Override + protected void doPassivate() throws Exception { - jdbcDelegate.commit(monitor); + // Do nothing } @Override - protected final void rollback(CommitContext context) + protected void doUnpassivate() throws Exception { - jdbcDelegate.rollback(); + // do nothing } - @Override - protected void doActivate() throws Exception + public EPackage[] loadPackageUnit(InternalCDOPackageUnit packageUnit) { - LifecycleUtil.activate(jdbcDelegate); + return getStore().getMetaDataManager().loadPackageUnit(getConnection(), packageUnit); } - @Override - protected void doDeactivate() throws Exception + public Collection<InternalCDOPackageUnit> readPackageUnits() { - LifecycleUtil.deactivate(jdbcDelegate); + return getStore().getMetaDataManager().readPackageUnits(getConnection()); } - @Override - protected void doPassivate() throws Exception + public void writePackageUnits(InternalCDOPackageUnit[] packageUnits, OMMonitor monitor) { - // Do nothing + monitor.begin(2); + try + { + getStore().getMetaDataManager().writePackageUnits(getConnection(), packageUnits, monitor.fork()); + getStore().getMappingStrategy().createMapping(getConnection(), packageUnits, monitor.fork()); + } + finally + { + monitor.done(); + } } - @Override - protected void doUnpassivate() throws Exception + private class ConnectionKeepAliveTask extends TimerTask { - // Do nothing + public static final long EXECUTION_PERIOD = 1000 * 60 * 60 * 4; // 4 hours + + @Override + public void run() + { + Statement stmt = null; + try + { + if (TRACER.isEnabled()) + { + TRACER.trace("DB connection keep-alive task activated."); + } + stmt = connection.createStatement(); + stmt.executeQuery("SELECT 1 FROM " + CDODBSchema.REPOSITORY); + } + catch (SQLException e) + { + OM.LOG.error("DB connection keep-alive failed.", e); + } + finally + { + DBUtil.close(stmt); + } + } } } diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreChunkReader.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreChunkReader.java index 3fde4ce6ba..1de3985e2d 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreChunkReader.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreChunkReader.java @@ -13,8 +13,8 @@ package org.eclipse.emf.cdo.server.internal.db; import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader; 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.IReferenceMapping; import org.eclipse.emf.cdo.spi.server.StoreChunkReader; import org.eclipse.emf.ecore.EStructuralFeature; @@ -26,7 +26,7 @@ import java.util.List; */ public class DBStoreChunkReader extends StoreChunkReader implements IDBStoreChunkReader { - private IReferenceMapping referenceMapping; + private IListMapping referenceMapping; private StringBuilder builder = new StringBuilder(); @@ -35,7 +35,7 @@ public class DBStoreChunkReader extends StoreChunkReader implements IDBStoreChun super(accessor, revision, feature); IMappingStrategy mappingStrategy = accessor.getStore().getMappingStrategy(); IClassMapping mapping = mappingStrategy.getClassMapping(revision.getEClass()); - referenceMapping = mapping.getReferenceMapping(feature); + referenceMapping = mapping.getListMapping(feature); } @Override @@ -49,7 +49,7 @@ public class DBStoreChunkReader extends StoreChunkReader implements IDBStoreChun { super.addSimpleChunk(index); builder.append(" AND "); - builder.append(CDODBSchema.REFERENCES_IDX); + builder.append(CDODBSchema.LIST_IDX); builder.append("="); builder.append(index); } @@ -59,7 +59,7 @@ public class DBStoreChunkReader extends StoreChunkReader implements IDBStoreChun { super.addRangedChunk(fromIndex, toIndex); builder.append(" AND "); - builder.append(CDODBSchema.REFERENCES_IDX); + builder.append(CDODBSchema.LIST_IDX); builder.append(" BETWEEN "); builder.append(fromIndex); builder.append(" AND "); diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreFactory.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreFactory.java index 1f238772a8..7112195c4a 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreFactory.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/DBStoreFactory.java @@ -7,6 +7,7 @@ * * Contributors: * Eike Stepper - initial API and implementation + * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 */ package org.eclipse.emf.cdo.server.internal.db; @@ -14,7 +15,6 @@ import org.eclipse.emf.cdo.internal.server.RepositoryConfigurator; import org.eclipse.emf.cdo.server.IStore; import org.eclipse.emf.cdo.server.IStoreFactory; import org.eclipse.emf.cdo.server.db.CDODBUtil; -import org.eclipse.emf.cdo.server.db.IJDBCDelegateProvider; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; import org.eclipse.net4j.db.DBUtil; @@ -48,33 +48,10 @@ public class DBStoreFactory implements IStoreFactory public IStore createStore(Element storeConfig) { IMappingStrategy mappingStrategy = getMappingStrategy(storeConfig); - IJDBCDelegateProvider delegateProvider = getDelegateProvider(storeConfig); IDBAdapter dbAdapter = getDBAdapter(storeConfig); DataSource dataSource = getDataSource(storeConfig); IDBConnectionProvider connectionProvider = DBUtil.createConnectionProvider(dataSource); - return CDODBUtil.createStore(mappingStrategy, dbAdapter, connectionProvider, delegateProvider); - } - - private IJDBCDelegateProvider getDelegateProvider(Element storeConfig) - { - NodeList delegateProviderConfigs = storeConfig.getElementsByTagName("jdbcDelegate"); - if (delegateProviderConfigs.getLength() != 1) - { - throw new IllegalStateException("Exactly one delegate provider must be configured for DB store"); - } - - Element delegateProviderConfig = (Element)delegateProviderConfigs.item(0); - String delegateProviderType = delegateProviderConfig.getAttribute("type"); - IJDBCDelegateProvider delegateProvider = CDODBUtil.createDelegateProvider(delegateProviderType); - if (delegateProvider == null) - { - throw new IllegalArgumentException("Unknown JDBC delegate type: " + delegateProviderType); - } - - Map<String, String> properties = RepositoryConfigurator.getProperties(delegateProviderConfig, 1); - delegateProvider.setProperties(properties); - - return delegateProvider; + return CDODBUtil.createStore(mappingStrategy, dbAdapter, connectionProvider); } private IMappingStrategy getMappingStrategy(Element storeConfig) 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 new file mode 100644 index 0000000000..d7bee71d0a --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/MetaDataManager.java @@ -0,0 +1,375 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 + * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 + */ +package org.eclipse.emf.cdo.server.internal.db; + +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDMeta; +import org.eclipse.emf.cdo.common.id.CDOIDMetaRange; +import org.eclipse.emf.cdo.common.id.CDOIDUtil; +import org.eclipse.emf.cdo.common.model.CDOModelUtil; +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.db.IDBStore; +import org.eclipse.emf.cdo.server.db.IMetaDataManager; +import org.eclipse.emf.cdo.server.internal.db.bundle.OM; +import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageInfo; +import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageRegistry; +import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit; + +import org.eclipse.net4j.db.DBException; +import org.eclipse.net4j.db.DBType; +import org.eclipse.net4j.db.DBUtil; +import org.eclipse.net4j.db.IDBRowHandler; +import org.eclipse.net4j.util.lifecycle.Lifecycle; +import org.eclipse.net4j.util.om.monitor.OMMonitor; +import org.eclipse.net4j.util.om.monitor.OMMonitor.Async; +import org.eclipse.net4j.util.om.trace.ContextTracer; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EClassifier; +import org.eclipse.emf.ecore.EEnum; +import org.eclipse.emf.ecore.EModelElement; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EcorePackage; +import org.eclipse.emf.ecore.InternalEObject; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * @author Eike Stepper + */ +public class MetaDataManager extends Lifecycle implements IMetaDataManager +{ + private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, MetaDataManager.class); + + private static Map<EClassifier, DBType> typeMap = new HashMap<EClassifier, DBType>(); + + private static final boolean ZIP_PACKAGE_BYTES = true; + + private IDBStore store; + + static + { + typeMap.put(EcorePackage.eINSTANCE.getEDate(), DBType.TIMESTAMP); + typeMap.put(EcorePackage.eINSTANCE.getEString(), DBType.VARCHAR); + typeMap.put(EcorePackage.eINSTANCE.getEByteArray(), DBType.BLOB); + + typeMap.put(EcorePackage.eINSTANCE.getEBoolean(), DBType.BOOLEAN); + typeMap.put(EcorePackage.eINSTANCE.getEByte(), DBType.SMALLINT); + typeMap.put(EcorePackage.eINSTANCE.getEChar(), DBType.CHAR); + typeMap.put(EcorePackage.eINSTANCE.getEDouble(), DBType.DOUBLE); + typeMap.put(EcorePackage.eINSTANCE.getEFloat(), DBType.FLOAT); + typeMap.put(EcorePackage.eINSTANCE.getEInt(), DBType.INTEGER); + typeMap.put(EcorePackage.eINSTANCE.getELong(), DBType.BIGINT); + typeMap.put(EcorePackage.eINSTANCE.getEShort(), DBType.SMALLINT); + + typeMap.put(EcorePackage.eINSTANCE.getEBooleanObject(), DBType.BOOLEAN); + typeMap.put(EcorePackage.eINSTANCE.getEByteObject(), DBType.SMALLINT); + typeMap.put(EcorePackage.eINSTANCE.getECharacterObject(), DBType.CHAR); + typeMap.put(EcorePackage.eINSTANCE.getEDoubleObject(), DBType.DOUBLE); + typeMap.put(EcorePackage.eINSTANCE.getEFloatObject(), DBType.FLOAT); + typeMap.put(EcorePackage.eINSTANCE.getEIntegerObject(), DBType.INTEGER); + typeMap.put(EcorePackage.eINSTANCE.getELongObject(), DBType.BIGINT); + typeMap.put(EcorePackage.eINSTANCE.getEShortObject(), DBType.SMALLINT); + } + + public MetaDataManager(IDBStore store) + { + this.store = store; + } + + public long getMetaID(EModelElement modelElement) + { + CDOID cdoid = getPackageRegistry().getMetaInstanceMapper().lookupMetaInstanceID((InternalEObject)modelElement); + return CDOIDUtil.getLong(cdoid); + } + + public EModelElement getMetaInstance(long id) + { + CDOIDMeta cdoid = CDOIDUtil.createMeta(id); + InternalEObject metaInstance = getPackageRegistry().getMetaInstanceMapper().lookupMetaInstance(cdoid); + return (EModelElement)metaInstance; + } + + public final EPackage[] loadPackageUnit(Connection connection, InternalCDOPackageUnit packageUnit) + { + String where = CDODBSchema.PACKAGE_UNITS_ID.getName() + "='" + packageUnit.getID() + "'"; + Object[] values = DBUtil.select(connection, where, CDODBSchema.PACKAGE_UNITS_PACKAGE_DATA); + byte[] bytes = (byte[])values[0]; + EPackage ePackage = createEPackage(packageUnit, bytes); + return EMFUtil.getAllPackages(ePackage); + } + + public Collection<InternalCDOPackageUnit> readPackageUnits(Connection connection) + { + final Map<String, InternalCDOPackageUnit> packageUnits = new HashMap<String, InternalCDOPackageUnit>(); + IDBRowHandler unitRowHandler = new IDBRowHandler() + { + public boolean handle(int row, final Object... values) + { + InternalCDOPackageUnit packageUnit = createPackageUnit(); + packageUnit.setOriginalType(CDOPackageUnit.Type.values()[(Integer)values[1]]); + packageUnit.setTimeStamp((Long)values[2]); + packageUnits.put((String)values[0], packageUnit); + return true; + } + }; + + DBUtil.select(connection, unitRowHandler, CDODBSchema.PACKAGE_UNITS_ID, CDODBSchema.PACKAGE_UNITS_ORIGINAL_TYPE, + CDODBSchema.PACKAGE_UNITS_TIME_STAMP); + + final Map<String, List<InternalCDOPackageInfo>> packageInfos = new HashMap<String, List<InternalCDOPackageInfo>>(); + IDBRowHandler infoRowHandler = new IDBRowHandler() + { + public boolean handle(int row, final Object... values) + { + long metaLB = (Long)values[3]; + long metaUB = (Long)values[4]; + CDOIDMetaRange metaIDRange = metaLB == 0 ? null : CDOIDUtil.createMetaRange(CDOIDUtil.createMeta(metaLB), + (int)(metaUB - metaLB) + 1); + + InternalCDOPackageInfo packageInfo = createPackageInfo(); + packageInfo.setPackageURI((String)values[1]); + packageInfo.setParentURI((String)values[2]); + packageInfo.setMetaIDRange(metaIDRange); + + 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; + } + }; + + DBUtil.select(connection, infoRowHandler, CDODBSchema.PACKAGE_INFOS_UNIT, CDODBSchema.PACKAGE_INFOS_URI, + CDODBSchema.PACKAGE_INFOS_PARENT, CDODBSchema.PACKAGE_INFOS_META_LB, CDODBSchema.PACKAGE_INFOS_META_UB); + + for (Entry<String, InternalCDOPackageUnit> entry : packageUnits.entrySet()) + { + String id = entry.getKey(); + InternalCDOPackageUnit packageUnit = entry.getValue(); + + List<InternalCDOPackageInfo> list = packageInfos.get(id); + InternalCDOPackageInfo[] array = list.toArray(new InternalCDOPackageInfo[list.size()]); + packageUnit.setPackageInfos(array); + } + + return packageUnits.values(); + } + + public final void writePackageUnits(Connection connection, InternalCDOPackageUnit[] packageUnits, OMMonitor monitor) + { + try + { + monitor.begin(2); + fillSystemTables(connection, packageUnits, monitor.fork()); + } + finally + { + monitor.done(); + } + } + + public DBType getDBType(EClassifier type) + { + if (type instanceof EClass) + { + return DBType.BIGINT; + } + + if (type instanceof EEnum) + { + return DBType.INTEGER; + } + + DBType dbType = typeMap.get(type); + if (dbType != null) + { + return dbType; + } + + return DBType.VARCHAR; + } + + protected IDBStore getStore() + { + return store; + } + + @Override + protected void doBeforeActivate() throws Exception + { + checkState(store != null, "Store is not set"); + } + + 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) + { + return EMFUtil.createEPackage(packageUnit.getID(), bytes, ZIP_PACKAGE_BYTES, getPackageRegistry()); + } + + private byte[] getEPackageBytes(InternalCDOPackageUnit packageUnit) + { + EPackage ePackage = packageUnit.getTopLevelPackageInfo().getEPackage(); + CDOPackageRegistry packageRegistry = getStore().getRepository().getPackageRegistry(); + return EMFUtil.getEPackageBytes(ePackage, ZIP_PACKAGE_BYTES, packageRegistry); + } + + private void fillSystemTables(Connection connection, InternalCDOPackageUnit packageUnit, OMMonitor monitor) + { + try + { + InternalCDOPackageInfo[] packageInfos = packageUnit.getPackageInfos(); + monitor.begin(1 + packageInfos.length); + + if (TRACER.isEnabled()) + { + TRACER.format("Writing package unit: {0}", packageUnit); + } + + String sql = "INSERT INTO " + CDODBSchema.PACKAGE_UNITS + " VALUES (?, ?, ?, ?)"; + DBUtil.trace(sql); + PreparedStatement pstmt = null; + Async async = monitor.forkAsync(); + + try + { + pstmt = connection.prepareStatement(sql); + pstmt.setString(1, packageUnit.getID()); + pstmt.setInt(2, packageUnit.getOriginalType().ordinal()); + pstmt.setLong(3, packageUnit.getTimeStamp()); + pstmt.setBytes(4, getEPackageBytes(packageUnit)); + + if (pstmt.execute()) + { + throw new DBException("No result set expected"); + } + + if (pstmt.getUpdateCount() == 0) + { + throw new DBException("No row inserted into table " + CDODBSchema.PACKAGE_UNITS); + } + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + DBUtil.close(pstmt); + async.stop(); + } + + for (InternalCDOPackageInfo packageInfo : packageInfos) + { + fillSystemTables(connection, packageInfo, monitor); // Don't fork monitor + } + } + finally + { + monitor.done(); + } + } + + private void fillSystemTables(Connection 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(Connection connection, InternalCDOPackageInfo packageInfo, OMMonitor monitor) + { + if (TRACER.isEnabled()) + { + TRACER.format("Writing package info: {0}", packageInfo); + } + + String packageURI = packageInfo.getPackageURI(); + String parentURI = packageInfo.getParentURI(); + String unitID = packageInfo.getPackageUnit().getID(); + CDOIDMetaRange metaIDRange = packageInfo.getMetaIDRange(); + long metaLB = metaIDRange == null ? 0L : ((CDOIDMeta)metaIDRange.getLowerBound()).getLongValue(); + long metaUB = metaIDRange == null ? 0L : ((CDOIDMeta)metaIDRange.getUpperBound()).getLongValue(); + + String sql = "INSERT INTO " + CDODBSchema.PACKAGE_INFOS + " VALUES (?, ?, ?, ?, ?)"; + DBUtil.trace(sql); + PreparedStatement pstmt = null; + Async async = monitor.forkAsync(); + + try + { + pstmt = connection.prepareStatement(sql); + pstmt.setString(1, packageURI); + pstmt.setString(2, parentURI); + pstmt.setString(3, unitID); + pstmt.setLong(4, metaLB); + pstmt.setLong(5, metaUB); + + if (pstmt.execute()) + { + throw new DBException("No result set expected"); + } + + if (pstmt.getUpdateCount() == 0) + { + throw new DBException("No row inserted into table " + CDODBSchema.PACKAGE_INFOS); + } + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + DBUtil.close(pstmt); + async.stop(); + } + } +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/NullPreparedStatementCache.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/NullPreparedStatementCache.java new file mode 100644 index 0000000000..6387550a0b --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/NullPreparedStatementCache.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 + * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 + */ +package org.eclipse.emf.cdo.server.internal.db; + +import org.eclipse.emf.cdo.server.db.IPreparedStatementCache; +import org.eclipse.emf.cdo.server.internal.db.bundle.OM; + +import org.eclipse.net4j.db.DBException; +import org.eclipse.net4j.db.DBUtil; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.HashSet; + +/** + * @author Stefan Winkler + * @since 2.0 + */ +public class NullPreparedStatementCache extends AbstractPreparedStatementCache implements IPreparedStatementCache +{ + private HashSet<PreparedStatement> allocatedStatements = new HashSet<PreparedStatement>(); + + public NullPreparedStatementCache() + { + } + + public PreparedStatement getPreparedStatement(String sql, ReuseProbability reuseProbability) + { + try + { + PreparedStatement result = getConnection().prepareStatement(sql); + allocatedStatements.add(result); + return result; + } + catch (SQLException ex) + { + throw new DBException(ex); + } + } + + public void releasePreparedStatement(PreparedStatement ps) + { + allocatedStatements.remove(ps); + DBUtil.close(ps); + } + + @Override + protected void doBeforeDeactivate() throws Exception + { + if (!allocatedStatements.isEmpty()) + { + OM.LOG.warn("Possible Leak Detected:"); + for (PreparedStatement ps : allocatedStatements) + { + OM.LOG.warn("- " + ps.toString()); + } + assert false; + } + } +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/ObjectIDIterator.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/ObjectIDIterator.java index 70611f9453..d085ef52f9 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/ObjectIDIterator.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/ObjectIDIterator.java @@ -51,7 +51,7 @@ public abstract class ObjectIDIterator implements CloseableIterator<CDOID> public void close() { - DBUtil.close(currentResultSet); + closeCurrentResultSet(); nextID = null; closed = true; } @@ -99,7 +99,8 @@ public abstract class ObjectIDIterator implements CloseableIterator<CDOID> return true; } - DBUtil.close(currentResultSet); + closeCurrentResultSet(); + currentResultSet = null; return false; } @@ -110,6 +111,11 @@ public abstract class ObjectIDIterator implements CloseableIterator<CDOID> } } + protected void closeCurrentResultSet() + { + DBUtil.close(currentResultSet); + } + public CDOID next() { if (nextID == null) diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/SmartPreparedStatementCache.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/SmartPreparedStatementCache.java new file mode 100644 index 0000000000..96d4d22766 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/SmartPreparedStatementCache.java @@ -0,0 +1,275 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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: + * Stefan Winkler - initial API and implementation + */ +package org.eclipse.emf.cdo.server.internal.db; + +import org.eclipse.emf.cdo.server.internal.db.bundle.OM; + +import org.eclipse.net4j.db.DBException; +import org.eclipse.net4j.util.ImplementationError; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.HashMap; + +/** + * @author Stefan Winkler + * @since 2.0 + */ +public class SmartPreparedStatementCache extends AbstractPreparedStatementCache +{ + private Cache cache; + + private HashMap<PreparedStatement, CachedPreparedStatement> checkedOut = new HashMap<PreparedStatement, CachedPreparedStatement>(); + + public SmartPreparedStatementCache(int capacity) + { + cache = new Cache(capacity); + } + + public PreparedStatement getPreparedStatement(String sql, ReuseProbability reuseProbability) + { + CachedPreparedStatement cachedStatement = cache.remove(sql); + + if (cachedStatement == null) + { + cachedStatement = createCachedPreparedStatement(sql, reuseProbability); + } + + PreparedStatement result = cachedStatement.getPreparedStatement(); + checkedOut.put(result, cachedStatement); + + return result; + } + + public void releasePreparedStatement(PreparedStatement ps) + { + CachedPreparedStatement cachedStatement = checkedOut.remove(ps); + cache.put(cachedStatement); + } + + @Override + protected void doBeforeDeactivate() throws Exception + { + if (!checkedOut.isEmpty()) + { + OM.LOG.warn("Statement leak detected."); + } + } + + private CachedPreparedStatement createCachedPreparedStatement(String sql, ReuseProbability reuseProbability) + { + PreparedStatement stmt; + try + { + stmt = getConnection().prepareStatement(sql); + CachedPreparedStatement result = new CachedPreparedStatement(sql, reuseProbability, stmt); + return result; + } + catch (SQLException ex) + { + throw new DBException(ex); + } + } + + private static final class Cache + { + private CacheList lists[]; + + private HashMap<String, CachedPreparedStatement> lookup; + + private int capacity; + + public Cache(int capacity) + { + this.capacity = capacity; + + lookup = new HashMap<String, CachedPreparedStatement>(capacity); + + lists = new CacheList[ReuseProbability.values().length]; + for (ReuseProbability prob : ReuseProbability.values()) + { + lists[prob.ordinal()] = new CacheList(); + } + } + + public void put(CachedPreparedStatement cachedStatement) + { + // refresh age + cachedStatement.touch(); + + // put into appripriate list + lists[cachedStatement.getProbability().ordinal()].add(cachedStatement); + + // put into lookup table + if (lookup.put(cachedStatement.getSql(), cachedStatement) != null) + { + throw new ImplementationError(cachedStatement.getSql() + " already in cache."); + } + + // handle capacity overflow + if (lookup.size() > capacity) + { + evictOne(); + } + } + + private void evictOne() + { + long maxAge = -1; + int ordinal = -1; + + for (ReuseProbability prob : ReuseProbability.values()) + { + if (!lists[prob.ordinal()].isEmpty()) + { + long age = lists[prob.ordinal()].tail().getAge(); + if (maxAge < age) + { + maxAge = age; + ordinal = prob.ordinal(); + } + } + } + + remove(lists[ordinal].tail().getSql()); + } + + public CachedPreparedStatement remove(String sql) + { + CachedPreparedStatement result = lookup.remove(sql); + if (result == null) + { + return null; + } + else + { + lists[result.getProbability().ordinal()].remove(result); + return result; + } + } + + private class CacheList + { + private CachedPreparedStatement first = null; + + private CachedPreparedStatement last = null; + + public CacheList() + { + }; + + public void add(CachedPreparedStatement s) + { + if (first == null) + { + first = s; + last = s; + s.previous = null; + s.next = null; + } + else + { + first.previous = s; + s.next = first; + first = s; + } + } + + public void remove(CachedPreparedStatement s) + { + if (s == first) + { + first = s.next; + } + if (s.next != null) + { + s.next.previous = s.previous; + } + if (s == last) + { + last = s.previous; + } + if (s.previous != null) + { + s.previous.next = s.next; + } + + s.previous = null; + s.next = null; + } + + public CachedPreparedStatement tail() + { + return last; + } + + public boolean isEmpty() + { + return first == null; + } + } + }; + + private static final class CachedPreparedStatement + { + private long timeStamp; + + private String sql; + + private ReuseProbability probability; + + private PreparedStatement statement; + + /** + * DL field + */ + private CachedPreparedStatement previous; + + /** + * DL field + */ + private CachedPreparedStatement next; + + public CachedPreparedStatement(String sql, ReuseProbability prob, PreparedStatement stmt) + { + this.sql = sql; + probability = prob; + statement = stmt; + timeStamp = System.currentTimeMillis(); + } + + public PreparedStatement getPreparedStatement() + { + return statement; + } + + public long getAge() + { + long currentTime = System.currentTimeMillis(); + return (currentTime - timeStamp) * probability.ordinal(); + } + + public void touch() + { + timeStamp = System.currentTimeMillis(); + } + + public String getSql() + { + return sql; + } + + public ReuseProbability getProbability() + { + return probability; + } + } +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/AbstractJDBCDelegate.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/AbstractJDBCDelegate.java deleted file mode 100644 index 33acb78d42..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/AbstractJDBCDelegate.java +++ /dev/null @@ -1,552 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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: - * Stefan Winkler - initial API and implementation - * Eike Stepper - maintenance - * Stefan Winkler - https://bugs.eclipse.org/bugs/show_bug.cgi?id=259402 - */ -package org.eclipse.emf.cdo.server.internal.db.jdbc; - -import org.eclipse.emf.cdo.common.id.CDOID; -import org.eclipse.emf.cdo.common.id.CDOIDUtil; -import org.eclipse.emf.cdo.common.revision.CDORevision; -import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk; -import org.eclipse.emf.cdo.server.db.CDODBUtil; -import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; -import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader; -import org.eclipse.emf.cdo.server.db.IJDBCDelegate; -import org.eclipse.emf.cdo.server.db.mapping.IAttributeMapping; -import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; -import org.eclipse.emf.cdo.server.db.mapping.IReferenceMapping; -import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; - -import org.eclipse.net4j.db.DBException; -import org.eclipse.net4j.db.DBUtil; -import org.eclipse.net4j.db.IDBConnectionProvider; -import org.eclipse.net4j.util.collection.MoveableList; -import org.eclipse.net4j.util.collection.Pair; -import org.eclipse.net4j.util.lifecycle.Lifecycle; -import org.eclipse.net4j.util.om.monitor.OMMonitor; -import org.eclipse.net4j.util.om.monitor.OMMonitor.Async; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * This abstract implementation of the {@link IJDBCDelegate} interface is used to translate CDO-related objects to base - * types (e.g. CDOIDs to long) and then to delegate the database execution part to the doXYZ methods which should be - * implemented by extenders. The purpose of this is to provide several JDBC strategies (e.g. simple or prepared - * statement database access) depending on the requirements, but a single point of interpreting and transforming - * CDO-internal structures. The JDBCDelegate also keeps open one database connection and one statement which can be used - * to perform operations on the database. Extenders may, but don't have to, use the statement to perform operations. - * - * @author Stefan Winkler - * @since 2.0 - */ -public abstract class AbstractJDBCDelegate extends Lifecycle implements IJDBCDelegate -{ - private IDBStoreAccessor storeAccessor; - - private Connection connection; - - private Statement statement; - - public AbstractJDBCDelegate() - { - } - - @Override - protected void doActivate() throws Exception - { - super.doActivate(); - connection = getConnectionProvider().getConnection(); - connection.setAutoCommit(isReadOnly()); - } - - @Override - protected void doDeactivate() throws Exception - { - DBUtil.close(statement); - statement = null; - - DBUtil.close(connection); - connection = null; - - super.doDeactivate(); - } - - public IDBStoreAccessor getStoreAccessor() - { - return storeAccessor; - } - - public void setStoreAccessor(IDBStoreAccessor storeAccessor) - { - checkInactive(); - this.storeAccessor = storeAccessor; - } - - public IDBConnectionProvider getConnectionProvider() - { - return storeAccessor.getStore().getDBConnectionProvider(); - } - - public boolean isReadOnly() - { - return storeAccessor.isReader(); - } - - public final Connection getConnection() - { - return connection; - } - - public final Statement getStatement() - { - if (statement == null) - { - try - { - statement = getConnection().createStatement(); - } - catch (SQLException ex) - { - throw new DBException(ex); - } - } - - return statement; - } - - public PreparedStatement getPreparedStatement(String sql) - { - try - { - return getConnection().prepareStatement(sql); - } - catch (SQLException ex) - { - throw new DBException(ex); - } - } - - public final void commit(OMMonitor monitor) - { - monitor.begin(); - Async async = monitor.forkAsync(); - - try - { - getConnection().commit(); - } - catch (SQLException ex) - { - throw new DBException(ex); - } - finally - { - async.stop(); - monitor.done(); - } - } - - public final void rollback() - { - try - { - getConnection().rollback(); - } - catch (SQLException ex) - { - throw new DBException(ex); - } - } - - public final void insertAttributes(InternalCDORevision revision, IClassMapping classMapping) - { - doInsertAttributes(classMapping.getTable().getName(), revision, classMapping.getAttributeMappings(), classMapping - .hasFullRevisionInfo()); - } - - public final void updateAttributes(InternalCDORevision cdoRevision, IClassMapping classMapping) - { - InternalCDORevision revision = cdoRevision; - - List<IAttributeMapping> attributeMappings = classMapping.getAttributeMappings(); - if (attributeMappings == null) - { - attributeMappings = Collections.emptyList(); - } - - List<Pair<IAttributeMapping, Object>> attributeChanges = new ArrayList<Pair<IAttributeMapping, Object>>( - attributeMappings.size()); - - for (IAttributeMapping am : classMapping.getAttributeMappings()) - { - attributeChanges.add(new Pair<IAttributeMapping, Object>(am, am.getRevisionValue(revision))); - } - - updateAttributes(revision.getID(), revision.getVersion(), revision.getCreated(), (CDOID)revision.getContainerID(), - revision.getContainingFeatureID(), revision.getResourceID(), attributeChanges, classMapping); - } - - public void updateAttributes(CDOID id, int newVersion, long created, CDOID newContainerId, - int newContainingFeatureId, CDOID newResourceId, List<Pair<IAttributeMapping, Object>> attributeChanges, - IClassMapping classMapping) - { - doUpdateAttributes(classMapping.getTable().getName(), CDOIDUtil.getLong(id), newVersion, created, CDOIDUtil - .getLong(newContainerId), newContainingFeatureId, CDOIDUtil.getLong(newResourceId), attributeChanges, - classMapping.hasFullRevisionInfo()); - } - - public final void updateAttributes(CDOID id, int newVersion, long created, - List<Pair<IAttributeMapping, Object>> attributeChanges, IClassMapping classMapping) - { - doUpdateAttributes(classMapping.getTable().getName(), CDOIDUtil.getLong(id), newVersion, created, attributeChanges, - classMapping.hasFullRevisionInfo()); - } - - public final void updateRevisedForReplace(InternalCDORevision revision, IClassMapping classMapping) - { - doUpdateRevisedForReplace(classMapping.getTable().getName(), revision.getCreated() - 1, CDOIDUtil.getLong(revision - .getID()), revision.getVersion() - 1); - } - - public final void updateRevisedForDetach(CDOID id, long revised, IClassMapping classMapping) - { - doUpdateRevisedForDetach(classMapping.getTable().getName(), revised, CDOIDUtil.getLong(id)); - } - - public final void deleteAttributes(CDOID id, IClassMapping classMapping) - { - doDeleteAttributes(classMapping.getTable().getName(), CDOIDUtil.getLong(id)); - } - - public final void insertReference(CDOID id, int version, int index, CDOID targetId, IReferenceMapping referenceMapping) - { - doInsertReference(referenceMapping.getTable().getName(), getDBID(referenceMapping), CDOIDUtil.getLong(id), version, - index, CDODBUtil.getLong(targetId)); - } - - public void insertReferenceRow(CDOID id, int newVersion, int index, CDOID value, IReferenceMapping referenceMapping) - { - doInsertReferenceRow(referenceMapping.getTable().getName(), getDBID(referenceMapping), CDOIDUtil.getLong(id), - newVersion, CDODBUtil.getLong(value), index); - } - - public void moveReferenceRow(CDOID id, int newVersion, int oldPosition, int newPosition, - IReferenceMapping referenceMapping) - { - doMoveReferenceRow(referenceMapping.getTable().getName(), getDBID(referenceMapping), CDOIDUtil.getLong(id), - newVersion, oldPosition, newPosition); - } - - public void removeReferenceRow(CDOID id, int index, int newVersion, IReferenceMapping referenceMapping) - { - doRemoveReferenceRow(referenceMapping.getTable().getName(), getDBID(referenceMapping), CDOIDUtil.getLong(id), - index, newVersion); - } - - public final void deleteReferences(CDOID id, IReferenceMapping referenceMapping) - { - doDeleteReferences(referenceMapping.getTable().getName(), getDBID(referenceMapping), CDOIDUtil.getLong(id)); - } - - public void updateReference(CDOID id, int version, int index, CDOID targetId, IReferenceMapping referenceMapping) - { - doUpdateReference(referenceMapping.getTable().getName(), getDBID(referenceMapping), CDOIDUtil.getLong(id), version, - index, CDODBUtil.getLong(targetId)); - } - - public final void updateReferenceVersion(CDOID id, int newVersion, IReferenceMapping referenceMapping) - { - doUpdateReferenceVersion(referenceMapping.getTable().getName(), CDOIDUtil.getLong(id), newVersion); - } - - public final boolean selectRevisionAttributes(InternalCDORevision revision, IClassMapping classMapping, String where) - { - List<IAttributeMapping> attributeMappings = classMapping.getAttributeMappings(); - if (attributeMappings == null) - { - attributeMappings = Collections.emptyList(); - } - - boolean withFullRevisionInfo = classMapping.hasFullRevisionInfo(); - ResultSet resultSet = null; - try - { - resultSet = doSelectRevisionAttributes(classMapping.getTable().getName(), CDOIDUtil.getLong(revision.getID()), - attributeMappings, withFullRevisionInfo, where); - - if (!resultSet.next()) - { - return false; - } - - int i = 0; - if (withFullRevisionInfo) - { - InternalCDORevision rev = revision; - rev.setVersion(resultSet.getInt(++i)); - rev.setCreated(resultSet.getLong(++i)); - rev.setRevised(resultSet.getLong(++i)); - rev.setResourceID(CDOIDUtil.createLong(resultSet.getLong(++i))); - rev.setContainerID(CDOIDUtil.createLong(resultSet.getLong(++i))); - rev.setContainingFeatureID(resultSet.getInt(++i)); - } - - if (attributeMappings != null) - { - for (IAttributeMapping attributeMapping : attributeMappings) - { - attributeMapping.extractValue(resultSet, ++i, revision); - } - } - - return true; - } - catch (SQLException ex) - { - throw new DBException(ex); - } - finally - { - close(resultSet); - } - } - - public void selectRevisionReferences(InternalCDORevision revision, IReferenceMapping referenceMapping, - int referenceChunk) - { - MoveableList<Object> list = revision.getList(referenceMapping.getFeature()); - - CDOID source = revision.getID(); - long sourceId = CDOIDUtil.getLong(source); - int version = revision.getVersion(); - - ResultSet resultSet = null; - try - { - resultSet = doSelectRevisionReferences(referenceMapping.getTable().getName(), sourceId, version, - getDBID(referenceMapping), ""); - - while (resultSet.next() && (referenceChunk == CDORevision.UNCHUNKED || --referenceChunk >= 0)) - { - long target = resultSet.getLong(1); - list.add(CDOIDUtil.createLong(target)); - } - - // TODO Optimize this? - while (resultSet.next()) - { - list.add(InternalCDORevision.UNINITIALIZED); - } - } - catch (SQLException ex) - { - throw new DBException(ex); - } - finally - { - close(resultSet); - } - } - - public void selectRevisionReferenceChunks(IDBStoreChunkReader chunkReader, List<Chunk> chunks, - IReferenceMapping referenceMapping, String where) - { - CDOID source = chunkReader.getRevision().getID(); - long sourceId = CDOIDUtil.getLong(source); - int version = chunkReader.getRevision().getVersion(); - - ResultSet resultSet = null; - - try - { - resultSet = doSelectRevisionReferences(referenceMapping.getTable().getName(), sourceId, version, - getDBID(referenceMapping), where); - - Chunk chunk = null; - int chunkSize = 0; - int chunkIndex = 0; - int indexInChunk = 0; - - while (resultSet.next()) - { - long target = resultSet.getLong(1); - if (chunk == null) - { - chunk = chunks.get(chunkIndex++); - chunkSize = chunk.size(); - } - - chunk.add(indexInChunk++, CDOIDUtil.createLong(target)); - if (indexInChunk == chunkSize) - { - chunk = null; - indexInChunk = 0; - } - } - } - catch (SQLException ex) - { - throw new DBException(ex); - } - finally - { - close(resultSet); - } - } - - private long getDBID(IReferenceMapping referenceMapping) - { - if (referenceMapping.isWithFeature()) - { - return storeAccessor.getStore().getMetaID(referenceMapping.getFeature()); - } - - return 0; - } - - /** - * Close the given result set and the statement, if this is needed (which is the case, iff the resultSet's statement - * is not the one which is kept open by this instance). - */ - private void close(ResultSet resultSet) - { - Statement stmt = null; - - try - { - stmt = resultSet.getStatement(); - } - catch (Exception ex) - { - // Ignore - } - finally - { - DBUtil.close(resultSet); - } - - // if the statement is one that has been created for the operation only - // release it. - if (stmt != statement) - { - releaseStatement(stmt); - } - } - - /** - * Release a statement which has been used by the doSelectXxx implementations to create the respective ResultSet. This - * must only be called with statements created by subclasses. Subclasses should override to handle special cases like - * cached statements which are kept open. - * - * @param stmt - * the statement to close - */ - protected void releaseStatement(Statement stmt) - { - DBUtil.close(stmt); - } - - /** - * Insert an attribute row. - */ - protected abstract void doInsertAttributes(String tableName, CDORevision revision, - List<IAttributeMapping> attributeMappings, boolean withFullRevisionInfo); - - /** - * Update an attribute row. - */ - protected abstract void doUpdateAttributes(String name, long long1, int newVersion, long created, - List<Pair<IAttributeMapping, Object>> attributeChanges, boolean hasFullRevisionInfo); - - /** - * Update an attribute row including containment and resource attributes. - */ - protected abstract void doUpdateAttributes(String name, long long1, int newVersion, long created, - long newContainerId, int newContainingFeatureId, long newResourceId, - List<Pair<IAttributeMapping, Object>> attributeChanges, boolean hasFullRevisionInfo); - - /** - * Set the revised date of a cdoid (the cdoid is to be detached) - */ - protected abstract void doUpdateRevisedForDetach(String tableName, long revised, long cdoid); - - /** - * Set the revised date of a specific revision's previous version (the previous version is to be replaced). - */ - protected abstract void doUpdateRevisedForReplace(String tableName, long revisedStamp, long cdoid, int version); - - /** - * Delete an attribute row. - */ - protected abstract void doDeleteAttributes(String name, long cdoid1); - - /** - * Insert one reference of a particular CDOID and adjusts indexes. - */ - protected abstract void doInsertReferenceRow(String tableName, long metaID, long cdoid, int newVersion, long l, - int index); - - /** - * Insert a reference row. Note: this is likely to be replaced by an implementation that supports storing multiple - * references in one batch. - */ - protected abstract void doInsertReference(String tableName, long metaID, long source, int version, int i, long target); - - /** - * Update the target ID of one reference of a particular CDOID. - */ - protected abstract void doUpdateReference(String name, long metaID, long sourceId, int newVersion, int index, - long targetId); - - /** - * Moves one reference of a particular CDOID and adjusts indexes. - */ - protected abstract void doMoveReferenceRow(String tableName, long metaID, long cdoid, int newVersion, - int oldPosition, int newPosition); - - /** - * Delete all references of a particular CDOID. - */ - protected abstract void doDeleteReferences(String tableName, long metaID, long cdoid); - - /** - * Deletes one reference of a particular CDOID and adjusts indexes. - * - * @param newVersion - */ - protected abstract void doRemoveReferenceRow(String tableName, long metaID, long cdoid, int index, int newVersion); - - /** - * Update all references of cdoid to newVersion - */ - protected abstract void doUpdateReferenceVersion(String tableName, long cdoid, int newVersion); - - /** - * Select a revision's attributes. The caller is resposible for closing resultSet and associated statement, if - * appropriate. - */ - protected abstract ResultSet doSelectRevisionAttributes(String tableName, long revisionId, - List<IAttributeMapping> attributeMappings, boolean hasFullRevisionInfo, String where) throws SQLException; - - /** - * Select a revision's references (or a part thereof) The caller is resposible for closing resultSet and associated - * statement, if appropriate. - */ - protected abstract ResultSet doSelectRevisionReferences(String tableName, long sourceId, int version, long metaID, - String where) throws SQLException; -} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/JDBCPerformanceReporter.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/JDBCPerformanceReporter.java deleted file mode 100644 index f45a982705..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/JDBCPerformanceReporter.java +++ /dev/null @@ -1,334 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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.jdbc; - -import org.eclipse.emf.cdo.common.id.CDOID; -import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk; -import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; -import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader; -import org.eclipse.emf.cdo.server.db.IJDBCDelegate; -import org.eclipse.emf.cdo.server.db.mapping.IAttributeMapping; -import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; -import org.eclipse.emf.cdo.server.db.mapping.IReferenceMapping; -import org.eclipse.emf.cdo.server.internal.db.bundle.OM; -import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; - -import org.eclipse.net4j.util.collection.Pair; -import org.eclipse.net4j.util.lifecycle.Lifecycle; -import org.eclipse.net4j.util.lifecycle.LifecycleUtil; -import org.eclipse.net4j.util.om.monitor.OMMonitor; -import org.eclipse.net4j.util.om.trace.ContextTracer; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.Statement; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * This class is only to be used in tests (there is a static data aggregation member!). - * - * @author Stefan Winkler - * @since 2.0 - */ -public class JDBCPerformanceReporter extends Lifecycle implements IJDBCDelegate -{ - private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, JDBCPerformanceReporter.class); - - private static Map<String, TimeData> timeData = Collections.synchronizedMap(new HashMap<String, TimeData>()); - - private IJDBCDelegate delegate; - - public JDBCPerformanceReporter() - { - } - - public IJDBCDelegate getDelegate() - { - return delegate; - } - - public void setDelegate(IJDBCDelegate delegate) - { - checkInactive(); - this.delegate = delegate; - } - - public Connection getConnection() - { - return delegate.getConnection(); - } - - public PreparedStatement getPreparedStatement(String sql) - { - return delegate.getPreparedStatement(sql); - } - - public Statement getStatement() - { - return delegate.getStatement(); - } - - public void insertAttributes(InternalCDORevision revision, IClassMapping classMapping) - { - long time = System.currentTimeMillis(); - delegate.insertAttributes(revision, classMapping); - time = System.currentTimeMillis() - time; - - registerCall("insertAttributes", time); - } - - public void insertReference(CDOID id, int version, int index, CDOID targetId, IReferenceMapping referenceMapping) - { - long time = System.currentTimeMillis(); - delegate.insertReference(id, version, index, targetId, referenceMapping); - time = System.currentTimeMillis() - time; - registerCall("insertReferenceDbId", time); - } - - public void flush(OMMonitor monitor) - { - long time = System.currentTimeMillis(); - delegate.flush(monitor); - time = System.currentTimeMillis() - time; - registerCall("write", time); - } - - public void commit(OMMonitor monitor) - { - delegate.commit(monitor); - } - - public void rollback() - { - delegate.rollback(); - } - - public boolean selectRevisionAttributes(InternalCDORevision revision, IClassMapping classMapping, String where) - { - long time = System.currentTimeMillis(); - boolean result = delegate.selectRevisionAttributes(revision, null, where); - time = System.currentTimeMillis() - time; - registerCall("selectAttributes", time); - return result; - } - - public void selectRevisionReferenceChunks(IDBStoreChunkReader chunkReader, List<Chunk> chunks, - IReferenceMapping referenceMapping, String where) - { - long time = System.currentTimeMillis(); - delegate.selectRevisionReferenceChunks(chunkReader, chunks, referenceMapping, where); - time = System.currentTimeMillis() - time; - registerCall("selectReferencesChunks", time); - } - - public void selectRevisionReferences(InternalCDORevision revision, IReferenceMapping referenceMapping, - int referenceChunk) - { - long time = System.currentTimeMillis(); - delegate.selectRevisionReferences(revision, referenceMapping, referenceChunk); - time = System.currentTimeMillis() - time; - registerCall("selectReferences", time); - } - - public final void updateRevisedForReplace(InternalCDORevision revision, IClassMapping classMapping) - { - long time = System.currentTimeMillis(); - delegate.updateRevisedForReplace(revision, classMapping); - time = System.currentTimeMillis() - time; - registerCall("updateRevisedForReplace", time); - } - - public final void updateRevisedForDetach(CDOID cdoid, long revised, IClassMapping classMapping) - { - long time = System.currentTimeMillis(); - delegate.updateRevisedForDetach(cdoid, revised, classMapping); - time = System.currentTimeMillis() - time; - registerCall("updateRevisedForDetach", time); - } - - public void deleteAttributes(CDOID id, IClassMapping classMapping) - { - long time = System.currentTimeMillis(); - delegate.deleteAttributes(id, classMapping); - time = System.currentTimeMillis() - time; - registerCall("deleteAttributes", time); - } - - public void deleteReferences(CDOID id, IReferenceMapping referenceMapping) - { - long time = System.currentTimeMillis(); - delegate.deleteReferences(id, referenceMapping); - time = System.currentTimeMillis() - time; - registerCall("deleteReferences", time); - } - - public void updateAttributes(InternalCDORevision revision, IClassMapping classMapping) - { - long time = System.currentTimeMillis(); - delegate.updateAttributes(revision, classMapping); - time = System.currentTimeMillis() - time; - registerCall("updateAllAttributes", time); - } - - public void updateAttributes(CDOID id, int newVersion, long created, - List<Pair<IAttributeMapping, Object>> attributeChanges, IClassMapping classMapping) - { - long time = System.currentTimeMillis(); - delegate.updateAttributes(id, newVersion, created, attributeChanges, classMapping); - time = System.currentTimeMillis() - time; - registerCall("updateAttributes", time); - } - - public void updateReferenceVersion(CDOID id, int newVersion, IReferenceMapping referenceMapping) - { - long time = System.currentTimeMillis(); - delegate.updateReferenceVersion(id, newVersion, referenceMapping); - time = System.currentTimeMillis() - time; - registerCall("updateReferenceVersion", time); - } - - public void insertReferenceRow(CDOID id, int newVersion, int index, CDOID value, IReferenceMapping referenceMapping) - { - long time = System.currentTimeMillis(); - delegate.insertReferenceRow(id, newVersion, index, value, referenceMapping); - time = System.currentTimeMillis() - time; - registerCall("insertReferenceRow", time); - } - - public void updateReference(CDOID id, int newVersion, int index, CDOID value, IReferenceMapping referenceMapping) - { - long time = System.currentTimeMillis(); - delegate.updateReference(id, newVersion, index, value, referenceMapping); - time = System.currentTimeMillis() - time; - registerCall("updateReference", time); - } - - public void moveReferenceRow(CDOID id, int newVersion, int oldPosition, int newPosition, - IReferenceMapping referenceMapping) - { - long time = System.currentTimeMillis(); - delegate.moveReferenceRow(id, newVersion, oldPosition, newPosition, referenceMapping); - time = System.currentTimeMillis() - time; - registerCall("moveReferenceRow", time); - } - - public void removeReferenceRow(CDOID id, int index, int newVersion, IReferenceMapping referenceMapping) - { - long time = System.currentTimeMillis(); - delegate.removeReferenceRow(id, index, newVersion, referenceMapping); - time = System.currentTimeMillis() - time; - registerCall("removeReferenceRow", time); - } - - public void updateAttributes(CDOID id, int newVersion, long created, CDOID newContainerId, - int newContainingFeatureId, CDOID newResourceId, List<Pair<IAttributeMapping, Object>> attributeChanges, - IClassMapping classMapping) - { - long time = System.currentTimeMillis(); - delegate.updateAttributes(id, newVersion, created, newContainerId, newContainingFeatureId, newResourceId, - attributeChanges, classMapping); - time = System.currentTimeMillis() - time; - registerCall("updateAttributes_with_containment", time); - } - - public void setStoreAccessor(IDBStoreAccessor storeAccessor) - { - delegate.setStoreAccessor(storeAccessor); - } - - @Override - protected void doBeforeActivate() throws Exception - { - super.doBeforeActivate(); - checkState(delegate, "delegate"); - } - - @Override - protected void doActivate() throws Exception - { - LifecycleUtil.activate(delegate); - super.doActivate(); - } - - @Override - protected void doDeactivate() throws Exception - { - report(); - super.doDeactivate(); - LifecycleUtil.deactivate(delegate); - } - - public static void report() - { - for (TimeData td : timeData.values()) - { - td.report(TRACER); - } - } - - private static void registerCall(String method, long time) - { - TimeData data = timeData.get(method); - if (data == null) - { - data = new TimeData(method); - timeData.put(method, data); - } - - data.registerCall(time); - } - - /** - * @author Stefan Winkler - * @since 2.0 - */ - private static final class TimeData - { - private String method; - - private long numberOfCalls = 0; - - private long timeMax = Integer.MIN_VALUE; - - private long timeMin = Integer.MAX_VALUE; - - private long timeTotal = 0; - - public TimeData(String method) - { - this.method = method; - } - - public synchronized void registerCall(long time) - { - if (timeMin > time) - { - timeMin = time; - } - if (timeMax < time) - { - timeMax = time; - } - - numberOfCalls++; - timeTotal += time; - } - - public void report(ContextTracer tracer) - { - tracer.format("{0}: {1} calls, {2} avg, {3} min, {4} max", method, numberOfCalls, timeTotal / numberOfCalls, - timeMin, timeMax); - } - } -} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/PreparedStatementJDBCDelegate.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/PreparedStatementJDBCDelegate.java deleted file mode 100644 index 7634e77155..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/PreparedStatementJDBCDelegate.java +++ /dev/null @@ -1,1661 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 - * Stefan Winkler - https://bugs.eclipse.org/bugs/show_bug.cgi?id=259402 - */ -package org.eclipse.emf.cdo.server.internal.db.jdbc; - -import org.eclipse.emf.cdo.common.id.CDOID; -import org.eclipse.emf.cdo.common.id.CDOIDUtil; -import org.eclipse.emf.cdo.common.revision.CDORevision; -import org.eclipse.emf.cdo.server.db.CDODBUtil; -import org.eclipse.emf.cdo.server.db.mapping.IAttributeMapping; -import org.eclipse.emf.cdo.server.internal.db.CDODBSchema; -import org.eclipse.emf.cdo.server.internal.db.bundle.OM; -import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; - -import org.eclipse.net4j.db.DBException; -import org.eclipse.net4j.db.DBUtil; -import org.eclipse.net4j.util.collection.Pair; -import org.eclipse.net4j.util.om.monitor.OMMonitor; -import org.eclipse.net4j.util.om.monitor.OMMonitor.Async; -import org.eclipse.net4j.util.om.trace.ContextTracer; -import org.eclipse.net4j.util.ref.ReferenceValueMap; - -import org.eclipse.emf.ecore.EEnumLiteral; - -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.sql.Timestamp; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -/** - * @author Stefan Winkler - * @since 2.0 - */ -public class PreparedStatementJDBCDelegate extends AbstractJDBCDelegate -{ - /** - * Value for {@link #cachingFlag}: Guess if caching is needed - */ - public static final String CACHE_STMTS_GUESS = "guess"; - - /** - * Value for {@link #cachingFlag}: Turn caching on - */ - public static final String CACHE_STMTS_TRUE = "true"; - - /** - * Value for {@link #cachingFlag}: Turn caching off - */ - public static final String CACHE_STMTS_FALSE = "false"; - - private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, PreparedStatementJDBCDelegate.class); - - private static final String SQL_UPDATE_REVISE_VERSION = " SET " + CDODBSchema.ATTRIBUTES_REVISED + " = ? WHERE " - + CDODBSchema.ATTRIBUTES_ID + " = ? AND " + CDODBSchema.ATTRIBUTES_VERSION + " = ?"; - - private static final String SQL_UPDATE_REVISE_UNREVISED = " SET " + CDODBSchema.ATTRIBUTES_REVISED + " = ? WHERE " - + CDODBSchema.ATTRIBUTES_ID + " = ? AND " + CDODBSchema.ATTRIBUTES_REVISED + " = 0"; - - private static final String SQL_INSERT_REFERENCE_WITH_DBID = " VALUES (?, ?, ?, ?, ?)"; - - private static final String SQL_INSERT_REFERENCE = " VALUES (?, ?, ?, ?)"; - - /** - * Cache for preparedStatements used in diverse methods - */ - private Map<CacheKey, WrappedPreparedStatement> statementCache = null; - - /** - * Container for dirty statements. A statement is considered 'dirty', if addBatch was called, but not executeBatch. - */ - private Map<CacheKey, PreparedStatement> dirtyStatements = null; - - /** - * This flag determines, if prepared statements should be cached within this delegate. Its value is guessed in - * {@link #postInitConnection()} based on the fact if the JDBC driver supports pooled statements. If it does, caching - * in the delegate is unnecessary. - */ - private boolean cacheStatements; - - private CachingEnablement cachingEnablement; - - /** - * This statement is used for unprepared batched statements like in - * {@link #doUpdateAttributes(String, long, int, long, List, boolean)} - */ - private Statement miscStatement = null; - - public PreparedStatementJDBCDelegate() - { - } - - @Override - protected void doActivate() throws Exception - { - super.doActivate(); - dirtyStatements = new ReferenceValueMap.Strong<CacheKey, PreparedStatement>(); - - switch (cachingEnablement) - { - case ENABLED: - cacheStatements = true; - break; - - case DISABLED: - cacheStatements = false; - break; - - case GUESS: - try - { - cacheStatements = !getConnection().getMetaData().supportsStatementPooling(); - } - catch (SQLException ex) - { - OM.LOG.warn("Failed to guess JDBC statement pooling. Activating cache, just to be sure ...", ex); - cacheStatements = true; - } - } - - if (TRACER.isEnabled()) - { - TRACER.trace("JDBC PreparedStatement caching is " + (cacheStatements ? "enabled." : "NOT enabled.")); - } - - if (cacheStatements) - { - // initialize cache ... - statementCache = new ReferenceValueMap.Soft<CacheKey, WrappedPreparedStatement>(); - } - } - - @Override - protected void doBeforeDeactivate() throws Exception - { - for (PreparedStatement ps : dirtyStatements.values()) - { - DBUtil.close(ps); - } - - dirtyStatements.clear(); - if (cacheStatements) - { - for (WrappedPreparedStatement ps : statementCache.values()) - { - DBUtil.close(ps.getWrappedStatement()); - } - - statementCache.clear(); - } - - super.doBeforeDeactivate(); - } - - public CachingEnablement getCachingEnablement() - { - return cachingEnablement; - } - - public void setCachingEnablement(CachingEnablement cachingEnablement) - { - checkInactive(); - this.cachingEnablement = cachingEnablement; - } - - public void flush(OMMonitor monitor) - { - try - { - monitor.begin(dirtyStatements.size() + 1); - - if (miscStatement != null) - { - Async async = monitor.forkAsync(); - try - { - int[] results = miscStatement.executeBatch(); - for (int result : results) - { - checkState(result == 1, "Batch of misc statements did not return '1'"); - } - } - catch (SQLException ex) - { - throw new DBException("Batch execution failed for misc statement.", ex); - } - finally - { - try - { - miscStatement.close(); - } - catch (SQLException ex) - { - // eat up ... - } - miscStatement = null; - async.stop(); - } - } - - for (Entry<CacheKey, PreparedStatement> entry : dirtyStatements.entrySet()) - { - try - { - int[] results; - Async async = monitor.forkAsync(); - - try - { - results = entry.getValue().executeBatch(); - } - finally - { - async.stop(); - } - - if (TRACER.isEnabled()) - { - TRACER.format("Executing batch for {0} [{1}]", entry.getKey().toString(), entry.getValue()); - } - - for (int result : results) - { - checkState(result != Statement.EXECUTE_FAILED, "Batch execution returned EXECUTE_FAILED!"); - } - } - catch (SQLException ex) - { - throw new DBException("Batch execution failed for " + entry.getKey().toString() + " [" + entry.getValue() - + "]", ex); - } - } - } - finally - { - if (!cacheStatements) - { - if (TRACER.isEnabled()) - { - TRACER.format("Closing prepared statements."); - } - - for (PreparedStatement ps : dirtyStatements.values()) - { - DBUtil.close(ps); - } - } - else - { - if (TRACER.isEnabled()) - { - TRACER.format("Re-caching prepared statements."); - } - - for (Entry<CacheKey, PreparedStatement> entry : dirtyStatements.entrySet()) - { - cacheStatement(entry.getKey(), entry.getValue()); - } - } - - dirtyStatements.clear(); - - monitor.done(); - } - } - - @Override - protected void doInsertAttributes(String tableName, CDORevision rev, List<IAttributeMapping> attributeMappings, - boolean withFullRevisionInfo) - { - boolean firstBatch = false; - InternalCDORevision revision = (InternalCDORevision)rev; - - if (attributeMappings == null) - { - attributeMappings = Collections.emptyList(); - } - - PreparedStatement stmt = getDirtyStatement(StmtType.INSERT_ATTRIBUTES, tableName); - if (stmt == null && cacheStatements) - { - firstBatch = true; - stmt = getAndRemoveCachedStatement(StmtType.INSERT_ATTRIBUTES, tableName); - } - - try - { - firstBatch = true; - if (stmt == null) - { - StringBuilder sql = new StringBuilder(); - - sql.append("INSERT INTO "); - sql.append(tableName); - sql.append(" VALUES (?, ?, "); - if (withFullRevisionInfo) - { - sql.append("?, ?, ?, ?, ?, ?"); - } - - for (int i = 0; i < attributeMappings.size(); i++) - { - sql.append(", ?"); - } - - sql.append(")"); - stmt = getConnection().prepareStatement(sql.toString()); - } - - int col = 1; - if (TRACER.isEnabled()) - { - TRACER.trace(stmt.toString()); - } - - stmt.setLong(col++, CDOIDUtil.getLong(revision.getID())); - stmt.setInt(col++, revision.getVersion()); - if (withFullRevisionInfo) - { - stmt.setLong(col++, getStoreAccessor().getStore().getMetaID(revision.getEClass())); - stmt.setLong(col++, revision.getCreated()); - stmt.setLong(col++, revision.getRevised()); - stmt.setLong(col++, CDOIDUtil.getLong(revision.getResourceID())); - stmt.setLong(col++, CDODBUtil.getLong((CDOID)revision.getContainerID())); - stmt.setInt(col++, revision.getContainingFeatureID()); - } - - for (IAttributeMapping attributeMapping : attributeMappings) - { - Object value = attributeMapping.getRevisionValue(revision); - - if (value == null) - { - stmt.setNull(col++, attributeMapping.getField().getType().getCode()); - } - else if (value instanceof java.util.Date) - { - // BUG 217255 - stmt.setTimestamp(col++, new Timestamp(((Date)value).getTime())); - } - else if (value instanceof EEnumLiteral) - { - stmt.setInt(col++, ((EEnumLiteral)value).getValue()); - } - else - { - stmt.setObject(col++, value); - } - } - - if (firstBatch) - { - addDirtyStatement(StmtType.INSERT_ATTRIBUTES, tableName, stmt); - } - - stmt.addBatch(); - } - catch (SQLException e) - { - throw new DBException(e); - } - } - - @Override - protected void doUpdateAttributes(String tableName, long cdoid, int newVersion, long created, - List<Pair<IAttributeMapping, Object>> attributeChanges, boolean hasFullRevisionInfo) - { - StringBuilder builder = new StringBuilder(); - builder.append("UPDATE "); - builder.append(tableName); - builder.append(" SET "); - builder.append(CDODBSchema.ATTRIBUTES_VERSION); - builder.append(" = "); - builder.append(newVersion); - builder.append(", "); - builder.append(CDODBSchema.ATTRIBUTES_CREATED); - builder.append(" = "); - builder.append(created); - - for (Pair<IAttributeMapping, Object> attributeChange : attributeChanges) - { - IAttributeMapping attributeMapping = attributeChange.getElement1(); - builder.append(", "); - builder.append(attributeMapping.getField()); - builder.append(" = "); - attributeMapping.appendValue(builder, attributeChange.getElement2()); - } - - builder.append(" WHERE "); - builder.append(CDODBSchema.ATTRIBUTES_ID); - builder.append(" = "); - builder.append(cdoid); - - String sql = builder.toString(); - - if (TRACER.isEnabled()) - { - TRACER.trace("Batching misc statement:" + sql); - } - - try - { - if (miscStatement == null) - { - miscStatement = getConnection().createStatement(); - } - miscStatement.addBatch(sql); - } - catch (SQLException ex) - { - throw new DBException(ex); - } - } - - @Override - protected void doUpdateAttributes(String tableName, long cdoid, int newVersion, long created, long newContainerId, - int newContainingFeatureId, long newResourceId, List<Pair<IAttributeMapping, Object>> attributeChanges, - boolean hasFullRevisionInfo) - { - StringBuilder builder = new StringBuilder(); - builder.append("UPDATE "); - builder.append(tableName); - builder.append(" SET "); - builder.append(CDODBSchema.ATTRIBUTES_VERSION); - builder.append(" = "); - builder.append(newVersion); - builder.append(", "); - builder.append(CDODBSchema.ATTRIBUTES_CREATED); - builder.append(" = "); - builder.append(created); - builder.append(", "); - builder.append(CDODBSchema.ATTRIBUTES_CONTAINER); - builder.append(" = "); - builder.append(newContainerId); - - builder.append(", "); - builder.append(CDODBSchema.ATTRIBUTES_FEATURE); - builder.append(" = "); - builder.append(newContainingFeatureId); - - builder.append(", "); - builder.append(CDODBSchema.ATTRIBUTES_RESOURCE); - builder.append(" = "); - builder.append(newResourceId); - - for (Pair<IAttributeMapping, Object> attributeChange : attributeChanges) - { - IAttributeMapping attributeMapping = attributeChange.getElement1(); - builder.append(", "); - builder.append(attributeMapping.getField()); - builder.append(" = "); - attributeMapping.appendValue(builder, attributeChange.getElement2()); - } - - builder.append(" WHERE "); - builder.append(CDODBSchema.ATTRIBUTES_ID); - builder.append(" = "); - builder.append(cdoid); - - String sql = builder.toString(); - - if (TRACER.isEnabled()) - { - TRACER.trace(sql); - } - - try - { - if (miscStatement == null) - { - miscStatement = getConnection().createStatement(); - } - miscStatement.addBatch(sql); - } - catch (SQLException ex) - { - throw new DBException(ex); - } - } - - @Override - protected void doUpdateRevisedForReplace(String tableName, long revisedStamp, long cdoid, int version) - { - PreparedStatement stmt = null; - if (cacheStatements) - { - stmt = getCachedStatement(StmtType.REVISE_VERSION, tableName); - } - - try - { - if (stmt == null) - { - StringBuilder sql = new StringBuilder("UPDATE "); - sql.append(tableName); - sql.append(SQL_UPDATE_REVISE_VERSION); - stmt = getConnection().prepareStatement(sql.toString()); - - if (cacheStatements) - { - cacheStatement(StmtType.REVISE_VERSION, tableName, stmt); - } - } - - stmt.setLong(1, revisedStamp); - stmt.setLong(2, cdoid); - stmt.setInt(3, version); - if (TRACER.isEnabled()) - { - TRACER.trace(stmt.toString()); - } - - stmt.execute(); - } - catch (SQLException e) - { - throw new DBException(e); - } - finally - { - if (!cacheStatements) - { - DBUtil.close(stmt); - } - } - } - - @Override - protected void doUpdateRevisedForDetach(String tableName, long revisedStamp, long cdoid) - { - PreparedStatement stmt = null; - if (cacheStatements) - { - stmt = getCachedStatement(StmtType.REVISE_UNREVISED, tableName); - } - - try - { - if (stmt == null) - { - StringBuilder sql = new StringBuilder("UPDATE "); - sql.append(tableName); - sql.append(SQL_UPDATE_REVISE_UNREVISED); - stmt = getConnection().prepareStatement(sql.toString()); - - if (cacheStatements) - { - cacheStatement(StmtType.REVISE_UNREVISED, tableName, stmt); - } - } - - stmt.setLong(1, revisedStamp); - stmt.setLong(2, cdoid); - if (TRACER.isEnabled()) - { - TRACER.trace(stmt.toString()); - } - - stmt.execute(); - } - catch (SQLException e) - { - throw new DBException(e); - } - finally - { - if (!cacheStatements) - { - DBUtil.close(stmt); - } - } - } - - /* - * This has been the preparedStatement version of updateAttributes. Does not make sense now, as amount of attributes - * is variable. Preparing for any number of attributes is not very intelligent ... - * @Override protected void doUpdateAllAttributes(String tableName, long cdoid, int version, long created, - * List<Pair<IAttributeMapping, Object>> attributeChanges, boolean withFullRevisionInfo) { boolean firstBatch = false; - * PreparedStatement stmt = getDirtyStatement(StmtType.UPDATE_ATTRIBUTES, tableName); if (stmt == null && - * cacheStatements) { firstBatch = true; stmt = getAndRemoveCachedStatement(StmtType.UPDATE_ATTRIBUTES, tableName); } - * try { firstBatch = true; if (stmt == null) { StringBuilder sql = new StringBuilder(); sql.append("UPDATE "); - * sql.append(tableName); sql.append(" SET "); sql.append(CDODBSchema.ATTRIBUTES_VERSION); sql.append(" = ? "); if - * (withFullRevisionInfo) { sql.append(", "); sql.append(CDODBSchema.ATTRIBUTES_RESOURCE); sql.append(" = ?,"); - * sql.append(CDODBSchema.ATTRIBUTES_CONTAINER); sql.append(" = ?,"); sql.append(CDODBSchema.ATTRIBUTES_FEATURE); - * sql.append(" = ?"); } for (IAttributeMapping attributeMapping : attributeMappings) { sql.append(", "); - * sql.append(attributeMapping.getField()); sql.append(" = ?"); } sql.append(" WHERE "); - * sql.append(CDODBSchema.ATTRIBUTES_ID); sql.append(" = ? "); stmt = - * getConnection().prepareStatement(sql.toString()); } int col = 1; if (TRACER.isEnabled()) { - * TRACER.trace(stmt.toString()); } stmt.setInt(col++, revision.getVersion()); if (withFullRevisionInfo) { - * stmt.setLong(col++, CDOIDUtil.getLong(revision.getResourceID())); stmt.setLong(col++, - * CDOIDUtil.getLong((CDOID)revision.getContainerID())); stmt.setInt(col++, revision.getContainingFeatureID()); } for - * (IAttributeMapping attributeMapping : attributeMappings) { Object value = - * attributeMapping.getRevisionValue(revision); if (value == null) { stmt.setNull(col++, - * attributeMapping.getField().getType().getCode()); } else { stmt.setObject(col++, value); } } stmt.setLong(col++, - * CDOIDUtil.getLong(revision.getID())); if (firstBatch) { addDirtyStatement(StmtType.UPDATE_ATTRIBUTES, tableName, - * stmt); } stmt.addBatch(); } catch (SQLException e) { throw new DBException(e); } } - */ - - @Override - protected void doDeleteAttributes(String tableName, long cdoid) - { - PreparedStatement stmt = null; - if (cacheStatements) - { - stmt = getCachedStatement(StmtType.DELETE_ATTRIBUTES, tableName); - } - - try - { - if (stmt == null) - { - StringBuilder sql = new StringBuilder("DELETE FROM "); - sql.append(tableName); - sql.append(" WHERE "); - sql.append(CDODBSchema.ATTRIBUTES_ID); - sql.append(" = ? "); - - stmt = getConnection().prepareStatement(sql.toString()); - if (cacheStatements) - { - cacheStatement(StmtType.DELETE_ATTRIBUTES, tableName, stmt); - } - } - - stmt.setLong(1, cdoid); - if (TRACER.isEnabled()) - { - TRACER.trace(stmt.toString()); - } - - stmt.execute(); - } - catch (SQLException e) - { - throw new DBException(e); - } - finally - { - if (!cacheStatements) - { - DBUtil.close(stmt); - } - } - } - - @Override - protected void doInsertReference(String tableName, long dbID, long source, int version, int index, long target) - { - PreparedStatement stmt = null; - if (cacheStatements) - { - stmt = getCachedStatement(StmtType.INSERT_REFERENCES, tableName); - } - - try - { - if (stmt == null) - { - StringBuilder sql = new StringBuilder("INSERT INTO "); - sql.append(tableName); - sql.append(dbID != 0 ? SQL_INSERT_REFERENCE_WITH_DBID : SQL_INSERT_REFERENCE); - stmt = getConnection().prepareStatement(sql.toString()); - if (cacheStatements) - { - cacheStatement(StmtType.INSERT_REFERENCES, tableName, stmt); - } - } - - int idx = 1; - if (dbID != 0) - { - stmt.setLong(idx++, dbID); - } - - stmt.setLong(idx++, source); - stmt.setInt(idx++, version); - stmt.setInt(idx++, index); - stmt.setLong(idx++, target); - if (TRACER.isEnabled()) - { - TRACER.trace(stmt.toString()); - } - - stmt.execute(); - } - catch (SQLException e) - { - throw new DBException(e); - } - finally - { - if (!cacheStatements) - { - DBUtil.close(stmt); - } - } - } - - @Override - protected void doInsertReferenceRow(String tableName, long metaID, long cdoid, int newVersion, long target, int index) - { - move1up(tableName, metaID, cdoid, newVersion, index); - doInsertReference(tableName, metaID, cdoid, newVersion, index, target); - } - - @Override - protected void doMoveReferenceRow(String tableName, long metaID, long cdoid, int newVersion, int oldPosition, - int newPosition) - { - if (oldPosition == newPosition) - { - return; - } - - // move element away temporarily - updateOneIndex(tableName, metaID, cdoid, newVersion, oldPosition, -1); - - // move elements in between - if (oldPosition < newPosition) - { - move1down(tableName, metaID, cdoid, newVersion, oldPosition, newPosition); - } - else - { - // oldPosition > newPosition -- equal case is handled above - move1up(tableName, metaID, cdoid, newVersion, newPosition, oldPosition); - } - - // move temporary element to new position - updateOneIndex(tableName, metaID, cdoid, newVersion, -1, newPosition); - - } - - @Override - protected void doRemoveReferenceRow(String tableName, long metaID, long cdoid, int index, int newVersion) - { - deleteReferenceRow(tableName, metaID, cdoid, index); - move1down(tableName, metaID, cdoid, newVersion, index); - } - - @Override - protected void doUpdateReference(String tableName, long metaID, long sourceId, int newVersion, int index, - long targetId) - { - PreparedStatement stmt = null; - if (cacheStatements) - { - stmt = getCachedStatement(StmtType.UPDATE_REFERENCE, tableName); - } - - try - { - if (stmt == null) - { - StringBuilder builder = new StringBuilder("UPDATE "); - builder.append(tableName); - builder.append(" SET "); - builder.append(CDODBSchema.REFERENCES_TARGET); - builder.append(" = ?, "); - builder.append(CDODBSchema.REFERENCES_VERSION); - builder.append(" = ? WHERE "); - if (metaID != 0) - { - builder.append(CDODBSchema.REFERENCES_FEATURE); - builder.append("= ? AND "); - } - - builder.append(CDODBSchema.REFERENCES_SOURCE); - builder.append("= ? AND "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" = ?"); - - stmt = getConnection().prepareStatement(builder.toString()); - if (cacheStatements) - { - cacheStatement(StmtType.UPDATE_REFERENCE, tableName, stmt); - } - } - - int idx = 1; - stmt.setLong(idx++, targetId); - stmt.setInt(idx++, newVersion); - - if (metaID != 0) - { - stmt.setLong(idx++, metaID); - } - - stmt.setLong(idx++, sourceId); - stmt.setLong(idx++, index); - - if (TRACER.isEnabled()) - { - TRACER.trace(stmt.toString()); - } - - stmt.execute(); - } - catch (SQLException e) - { - throw new DBException(e); - } - finally - { - if (!cacheStatements) - { - DBUtil.close(stmt); - } - } - } - - @Override - protected void doUpdateReferenceVersion(String tableName, long cdoid, int newVersion) - { - boolean firstBatch = false; - - PreparedStatement stmt = getDirtyStatement(StmtType.UPDATE_REFERENCE_VERSION, tableName); - if (stmt == null && cacheStatements) - { - firstBatch = true; - stmt = getAndRemoveCachedStatement(StmtType.UPDATE_REFERENCE_VERSION, tableName); - } - - try - { - if (stmt == null) - { - firstBatch = true; - - StringBuilder sql = new StringBuilder(); - sql.append("UPDATE "); - sql.append(tableName); - sql.append(" SET "); - sql.append(CDODBSchema.REFERENCES_VERSION); - sql.append(" = ? "); - sql.append(" WHERE "); - sql.append(CDODBSchema.REFERENCES_SOURCE); - sql.append(" = ?"); - - stmt = getConnection().prepareStatement(sql.toString()); - } - - stmt.setInt(1, newVersion); - stmt.setLong(2, cdoid); - - if (TRACER.isEnabled()) - { - TRACER.trace(stmt.toString()); - } - - if (firstBatch) - { - addDirtyStatement(StmtType.UPDATE_REFERENCE_VERSION, tableName, stmt); - } - - stmt.addBatch(); - } - catch (SQLException e) - { - throw new DBException(e); - } - } - - @Override - protected void doDeleteReferences(String tableName, long metaID, long cdoid) - { - PreparedStatement stmt = null; - if (cacheStatements) - { - stmt = getCachedStatement(StmtType.DELETE_REFERENCES, tableName); - } - - try - { - if (stmt == null) - { - StringBuilder sql = new StringBuilder("DELETE FROM "); - sql.append(tableName); - sql.append(" WHERE "); - sql.append(CDODBSchema.REFERENCES_SOURCE); - sql.append(" = ? "); - - if (metaID != 0) - { - sql.append("AND"); - sql.append(CDODBSchema.REFERENCES_FEATURE); - sql.append(" = ? "); - } - - stmt = getConnection().prepareStatement(sql.toString()); - if (cacheStatements) - { - cacheStatement(StmtType.DELETE_REFERENCES, tableName, stmt); - } - } - - stmt.setLong(1, cdoid); - if (metaID != 0) - { - stmt.setLong(2, metaID); - } - - if (TRACER.isEnabled()) - { - TRACER.trace(stmt.toString()); - } - - stmt.execute(); - } - catch (SQLException e) - { - throw new DBException(e); - } - finally - { - if (!cacheStatements) - { - DBUtil.close(stmt); - } - } - } - - @Override - protected ResultSet doSelectRevisionAttributes(String tableName, long revisionId, - List<IAttributeMapping> attributeMappings, boolean hasFullRevisionInfo, String where) throws SQLException - { - // Because of the variable where clause, statement caching can not be - // based on table names. Instead, we build the sql in any case and - // use this as key (similar to what JDBC3 does ...). - - StringBuilder builder = new StringBuilder(); - builder.append("SELECT "); - builder.append(CDODBSchema.ATTRIBUTES_VERSION); - builder.append(", "); - builder.append(CDODBSchema.ATTRIBUTES_CREATED); - - if (hasFullRevisionInfo) - { - builder.append(", "); - builder.append(CDODBSchema.ATTRIBUTES_REVISED); - builder.append(", "); - builder.append(CDODBSchema.ATTRIBUTES_RESOURCE); - builder.append(", "); - builder.append(CDODBSchema.ATTRIBUTES_CONTAINER); - builder.append(", "); - builder.append(CDODBSchema.ATTRIBUTES_FEATURE); - } - - for (IAttributeMapping attributeMapping : attributeMappings) - { - builder.append(", "); - builder.append(attributeMapping.getField()); - } - - builder.append(" FROM "); - builder.append(tableName); - builder.append(" WHERE "); - builder.append(CDODBSchema.ATTRIBUTES_ID); - builder.append("= ? AND ("); - builder.append(where); - builder.append(")"); - String sql = builder.toString(); - if (TRACER.isEnabled()) - { - TRACER.format("{0} ({1})", sql, revisionId); - } - - PreparedStatement pstmt = null; - if (cacheStatements) - { - pstmt = getCachedStatement(StmtType.GENERAL, sql); - if (pstmt == null) - { - pstmt = getConnection().prepareStatement(sql); - cacheStatement(StmtType.GENERAL, sql, pstmt); - } - } - else - { - /* no caching */ - pstmt = getConnection().prepareStatement(sql); - } - - pstmt.setLong(1, revisionId); - return pstmt.executeQuery(); - } - - @Override - protected ResultSet doSelectRevisionReferences(String tableName, long sourceId, int version, long metaID, String where) - throws SQLException - { - StringBuilder builder = new StringBuilder(); - builder.append("SELECT "); - builder.append(CDODBSchema.REFERENCES_TARGET); - builder.append(" FROM "); - builder.append(tableName); - builder.append(" WHERE "); - if (metaID != 0) - { - builder.append(CDODBSchema.REFERENCES_FEATURE); - builder.append("= ? AND "); - } - - builder.append(CDODBSchema.REFERENCES_SOURCE); - builder.append("= ? AND "); - builder.append(CDODBSchema.REFERENCES_VERSION); - builder.append("= ? "); - if (where != null) - { - builder.append(where); - } - - builder.append(" ORDER BY "); - builder.append(CDODBSchema.REFERENCES_IDX); - - String sql = builder.toString(); - if (TRACER.isEnabled()) - { - TRACER.trace(sql); - } - - PreparedStatement pstmt = null; - if (cacheStatements) - { - pstmt = getCachedStatement(StmtType.GENERAL, sql); - if (pstmt == null) - { - pstmt = getConnection().prepareStatement(sql); - cacheStatement(StmtType.GENERAL, sql, pstmt); - } - } - else - { - /* no caching */ - pstmt = getConnection().prepareStatement(sql); - } - - int idx = 1; - if (metaID != 0) - { - pstmt.setLong(idx++, metaID); - } - - pstmt.setLong(idx++, sourceId); - pstmt.setInt(idx++, version); - return pstmt.executeQuery(); - } - - /** - * Implementation of the hook which is called after selects. - */ - @Override - protected void releaseStatement(Statement stmt) - { - // leave open cached statements - if (!cacheStatements || !(stmt instanceof PreparedStatement)) - { - super.releaseStatement(stmt); - } - - // /* This code would guarantee that releaseStatement is only called - // for cached statements. However this looks through the whole hashmap - // and is thus too expensive to do in non-debugging mode. */ - // - // else { - // if(!selectStatementsCache.containsValue(stmt)) { - // super.releaseStatement(stmt); - // } - // } - } - - // ---------------------------------------------------------- - // List management helpers - // ---------------------------------------------------------- - - private void updateOneIndex(String tableName, long metaID, long cdoid, int newVersion, int oldIndex, int newIndex) - { - if (TRACER.isEnabled()) - { - TRACER.format("updateOneIndex ({0},{1},{2},{3},{4})", tableName, cdoid, newVersion, oldIndex, newIndex); - } - - PreparedStatement stmt = null; - if (cacheStatements) - { - stmt = getCachedStatement(StmtType.MOVE_ONE_INDEX, tableName); - } - - try - { - if (stmt == null) - { - StringBuilder builder = new StringBuilder("UPDATE "); - builder.append(tableName); - builder.append(" SET "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" = ?, "); - builder.append(CDODBSchema.REFERENCES_VERSION); - builder.append(" = ? WHERE "); - if (metaID != 0) - { - builder.append(CDODBSchema.REFERENCES_FEATURE); - builder.append("= ? AND "); - } - - builder.append(CDODBSchema.REFERENCES_SOURCE); - builder.append("= ? AND "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" = ?"); - - stmt = getConnection().prepareStatement(builder.toString()); - if (cacheStatements) - { - cacheStatement(StmtType.MOVE_ONE_INDEX, tableName, stmt); - } - } - - int idx = 1; - stmt.setInt(idx++, newIndex); - stmt.setInt(idx++, newVersion); - - if (metaID != 0) - { - stmt.setLong(idx++, metaID); - } - - stmt.setLong(idx++, cdoid); - stmt.setLong(idx++, oldIndex); - - if (TRACER.isEnabled()) - { - TRACER.trace(stmt.toString()); - } - - stmt.execute(); - } - catch (SQLException e) - { - throw new DBException(e); - } - finally - { - if (!cacheStatements) - { - DBUtil.close(stmt); - } - } - } - - /** - * Move references downwards to close a gap at position <code>index</code>. Only indexes starting with - * <code>index + 1</code> and ending with <code>upperIndex</code> are moved down. - */ - private void move1down(String tableName, long metaID, long cdoid, int newVersion, int index, int upperIndex) - { - if (TRACER.isEnabled()) - { - TRACER.format("move1down({0},{1},{2},{3},{4})", tableName, cdoid, newVersion, index, upperIndex); - } - - PreparedStatement stmt = null; - if (cacheStatements) - { - stmt = getCachedStatement(StmtType.MOVE_RANGE_1_DOWN, tableName); - } - - try - { - if (stmt == null) - { - StringBuilder builder = new StringBuilder(); - builder.append("UPDATE "); - builder.append(tableName); - builder.append(" SET "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" = "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append("-1 ,"); - builder.append(CDODBSchema.REFERENCES_VERSION); - builder.append(" = ? WHERE "); - if (metaID != 0) - { - builder.append(CDODBSchema.REFERENCES_FEATURE); - builder.append("= ? AND "); - } - - builder.append(CDODBSchema.REFERENCES_SOURCE); - builder.append("= ? AND "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" > ? AND "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" <= ?"); - - stmt = getConnection().prepareStatement(builder.toString()); - if (cacheStatements) - { - cacheStatement(StmtType.MOVE_RANGE_1_DOWN, tableName, stmt); - } - } - - int idx = 1; - stmt.setInt(idx++, newVersion); - - if (metaID != 0) - { - stmt.setLong(idx++, metaID); - } - - stmt.setLong(idx++, cdoid); - stmt.setInt(idx++, index); - stmt.setInt(idx++, upperIndex); - - stmt.execute(); - } - catch (SQLException e) - { - throw new DBException(e); - } - finally - { - if (!cacheStatements) - { - DBUtil.close(stmt); - } - } - } - - /** - * Move references downwards to close a gap at position <code>index</code>. All indexes starting with - * <code>index + 1</code> are moved down. - */ - private void move1down(String tableName, long metaID, long cdoid, int newVersion, int index) - { - if (TRACER.isEnabled()) - { - TRACER.format("move1down({0},{1},{2},{3})", tableName, cdoid, newVersion, index); - } - - PreparedStatement stmt = null; - if (cacheStatements) - { - stmt = getCachedStatement(StmtType.MOVE_1_DOWN, tableName); - } - - try - { - if (stmt == null) - { - StringBuilder builder = new StringBuilder(); - builder.append("UPDATE "); - builder.append(tableName); - builder.append(" SET "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" = "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append("-1 ,"); - builder.append(CDODBSchema.REFERENCES_VERSION); - builder.append(" = ? WHERE "); - if (metaID != 0) - { - builder.append(CDODBSchema.REFERENCES_FEATURE); - builder.append("= ? AND "); - } - - builder.append(CDODBSchema.REFERENCES_SOURCE); - builder.append("= ? AND "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" > ?"); - - stmt = getConnection().prepareStatement(builder.toString()); - if (cacheStatements) - { - cacheStatement(StmtType.MOVE_1_DOWN, tableName, stmt); - } - } - - int idx = 1; - stmt.setInt(idx++, newVersion); - - if (metaID != 0) - { - stmt.setLong(idx++, metaID); - } - - stmt.setLong(idx++, cdoid); - stmt.setInt(idx++, index); - - stmt.execute(); - } - catch (SQLException e) - { - throw new DBException(e); - } - finally - { - if (!cacheStatements) - { - DBUtil.close(stmt); - } - - } - } - - /** - * Move references upwards to make room at position <code>index</code>. Only indexes starting with <code>index</code> - * and ending with <code>upperIndex - 1</code> are moved up. - */ - private void move1up(String tableName, long metaID, long cdoid, int newVersion, int index, int upperIndex) - { - if (TRACER.isEnabled()) - { - TRACER.format("move1up({0},{1},{2},{3},{4})", tableName, cdoid, newVersion, index, upperIndex); - } - - PreparedStatement stmt = null; - if (cacheStatements) - { - stmt = getCachedStatement(StmtType.MOVE_RANGE_1_UP, tableName); - } - - try - { - if (stmt == null) - { - StringBuilder builder = new StringBuilder(); - builder.append("UPDATE "); - builder.append(tableName); - builder.append(" SET "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" = "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append("+1 ,"); - builder.append(CDODBSchema.REFERENCES_VERSION); - builder.append(" = ? WHERE "); - if (metaID != 0) - { - builder.append(CDODBSchema.REFERENCES_FEATURE); - builder.append("= ? AND "); - } - - builder.append(CDODBSchema.REFERENCES_SOURCE); - builder.append("= ? AND "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" => ? AND "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" < ?"); - - stmt = getConnection().prepareStatement(builder.toString()); - if (cacheStatements) - { - cacheStatement(StmtType.MOVE_RANGE_1_UP, tableName, stmt); - } - } - - int idx = 1; - stmt.setInt(idx++, newVersion); - - if (metaID != 0) - { - stmt.setLong(idx++, metaID); - } - - stmt.setLong(idx++, cdoid); - stmt.setInt(idx++, index); - stmt.setInt(idx++, upperIndex); - - stmt.execute(); - } - catch (SQLException e) - { - throw new DBException(e); - } - finally - { - if (!cacheStatements) - { - DBUtil.close(stmt); - } - - } - } - - /** - * Move references upwards to make room at position <code>index</code>. Only indexes starting with <code>index</code>. - */ - private void move1up(String tableName, long metaID, long cdoid, int newVersion, int index) - { - if (TRACER.isEnabled()) - { - TRACER.format("move1up({0},{1},{2},{3})", tableName, cdoid, newVersion, index); - } - - PreparedStatement stmt = null; - if (cacheStatements) - { - stmt = getCachedStatement(StmtType.MOVE_1_UP, tableName); - } - - try - { - if (stmt == null) - { - StringBuilder builder = new StringBuilder(); - builder.append("UPDATE "); - builder.append(tableName); - builder.append(" SET "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" = "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append("+1 ,"); - builder.append(CDODBSchema.REFERENCES_VERSION); - builder.append(" = ? WHERE "); - if (metaID != 0) - { - builder.append(CDODBSchema.REFERENCES_FEATURE); - builder.append("= ? AND "); - } - - builder.append(CDODBSchema.REFERENCES_SOURCE); - builder.append("= ? AND "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" >= ?"); - - stmt = getConnection().prepareStatement(builder.toString()); - if (cacheStatements) - { - cacheStatement(StmtType.MOVE_1_UP, tableName, stmt); - } - } - - int idx = 1; - stmt.setInt(idx++, newVersion); - - if (metaID != 0) - { - stmt.setLong(idx++, metaID); - } - - stmt.setLong(idx++, cdoid); - stmt.setInt(idx++, index); - - stmt.execute(); - } - catch (SQLException e) - { - throw new DBException(e); - } - finally - { - if (!cacheStatements) - { - DBUtil.close(stmt); - } - - } - } - - private void deleteReferenceRow(String tableName, long metaID, long cdoid, int index) - { - PreparedStatement stmt = null; - if (cacheStatements) - { - stmt = getCachedStatement(StmtType.DELETE_ONE_REFERENCE, tableName); - } - - try - { - if (stmt == null) - { - StringBuilder sql = new StringBuilder("DELETE FROM "); - sql.append(tableName); - sql.append(" WHERE "); - sql.append(CDODBSchema.REFERENCES_SOURCE); - sql.append(" = ? AND "); - sql.append(CDODBSchema.REFERENCES_IDX); - sql.append(" = ? "); - - if (metaID != 0) - { - sql.append("AND"); - sql.append(CDODBSchema.REFERENCES_FEATURE); - sql.append(" = ? "); - } - - stmt = getConnection().prepareStatement(sql.toString()); - if (cacheStatements) - { - cacheStatement(StmtType.DELETE_ONE_REFERENCE, tableName, stmt); - } - } - - stmt.setLong(1, cdoid); - stmt.setInt(2, index); - if (metaID != 0) - { - stmt.setLong(3, metaID); - } - - if (TRACER.isEnabled()) - { - TRACER.trace(stmt.toString()); - } - - stmt.execute(); - } - catch (SQLException e) - { - throw new DBException(e); - } - finally - { - if (!cacheStatements) - { - DBUtil.close(stmt); - } - } - } - - // ---------------------------------------------------------- - // Statement caching - // ---------------------------------------------------------- - - /** - * Add a dirty statement to the dirty statements container. - */ - private void addDirtyStatement(StmtType type, String subKey, PreparedStatement stmt) - { - if (TRACER.isEnabled()) - { - TRACER.format("Adding dirty statement: ({0},{1}) -> {2}", type, subKey, stmt); - } - - dirtyStatements.put(new CacheKey(type, subKey), stmt); - } - - /** - * Query the dirty statements container. - * - * @return - */ - private PreparedStatement getDirtyStatement(StmtType type, String subKey) - { - return dirtyStatements.get(CacheKey.useOnce(type, subKey)); - } - - /** - * Cache a prepared statement. - */ - private void cacheStatement(StmtType type, String subKey, PreparedStatement stmt) - { - cacheStatement(new CacheKey(type, subKey), stmt); - } - - /** - * Cache a prepared statement with given key. - */ - private void cacheStatement(CacheKey key, PreparedStatement stmt) - { - if (TRACER.isEnabled()) - { - TRACER.format("Adding cached statement: {0} -> {1}", key, stmt); - } - - statementCache.put(key, new WrappedPreparedStatement(stmt)); - } - - /** - * Query the cache of prepared statements. - */ - private PreparedStatement getCachedStatement(StmtType type, String subKey) - { - WrappedPreparedStatement wrapped = statementCache.get(CacheKey.useOnce(type, subKey)); - if (wrapped == null) - { - return null; - } - - PreparedStatement stmt = wrapped.getWrappedStatement(); - if (TRACER.isEnabled()) - { - TRACER.format("Using cached statement: ({0},{1}) -> {2}", type, subKey, stmt); - } - - return stmt; - } - - private PreparedStatement getAndRemoveCachedStatement(StmtType type, String subKey) - { - WrappedPreparedStatement wrapped = statementCache.remove(CacheKey.useOnce(type, subKey)); - if (wrapped == null) - { - return null; - } - - PreparedStatement stmt = wrapped.unwrapStatement(); - if (TRACER.isEnabled()) - { - TRACER.format("Removing cached statement: ({0},{1}) -> {2}", type, subKey, stmt); - } - - return stmt; - } - - /** - * @author Stefan Winkler - */ - public static enum CachingEnablement - { - ENABLED, DISABLED, GUESS - } - - /** - * Statement type as first part of the statement cache key. - * - * @author Stefan Winkler - */ - private static enum StmtType - { - INSERT_ATTRIBUTES, DELETE_ATTRIBUTES, INSERT_REFERENCES, DELETE_REFERENCES, DELETE_ONE_REFERENCE, REVISE_VERSION, REVISE_UNREVISED, GENERAL, UPDATE_REFERENCE_VERSION, MOVE_1_UP, MOVE_RANGE_1_UP, MOVE_1_DOWN, MOVE_RANGE_1_DOWN, MOVE_ONE_INDEX, UPDATE_REFERENCE - } - - /** - * Convenience definition for Pair<StmtType, String> - * - * @author Stefan Winkler - */ - private static class CacheKey extends Pair<StmtType, String> - { - public CacheKey(StmtType type, String subKey) - { - super(type, subKey); - } - - private static CacheKey useOnceKey = new CacheKey(StmtType.GENERAL, ""); - - /** - * Memory-resource-friendly method which uses a single static field, modifies it and returns it to be used at once, - * e.g., to use it in a cache lookup. Do not store a reference to the result!!! - */ - public static CacheKey useOnce(StmtType type, String subKey) - { - useOnceKey.setElement1(type); - useOnceKey.setElement2(subKey); - return useOnceKey; - } - } -} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/PreparedStatementJDBCDelegateProvider.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/PreparedStatementJDBCDelegateProvider.java deleted file mode 100644 index 08b13d3cc8..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/PreparedStatementJDBCDelegateProvider.java +++ /dev/null @@ -1,49 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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.jdbc; - -import org.eclipse.emf.cdo.server.db.IJDBCDelegate; -import org.eclipse.emf.cdo.server.db.IJDBCDelegateProvider; -import org.eclipse.emf.cdo.server.internal.db.jdbc.PreparedStatementJDBCDelegate.CachingEnablement; - -import java.util.Map; - -/** - * @author Eike Stepper - */ -public class PreparedStatementJDBCDelegateProvider implements IJDBCDelegateProvider -{ - public static final String CACHE_STATEMENT_PROPERTY_KEY = "cacheStatements"; - - private CachingEnablement cachingEnablement = CachingEnablement.GUESS; - - public PreparedStatementJDBCDelegateProvider() - { - } - - public IJDBCDelegate getJDBCDelegate() - { - PreparedStatementJDBCDelegate delegate = new PreparedStatementJDBCDelegate(); - delegate.setCachingEnablement(cachingEnablement); - return delegate; - } - - public void setProperties(Map<String, String> properties) - { - String value = properties.get(CACHE_STATEMENT_PROPERTY_KEY); - if (value == null) - { - value = "GUESS"; - } - - cachingEnablement = CachingEnablement.valueOf(value.toUpperCase()); - } -} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/StatementJDBCDelegate.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/StatementJDBCDelegate.java deleted file mode 100644 index 11d0e0b844..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/StatementJDBCDelegate.java +++ /dev/null @@ -1,648 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 - * Stefan Winkler - https://bugs.eclipse.org/bugs/show_bug.cgi?id=259402 - */ -package org.eclipse.emf.cdo.server.internal.db.jdbc; - -import org.eclipse.emf.cdo.common.id.CDOID; -import org.eclipse.emf.cdo.common.id.CDOIDUtil; -import org.eclipse.emf.cdo.common.revision.CDORevision; -import org.eclipse.emf.cdo.common.revision.CDORevisionData; -import org.eclipse.emf.cdo.server.db.CDODBUtil; -import org.eclipse.emf.cdo.server.db.mapping.IAttributeMapping; -import org.eclipse.emf.cdo.server.internal.db.CDODBSchema; -import org.eclipse.emf.cdo.server.internal.db.bundle.OM; -import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; - -import org.eclipse.net4j.db.DBException; -import org.eclipse.net4j.util.collection.Pair; -import org.eclipse.net4j.util.om.monitor.OMMonitor; -import org.eclipse.net4j.util.om.trace.ContextTracer; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.List; - -/** - * @author Stefan Winkler - * @since 2.0 - */ -public class StatementJDBCDelegate extends AbstractJDBCDelegate -{ - private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, StatementJDBCDelegate.class); - - public StatementJDBCDelegate() - { - } - - public void flush(OMMonitor monitor) - { - // Do nothing - } - - @Override - protected void doInsertAttributes(String table, CDORevision revision, List<IAttributeMapping> attributeMappings, - boolean withFullRevisionInfo) - { - StringBuilder builder = new StringBuilder(); - builder.append("INSERT INTO "); - builder.append(table); - builder.append(" VALUES ("); - - builder.append(CDOIDUtil.getLong(revision.getID())); - builder.append(", "); - builder.append(revision.getVersion()); - - if (withFullRevisionInfo) - { - CDORevisionData data = revision.data(); - builder.append(", "); - builder.append(getStoreAccessor().getStore().getMetaID(revision.getEClass())); - builder.append(", "); - builder.append(revision.getCreated()); - builder.append(", "); - builder.append(revision.getRevised()); - builder.append(", "); - builder.append(CDOIDUtil.getLong(data.getResourceID())); - builder.append(", "); - builder.append(CDODBUtil.getLong((CDOID)data.getContainerID())); - builder.append(", "); - builder.append(data.getContainingFeatureID()); - } - - if (attributeMappings != null) - { - for (IAttributeMapping attributeMapping : attributeMappings) - { - builder.append(", "); - attributeMapping.appendValue(builder, (InternalCDORevision)revision); - } - } - - builder.append(")"); - sqlUpdate(builder.toString()); - } - - @Override - protected void doUpdateAttributes(String tableName, long cdoid, int newVersion, long created, - List<Pair<IAttributeMapping, Object>> attributeChanges, boolean hasFullRevisionInfo) - { - StringBuilder builder = new StringBuilder(); - builder.append("UPDATE "); - builder.append(tableName); - builder.append(" SET "); - builder.append(CDODBSchema.ATTRIBUTES_VERSION); - builder.append(" = "); - builder.append(newVersion); - builder.append(", "); - builder.append(CDODBSchema.ATTRIBUTES_CREATED); - builder.append(" = "); - builder.append(created); - - for (Pair<IAttributeMapping, Object> attributeChange : attributeChanges) - { - IAttributeMapping attributeMapping = attributeChange.getElement1(); - builder.append(", "); - builder.append(attributeMapping.getField()); - builder.append(" = "); - attributeMapping.appendValue(builder, attributeChange.getElement2()); - } - - builder.append(" WHERE "); - builder.append(CDODBSchema.ATTRIBUTES_ID); - builder.append(" = "); - builder.append(cdoid); - - sqlUpdate(builder.toString()); - } - - @Override - protected void doUpdateAttributes(String tableName, long cdoid, int newVersion, long created, long newContainerId, - int newContainingFeatureId, long newResourceId, List<Pair<IAttributeMapping, Object>> attributeChanges, - boolean hasFullRevisionInfo) - { - StringBuilder builder = new StringBuilder(); - builder.append("UPDATE "); - builder.append(tableName); - builder.append(" SET "); - builder.append(CDODBSchema.ATTRIBUTES_VERSION); - builder.append(" = "); - builder.append(newVersion); - builder.append(", "); - builder.append(CDODBSchema.ATTRIBUTES_CREATED); - builder.append(" = "); - builder.append(created); - - builder.append(", "); - builder.append(CDODBSchema.ATTRIBUTES_CONTAINER); - builder.append(" = "); - builder.append(newContainerId); - - builder.append(", "); - builder.append(CDODBSchema.ATTRIBUTES_FEATURE); - builder.append(" = "); - builder.append(newContainingFeatureId); - - builder.append(", "); - builder.append(CDODBSchema.ATTRIBUTES_RESOURCE); - builder.append(" = "); - builder.append(newResourceId); - - for (Pair<IAttributeMapping, Object> attributeChange : attributeChanges) - { - IAttributeMapping attributeMapping = attributeChange.getElement1(); - builder.append(", "); - builder.append(attributeMapping.getField()); - builder.append(" = "); - attributeMapping.appendValue(builder, attributeChange.getElement2()); - } - - builder.append(" WHERE "); - builder.append(CDODBSchema.ATTRIBUTES_ID); - builder.append(" = "); - builder.append(cdoid); - - sqlUpdate(builder.toString()); - } - - @Override - protected void doDeleteAttributes(String name, long cdoid) - { - StringBuilder builder = new StringBuilder(); - builder.append("DELETE FROM "); - builder.append(name); - builder.append(" WHERE "); - builder.append(CDODBSchema.ATTRIBUTES_ID); - builder.append(" = "); - builder.append(cdoid); - sqlUpdate(builder.toString()); - } - - @Override - protected void doUpdateRevisedForReplace(String table, long revisedStamp, long cdoid, int version) - { - StringBuilder builder = new StringBuilder(); - builder.append("UPDATE "); - builder.append(table); - builder.append(" SET "); - builder.append(CDODBSchema.ATTRIBUTES_REVISED); - builder.append("="); - builder.append(revisedStamp); - builder.append(" WHERE "); - builder.append(CDODBSchema.ATTRIBUTES_ID); - builder.append("="); - builder.append(cdoid); - builder.append(" AND "); - builder.append(CDODBSchema.ATTRIBUTES_VERSION); - builder.append("="); - builder.append(version); - sqlUpdate(builder.toString()); - } - - @Override - protected void doUpdateRevisedForDetach(String table, long revisedStamp, long cdoid) - { - StringBuilder builder = new StringBuilder(); - builder.append("UPDATE "); - builder.append(table); - builder.append(" SET "); - builder.append(CDODBSchema.ATTRIBUTES_REVISED); - builder.append("="); - builder.append(revisedStamp); - builder.append(" WHERE "); - builder.append(CDODBSchema.ATTRIBUTES_ID); - builder.append("="); - builder.append(cdoid); - builder.append(" AND "); - builder.append(CDODBSchema.ATTRIBUTES_REVISED); - builder.append("=0"); - sqlUpdate(builder.toString()); - } - - @Override - protected void doInsertReferenceRow(String tableName, long metaID, long cdoid, int newVersion, long target, int index) - { - move1up(tableName, metaID, cdoid, newVersion, index, -1); - doInsertReference(tableName, metaID, cdoid, newVersion, index, target); - } - - @Override - protected void doInsertReference(String table, long metaID, long source, int version, int i, long target) - { - StringBuilder builder = new StringBuilder(); - builder.append("INSERT INTO "); - builder.append(table); - builder.append(" VALUES ("); - if (metaID != 0) - { - builder.append(metaID); - builder.append(", "); - } - builder.append(source); - builder.append(", "); - builder.append(version); - builder.append(", "); - builder.append(i); - builder.append(", "); - builder.append(target); - builder.append(")"); - sqlUpdate(builder.toString()); - } - - @Override - protected void doMoveReferenceRow(String tableName, long metaID, long cdoid, int newVersion, int oldPosition, - int newPosition) - { - if (oldPosition == newPosition) - { - return; - } - - // move element away temporarily - updateOneIndex(tableName, metaID, cdoid, newVersion, oldPosition, -1); - - // move elements in between - if (oldPosition < newPosition) - { - move1down(tableName, metaID, cdoid, newVersion, oldPosition, newPosition); - } - else - { - // oldPosition > newPosition -- equal case is handled above - move1up(tableName, metaID, cdoid, newVersion, newPosition, oldPosition); - } - - // move temporary element to new position - updateOneIndex(tableName, metaID, cdoid, newVersion, -1, newPosition); - } - - @Override - protected void doDeleteReferences(String name, long metaID, long cdoid) - { - StringBuilder builder = new StringBuilder(); - builder.append("DELETE FROM "); - builder.append(name); - builder.append(" WHERE "); - builder.append(CDODBSchema.REFERENCES_SOURCE); - builder.append(" = "); - builder.append(cdoid); - if (metaID != 0) - { - builder.append(" AND "); - builder.append(CDODBSchema.REFERENCES_FEATURE); - builder.append(" = "); - builder.append(metaID); - } - sqlUpdate(builder.toString()); - } - - @Override - protected void doRemoveReferenceRow(String tableName, long metaID, long cdoid, int index, int newVersion) - { - deleteReferenceRow(tableName, metaID, cdoid, index); - move1down(tableName, metaID, cdoid, newVersion, index, -1); - } - - @Override - protected void doUpdateReferenceVersion(String tableName, long cdoid, int newVersion) - { - StringBuilder builder = new StringBuilder(); - builder.append("UPDATE "); - builder.append(tableName); - builder.append(" SET "); - builder.append(CDODBSchema.REFERENCES_VERSION); - builder.append(" = "); - builder.append(newVersion); - builder.append(" WHERE "); - builder.append(CDODBSchema.REFERENCES_SOURCE); - builder.append(" = "); - builder.append(cdoid); - sqlUpdate(builder.toString()); - } - - @Override - protected void doUpdateReference(String tableName, long metaID, long sourceId, int newVersion, int index, - long targetId) - { - StringBuilder builder = new StringBuilder(); - builder.append("UPDATE "); - builder.append(tableName); - builder.append(" SET "); - builder.append(CDODBSchema.REFERENCES_TARGET); - builder.append(" = "); - builder.append(targetId); - builder.append(", "); - builder.append(CDODBSchema.REFERENCES_VERSION); - builder.append(" = "); - builder.append(newVersion); - builder.append(" WHERE "); - builder.append(CDODBSchema.REFERENCES_SOURCE); - builder.append(" = "); - builder.append(sourceId); - builder.append(" AND "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" = "); - builder.append(index); - - if (metaID != 0) - { - builder.append(" AND "); - builder.append(CDODBSchema.REFERENCES_FEATURE); - builder.append(" = "); - builder.append(metaID); - } - - sqlUpdate(builder.toString()); - } - - @Override - protected ResultSet doSelectRevisionAttributes(String tableName, long revisionId, - List<IAttributeMapping> attributeMappings, boolean hasFullRevisionInfo, String where) throws SQLException - { - StringBuilder builder = new StringBuilder(); - builder.append("SELECT "); - if (hasFullRevisionInfo) - { - builder.append(CDODBSchema.ATTRIBUTES_VERSION); - builder.append(", "); - builder.append(CDODBSchema.ATTRIBUTES_CREATED); - builder.append(", "); - builder.append(CDODBSchema.ATTRIBUTES_REVISED); - builder.append(", "); - builder.append(CDODBSchema.ATTRIBUTES_RESOURCE); - builder.append(", "); - builder.append(CDODBSchema.ATTRIBUTES_CONTAINER); - builder.append(", "); - builder.append(CDODBSchema.ATTRIBUTES_FEATURE); - } - else - { - if (attributeMappings == null) - { - // Only references return - return null; - } - } - - if (attributeMappings != null) - { - for (IAttributeMapping attributeMapping : attributeMappings) - { - builder.append(", "); - builder.append(attributeMapping.getField()); - } - } - - builder.append(" FROM "); - builder.append(tableName); - builder.append(" WHERE "); - builder.append(CDODBSchema.ATTRIBUTES_ID); - builder.append("="); - builder.append(revisionId); - builder.append(" AND ("); - builder.append(where); - builder.append(")"); - String sql = builder.toString(); - if (TRACER.isEnabled()) - { - TRACER.trace(sql); - } - - return getStatement().executeQuery(sql); - } - - @Override - protected ResultSet doSelectRevisionReferences(String tableName, long sourceId, int version, long metaID, String where) - throws SQLException - { - - StringBuilder builder = new StringBuilder(); - builder.append("SELECT "); - builder.append(CDODBSchema.REFERENCES_TARGET); - builder.append(" FROM "); - builder.append(tableName); - builder.append(" WHERE "); - if (metaID != 0) - { - builder.append(CDODBSchema.REFERENCES_FEATURE); - builder.append("="); - builder.append(metaID); - builder.append(" AND "); - } - - builder.append(CDODBSchema.REFERENCES_SOURCE); - builder.append("="); - builder.append(sourceId); - builder.append(" AND "); - builder.append(CDODBSchema.REFERENCES_VERSION); - builder.append("="); - builder.append(version); - - if (where != null) - { - builder.append(where); - } - - builder.append(" ORDER BY "); - builder.append(CDODBSchema.REFERENCES_IDX); - - String sql = builder.toString(); - - if (TRACER.isEnabled()) - { - TRACER.trace(sql); - } - - return getStatement().executeQuery(sql); - } - - private int sqlUpdate(String sql) throws DBException - { - if (TRACER.isEnabled()) - { - TRACER.trace(sql); - } - - Statement statement = null; - try - { - statement = getConnection().createStatement(); - return statement.executeUpdate(sql); - } - catch (SQLException ex) - { - throw new DBException(ex); - } - finally - { - try - { - statement.close(); - } - catch (SQLException e) - { - if (TRACER.isEnabled()) - { - TRACER.trace(e); - } - } - } - } - - private void deleteReferenceRow(String name, long metaID, long cdoid, int index) - { - StringBuilder builder = new StringBuilder(); - builder.append("DELETE FROM "); - builder.append(name); - builder.append(" WHERE "); - builder.append(CDODBSchema.REFERENCES_SOURCE); - builder.append(" = "); - builder.append(cdoid); - builder.append(" AND "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" = "); - builder.append(index); - if (metaID != 0) - { - builder.append(" AND "); - builder.append(CDODBSchema.REFERENCES_FEATURE); - builder.append(" = "); - builder.append(metaID); - } - sqlUpdate(builder.toString()); - } - - /** - * Move references upwards to make room at position <code>index</code>. If <code>upperIndex</code> is <code>-1</code>, - * then all indices beginning with <code>index</code> are moved. Else, only indexes starting with <code>index</code> - * and ending with <code>upperIndex - 1</code> are moved up. - */ - private void move1up(String tableName, long metaID, long cdoid, int newVersion, int index, int upperIndex) - { - StringBuilder builder = new StringBuilder(); - builder.append("UPDATE "); - builder.append(tableName); - builder.append(" SET "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" = "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append("+1 ,"); - builder.append(CDODBSchema.REFERENCES_VERSION); - builder.append(" = "); - builder.append(newVersion); - builder.append(" WHERE "); - if (metaID != 0) - { - builder.append(CDODBSchema.REFERENCES_FEATURE); - builder.append("="); - builder.append(metaID); - builder.append(" AND "); - } - - builder.append(CDODBSchema.REFERENCES_SOURCE); - builder.append("="); - builder.append(cdoid); - builder.append(" AND "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" >= "); - builder.append(index); - - if (upperIndex != -1) - { - builder.append(" AND "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" < "); - builder.append(upperIndex); - } - - sqlUpdate(builder.toString()); - } - - /** - * Move references downwards to close a gap at position <code>index</code>. If <code>upperIndex</code> is - * <code>-1</code>, then all indices beginning with <code>index + 1</code> are moved. Else, only indexes starting with - * <code>index + 1</code> and ending with <code>upperIndex</code> are moved down. - */ - private void move1down(String tableName, long metaID, long cdoid, int newVersion, int index, int upperIndex) - { - StringBuilder builder = new StringBuilder(); - builder.append("UPDATE "); - builder.append(tableName); - builder.append(" SET "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" = "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append("-1 ,"); - builder.append(CDODBSchema.REFERENCES_VERSION); - builder.append(" = "); - builder.append(newVersion); - builder.append(" WHERE "); - if (metaID != 0) - { - builder.append(CDODBSchema.REFERENCES_FEATURE); - builder.append("="); - builder.append(metaID); - builder.append(" AND "); - } - - builder.append(CDODBSchema.REFERENCES_SOURCE); - builder.append("="); - builder.append(cdoid); - builder.append(" AND "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" > "); - builder.append(index); - - if (upperIndex != -1) - { - builder.append(" AND "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" <= "); - builder.append(upperIndex); - } - - sqlUpdate(builder.toString()); - } - - private void updateOneIndex(String tableName, long metaID, long cdoid, int newVersion, int oldIndex, int newIndex) - { - StringBuilder builder = new StringBuilder(); - - builder.append("UPDATE "); - builder.append(tableName); - builder.append(" SET "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" = "); - builder.append(newIndex); - builder.append(", "); - builder.append(CDODBSchema.REFERENCES_VERSION); - builder.append(" = "); - builder.append(newVersion); - builder.append(" WHERE "); - if (metaID != 0) - { - builder.append(CDODBSchema.REFERENCES_FEATURE); - builder.append("="); - builder.append(metaID); - builder.append(" AND "); - } - - builder.append(CDODBSchema.REFERENCES_SOURCE); - builder.append("="); - builder.append(cdoid); - builder.append(" AND "); - builder.append(CDODBSchema.REFERENCES_IDX); - builder.append(" = "); - builder.append(oldIndex); - - sqlUpdate(builder.toString()); - } -} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/StatementJDBCDelegateProvider.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/StatementJDBCDelegateProvider.java deleted file mode 100644 index ecb83538b2..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/jdbc/StatementJDBCDelegateProvider.java +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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.jdbc; - -import org.eclipse.emf.cdo.server.db.IJDBCDelegate; -import org.eclipse.emf.cdo.server.db.IJDBCDelegateProvider; - -import java.util.Map; - -/** - * @author Eike Stepper - * @since 2.0 - */ -public class StatementJDBCDelegateProvider implements IJDBCDelegateProvider -{ - public StatementJDBCDelegateProvider() - { - } - - public IJDBCDelegate getJDBCDelegate() - { - return new StatementJDBCDelegate(); - } - - public void setProperties(Map<String, String> properties) - { - // ignore -- no properties for this delegate - } -} 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 new file mode 100644 index 0000000000..12dfdd8235 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AbstractMappingStrategy.java @@ -0,0 +1,454 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 + * Stefan Winkler - major refactoring + * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 + */ +package org.eclipse.emf.cdo.server.internal.db.mapping; + +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.model.CDOClassifierRef; +import org.eclipse.emf.cdo.common.model.CDOModelUtil; +import org.eclipse.emf.cdo.common.model.CDOType; +import org.eclipse.emf.cdo.common.model.EMFUtil; +import org.eclipse.emf.cdo.server.IStoreAccessor.QueryResourcesContext; +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.ITypeMapping; +import org.eclipse.emf.cdo.server.internal.db.ObjectIDIterator; +import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageInfo; +import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit; + +import org.eclipse.net4j.db.DBException; +import org.eclipse.net4j.db.DBUtil; +import org.eclipse.net4j.db.IDBAdapter; +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.om.monitor.OMMonitor; +import org.eclipse.net4j.util.om.monitor.OMMonitor.Async; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.ENamedElement; +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.emf.ecore.EStructuralFeature; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * This abstract base class implements those methods which are most likely common to most mapping strategies. It can be + * used to derive custom mapping strategy implementation. + * + * @author Eike Stepper + * @since 2.0 + */ +public abstract class AbstractMappingStrategy extends Lifecycle implements IMappingStrategy +{ + // --------- database name generation strings -------------- + protected static final String NAME_SEPARATOR = "_"; + + protected static final String TYPE_PREFIX_FEATURE = "F"; + + protected static final String TYPE_PREFIX_CLASS = "C"; + + protected static final String TYPE_PREFIX_PACKAGE = "P"; + + protected static final String FEATEURE_TABLE_SUFFIX = "_list"; + + private IDBStore store; + + private Map<String, String> properties; + + private Map<EClass, IClassMapping> classMappings; + + public AbstractMappingStrategy() + { + classMappings = new HashMap<EClass, IClassMapping>(); + } + + // -- property related methods ----------------------------------------- + + public synchronized Map<String, String> getProperties() + { + if (properties == null) + { + properties = new HashMap<String, String>(); + } + + return properties; + } + + public synchronized void setProperties(Map<String, String> properties) + { + this.properties = properties; + } + + private int getMaxTableNameLength() + { + String value = getProperties().get(PROP_MAX_TABLE_NAME_LENGTH); + return value == null ? store.getDBAdapter().getMaxTableNameLength() : Integer.valueOf(value); + } + + private int getMaxFieldNameLength() + { + String value = getProperties().get(PROP_MAX_FIELD_NAME_LENGTH); + return value == null ? store.getDBAdapter().getMaxFieldNameLength() : Integer.valueOf(value); + } + + private boolean isQualifiedNames() + { + String value = getProperties().get(PROP_QUALIFIED_NAMES); + return value == null ? false : Boolean.valueOf(value); + } + + private boolean isForceNamesWithID() + { + String value = getProperties().get(PROP_FORCE_NAMES_WITH_ID); + return value == null ? false : Boolean.valueOf(value); + } + + private String getTableNamePrefix() + { + String value = getProperties().get(PROP_TABLE_NAME_PREFIX); + return StringUtil.safe(value); + } + + // -- getters and setters ---------------------------------------------- + + public final IDBStore getStore() + { + return store; + } + + public final void setStore(IDBStore dbStore) + { + checkInactive(); + store = dbStore; + } + + protected final IMetaDataManager getMetaDataManager() + { + return getStore().getMetaDataManager(); + } + + public abstract boolean hasAuditSupport(); + + public abstract boolean hasDeltaSupport(); + + // -- object id related methods ---------------------------------------- + + public CloseableIterator<CDOID> readObjectIDs(IDBStoreAccessor dbStoreAccessor) + { + Collection<EClass> classes = getClassesWithObjectInfo(); + final Iterator<EClass> classIt = classes.iterator(); + + return new ObjectIDIterator(this, dbStoreAccessor) + { + private PreparedStatement currentStatement = null; + + @Override + protected ResultSet getNextResultSet() + { + while (classIt.hasNext()) + { + EClass eClass = classIt.next(); + IClassMapping mapping = getClassMapping(eClass); + currentStatement = mapping.createObjectIdStatement(getAccessor()); + + ResultSet rset = null; + try + { + rset = currentStatement.executeQuery(); + return rset; + } + catch (SQLException ex) + { + DBUtil.close(rset); // only on error + getAccessor().getStatementCache().releasePreparedStatement(currentStatement); + throw new DBException(ex); + } + } + return null; + } + + @Override + protected void closeCurrentResultSet() + { + super.closeCurrentResultSet(); + getAccessor().getStatementCache().releasePreparedStatement(currentStatement); + currentStatement = null; + } + }; + }; + + public abstract CDOClassifierRef readObjectType(IDBStoreAccessor dbStoreAccessor, CDOID id); + + public abstract long repairAfterCrash(IDBAdapter dbAdapter, Connection connection); + + protected abstract Collection<EClass> getClassesWithObjectInfo(); + + // -- resource query handling ------------------------------------------ + + public abstract void queryResources(IDBStoreAccessor dbStoreAccessor, QueryResourcesContext context); + + // -- database name demangling methods --------------------------------- + + public String getTableName(ENamedElement element) + { + String name = null; + String typePrefix = null; + + if (element instanceof EClass) + { + name = isQualifiedNames() ? EMFUtil.getQualifiedName((EClass)element, NAME_SEPARATOR) : element.getName(); + typePrefix = TYPE_PREFIX_CLASS; + } + else if (element instanceof EPackage) + { + name = isQualifiedNames() ? EMFUtil.getQualifiedName((EPackage)element, NAME_SEPARATOR) : element.getName(); + typePrefix = TYPE_PREFIX_PACKAGE; + } + else + { + throw new ImplementationError("Unknown element: " + element); + } + + String prefix = getTableNamePrefix(); + if (prefix.length() != 0 && !prefix.endsWith(NAME_SEPARATOR)) + { + prefix += NAME_SEPARATOR; + } + + return getName(prefix + name, typePrefix + getMetaDataManager().getMetaID(element), getMaxTableNameLength()); + } + + public String getTableName(EClass eClass, EStructuralFeature feature) + { + String name = isQualifiedNames() ? EMFUtil.getQualifiedName(eClass, NAME_SEPARATOR) : eClass.getName(); + name += NAME_SEPARATOR; + name += feature.getName(); + name += FEATEURE_TABLE_SUFFIX; + + String prefix = getTableNamePrefix(); + if (prefix.length() != 0 && !prefix.endsWith(NAME_SEPARATOR)) + { + prefix += NAME_SEPARATOR; + } + + return getName(prefix + name, TYPE_PREFIX_FEATURE + getMetaDataManager().getMetaID(feature), + getMaxTableNameLength()); + } + + public String getFieldName(EStructuralFeature feature) + { + return getName(feature.getName(), TYPE_PREFIX_FEATURE + getMetaDataManager().getMetaID(feature), + getMaxFieldNameLength()); + } + + private String getName(String name, String suffix, int maxLength) + { + boolean forceNamesWithID = isForceNamesWithID(); + if (store.getDBAdapter().isReservedWord(name)) + { + forceNamesWithID = true; + } + + if (name.length() > maxLength || forceNamesWithID) + { + suffix = NAME_SEPARATOR + suffix.replace('-', 'S'); + int length = Math.min(name.length(), maxLength - suffix.length()); + name = name.substring(0, length) + suffix; + } + + return name; + } + + // -- factories for mapping of classes, values, lists ------------------ + + public void createMapping(Connection connection, InternalCDOPackageUnit[] packageUnits, OMMonitor monitor) + { + monitor.begin(); + Async async = monitor.forkAsync(); + + try + { + mapPackageUnits(packageUnits); + getStore().getDBAdapter().createTables(getModelTables(), connection); + } + finally + { + async.stop(); + monitor.done(); + } + } + + private void mapPackageInfos(InternalCDOPackageInfo[] packageInfos) + { + for (InternalCDOPackageInfo packageInfo : packageInfos) + { + EPackage ePackage = packageInfo.getEPackage(); + if (!CDOModelUtil.isCorePackage(ePackage)) + { + mapClasses(EMFUtil.getPersistentClasses(ePackage)); + } + } + } + + private void mapClasses(EClass... eClasses) + { + for (EClass eClass : eClasses) + { + if (!(eClass.isInterface() || eClass.isAbstract())) + { + createClassMapping(eClass); + } + } + } + + private void mapPackageUnits(InternalCDOPackageUnit[] packageUnits) + { + if (packageUnits != null && packageUnits.length != 0) + { + for (InternalCDOPackageUnit packageUnit : packageUnits) + { + mapPackageInfos(packageUnit.getPackageInfos()); + } + } + } + + private Set<IDBTable> getModelTables() + { + Set<IDBTable> tables = new HashSet<IDBTable>(); + + for (IClassMapping mapping : classMappings.values()) + { + tables.addAll(mapping.getDBTables()); + } + + return tables; + } + + private IClassMapping createClassMapping(EClass eClass) + { + IClassMapping mapping = doCreateClassMapping(eClass); + + if (mapping != null) + { + classMappings.put(eClass, mapping); + } + + return mapping; + } + + protected abstract IClassMapping doCreateClassMapping(EClass eClass); + + public final Map<EClass, IClassMapping> getClassMappings() + { + return classMappings; + } + + public final IClassMapping getClassMapping(EClass eClass) + { + IClassMapping result = classMappings.get(eClass); + if (result != null) + { + return result; + } + else + { + // create class mapping on demand ... + return createClassMapping(eClass); + } + } + + public ITypeMapping createValueMapping(EStructuralFeature feature) + { + CDOType type = CDOModelUtil.getType(feature.getEType()); + + if (type == CDOType.BOOLEAN || type == CDOType.BOOLEAN_OBJECT) + { + return new TypeMapping.TMBoolean(this, feature); + } + else if (type == CDOType.BYTE || type == CDOType.BYTE_OBJECT) + { + return new TypeMapping.TMByte(this, feature); + } + else if (type == CDOType.CHAR || type == CDOType.CHARACTER_OBJECT) + { + return new TypeMapping.TMCharacter(this, feature); + } + else if (type == CDOType.DATE) + { + return new TypeMapping.TMDate(this, feature); + } + else if (type == CDOType.DOUBLE || type == CDOType.DOUBLE_OBJECT) + { + return new TypeMapping.TMDouble(this, feature); + } + else if (type == CDOType.FLOAT || type == CDOType.FLOAT_OBJECT) + { + return new TypeMapping.TMFloat(this, feature); + } + else if (type == CDOType.INT || type == CDOType.INTEGER_OBJECT) + { + return new TypeMapping.TMInteger(this, feature); + } + else if (type == CDOType.LONG || type == CDOType.LONG_OBJECT) + { + return new TypeMapping.TMLong(this, feature); + } + else if (type == CDOType.OBJECT) + { + return new TypeMapping.TMObject(this, feature); + } + else if (type == CDOType.SHORT || type == CDOType.SHORT_OBJECT) + { + return new TypeMapping.TMShort(this, feature); + } + else if (type == CDOType.ENUM) + { + return new TypeMapping.TMEnum(this, feature); + } + else if (type == CDOType.STRING || type == CDOType.CUSTOM) + { + return new TypeMapping.TMString(this, feature); + } + else if (type == CDOType.BYTE_ARRAY) + { + return new TypeMapping.TMBytes(this, feature); + } + + throw new ImplementationError("Unrecognized CDOType: " + type); + } + + public final IListMapping createListMapping(EClass containingClass, EStructuralFeature feature) + { + checkArg(feature.isMany(), "Only many-valued features allowed."); + IListMapping mapping = doCreateListMapping(containingClass, feature); + return mapping; + } + + public abstract IListMapping doCreateListMapping(EClass containingClass, EStructuralFeature feature); + +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AttributeMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AttributeMapping.java deleted file mode 100644 index b1c1a05022..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/AttributeMapping.java +++ /dev/null @@ -1,327 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 - * Stefan Winkler - https://bugs.eclipse.org/bugs/show_bug.cgi?id=259402 - */ -package org.eclipse.emf.cdo.server.internal.db.mapping; - -import org.eclipse.emf.cdo.common.id.CDOID; -import org.eclipse.emf.cdo.common.id.CDOIDUtil; -import org.eclipse.emf.cdo.server.db.CDODBUtil; -import org.eclipse.emf.cdo.server.db.mapping.IAttributeMapping; -import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; - -import org.eclipse.net4j.db.DBException; -import org.eclipse.net4j.db.IDBAdapter; -import org.eclipse.net4j.db.ddl.IDBField; - -import org.eclipse.emf.ecore.EStructuralFeature; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.text.MessageFormat; - -/** - * @author Eike Stepper - */ -public abstract class AttributeMapping extends FeatureMapping implements IAttributeMapping -{ - private IDBField field; - - public AttributeMapping(ClassMapping classMapping, EStructuralFeature feature) - { - super(classMapping, feature); - field = classMapping.addField(feature, classMapping.getTable()); - } - - public IDBField getField() - { - return field; - } - - public void appendValue(StringBuilder builder, InternalCDORevision revision) - { - IDBAdapter dbAdapter = getDBAdapter(); - Object value = getRevisionValue(revision); - dbAdapter.appendValue(builder, field, value); - } - - public void appendValue(StringBuilder builder, Object value) - { - IDBAdapter dbAdapter = getDBAdapter(); - Object dbValue = convertToDBType(value); - dbAdapter.appendValue(builder, field, dbValue); - } - - public Object getRevisionValue(InternalCDORevision revision) - { - EStructuralFeature feature = getFeature(); - return revision.getValue(feature); - } - - public void extractValue(ResultSet resultSet, int column, InternalCDORevision revision) - { - try - { - Object value = getResultSetValue(resultSet, column); - if (resultSet.wasNull()) - { - value = null; - } - - revision.setValue(getFeature(), value); - } - catch (SQLException ex) - { - throw new DBException(ex); - } - } - - @Override - public String toString() - { - return MessageFormat.format("AttributeMapping[feature={0}, field={1}]", getFeature(), getField()); - } - - protected abstract Object getResultSetValue(ResultSet resultSet, int column) throws SQLException; - - /** - * Convert a value to a DB compatible format. Needs to be overridden by those AttributeMappings for which - * <code>value.toString()</code> is not sufficient (e.g. for CDOID). - */ - protected Object convertToDBType(Object value) - { - return value; - } - - /** - * @author Eike Stepper - */ - public static class AMEnum extends AttributeMapping - { - public AMEnum(ClassMapping classMapping, EStructuralFeature feature) - { - super(classMapping, feature); - } - - @Override - protected Object getResultSetValue(ResultSet resultSet, int column) throws SQLException - { - return resultSet.getInt(column); - // EEnum type = (EEnum)getFeature().getEType(); - // int value = resultSet.getInt(column); - // return type.getEEnumLiteral(value); - } - } - - /** - * @author Eike Stepper - */ - public static class AMString extends AttributeMapping - { - public AMString(ClassMapping classMapping, EStructuralFeature feature) - { - super(classMapping, feature); - } - - @Override - protected Object getResultSetValue(ResultSet resultSet, int column) throws SQLException - { - return resultSet.getString(column); - } - } - - /** - * @author Eike Stepper - */ - public static class AMShort extends AttributeMapping - { - public AMShort(ClassMapping classMapping, EStructuralFeature feature) - { - super(classMapping, feature); - } - - @Override - protected Object getResultSetValue(ResultSet resultSet, int column) throws SQLException - { - return resultSet.getShort(column); - } - } - - /** - * @author Eike Stepper - */ - public static class AMObject extends AttributeMapping - { - public AMObject(ClassMapping classMapping, EStructuralFeature feature) - { - super(classMapping, feature); - } - - @Override - protected Object getResultSetValue(ResultSet resultSet, int column) throws SQLException - { - long id = resultSet.getLong(column); - if (resultSet.wasNull()) - { - return null; - } - - return CDOIDUtil.createLong(id); - } - - @Override - protected Object convertToDBType(Object value) - { - return CDODBUtil.getLong((CDOID)value); - } - } - - /** - * @author Eike Stepper - */ - public static class AMLong extends AttributeMapping - { - public AMLong(ClassMapping classMapping, EStructuralFeature feature) - { - super(classMapping, feature); - } - - @Override - protected Object getResultSetValue(ResultSet resultSet, int column) throws SQLException - { - return resultSet.getLong(column); - } - } - - /** - * @author Eike Stepper - */ - public static class AMInteger extends AttributeMapping - { - public AMInteger(ClassMapping classMapping, EStructuralFeature feature) - { - super(classMapping, feature); - } - - @Override - protected Object getResultSetValue(ResultSet resultSet, int column) throws SQLException - { - return resultSet.getInt(column); - } - } - - /** - * @author Eike Stepper - */ - public static class AMFloat extends AttributeMapping - { - public AMFloat(ClassMapping classMapping, EStructuralFeature feature) - { - super(classMapping, feature); - } - - @Override - protected Object getResultSetValue(ResultSet resultSet, int column) throws SQLException - { - return resultSet.getFloat(column); - } - } - - /** - * @author Eike Stepper - */ - public static class AMDouble extends AttributeMapping - { - public AMDouble(ClassMapping classMapping, EStructuralFeature feature) - { - super(classMapping, feature); - } - - @Override - protected Object getResultSetValue(ResultSet resultSet, int column) throws SQLException - { - return resultSet.getDouble(column); - } - } - - /** - * @author Eike Stepper - */ - public static class AMDate extends AttributeMapping - { - public AMDate(ClassMapping classMapping, EStructuralFeature feature) - { - super(classMapping, feature); - } - - @Override - protected Object getResultSetValue(ResultSet resultSet, int column) throws SQLException - { - return resultSet.getTimestamp(column); - } - } - - /** - * @author Eike Stepper - */ - public static class AMCharacter extends AttributeMapping - { - public AMCharacter(ClassMapping classMapping, EStructuralFeature feature) - { - super(classMapping, feature); - } - - @Override - protected Object getResultSetValue(ResultSet resultSet, int column) throws SQLException - { - String str = resultSet.getString(column); - if (resultSet.wasNull()) - { - return null; - } - - return str.charAt(0); - } - } - - /** - * @author Eike Stepper - */ - public static class AMByte extends AttributeMapping - { - public AMByte(ClassMapping classMapping, EStructuralFeature feature) - { - super(classMapping, feature); - } - - @Override - protected Object getResultSetValue(ResultSet resultSet, int column) throws SQLException - { - return resultSet.getByte(column); - } - } - - /** - * @author Eike Stepper - */ - public static class AMBoolean extends AttributeMapping - { - public AMBoolean(ClassMapping classMapping, EStructuralFeature feature) - { - super(classMapping, feature); - } - - @Override - protected Object getResultSetValue(ResultSet resultSet, int column) throws SQLException - { - return resultSet.getBoolean(column); - } - } -} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/ClassMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/ClassMapping.java deleted file mode 100644 index 396bfe58b6..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/ClassMapping.java +++ /dev/null @@ -1,708 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 - * Stefan Winkler - https://bugs.eclipse.org/bugs/show_bug.cgi?id=259402 - */ -package org.eclipse.emf.cdo.server.internal.db.mapping; - -import org.eclipse.emf.cdo.common.id.CDOID; -import org.eclipse.emf.cdo.common.model.CDOModelUtil; -import org.eclipse.emf.cdo.common.model.CDOType; -import org.eclipse.emf.cdo.common.revision.CDORevision; -import org.eclipse.emf.cdo.common.revision.delta.CDOAddFeatureDelta; -import org.eclipse.emf.cdo.common.revision.delta.CDOClearFeatureDelta; -import org.eclipse.emf.cdo.common.revision.delta.CDOContainerFeatureDelta; -import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta; -import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDeltaVisitor; -import org.eclipse.emf.cdo.common.revision.delta.CDOListFeatureDelta; -import org.eclipse.emf.cdo.common.revision.delta.CDOMoveFeatureDelta; -import org.eclipse.emf.cdo.common.revision.delta.CDORemoveFeatureDelta; -import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta; -import org.eclipse.emf.cdo.common.revision.delta.CDOSetFeatureDelta; -import org.eclipse.emf.cdo.common.revision.delta.CDOUnsetFeatureDelta; -import org.eclipse.emf.cdo.server.IStore; -import org.eclipse.emf.cdo.server.db.IDBStore; -import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; -import org.eclipse.emf.cdo.server.db.mapping.IAttributeMapping; -import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; -import org.eclipse.emf.cdo.server.db.mapping.IFeatureMapping; -import org.eclipse.emf.cdo.server.db.mapping.IReferenceMapping; -import org.eclipse.emf.cdo.server.internal.db.CDODBSchema; -import org.eclipse.emf.cdo.server.internal.db.DBStore; -import org.eclipse.emf.cdo.server.internal.db.ToMany; -import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; -import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta; - -import org.eclipse.net4j.db.DBException; -import org.eclipse.net4j.db.DBType; -import org.eclipse.net4j.db.IDBAdapter; -import org.eclipse.net4j.db.ddl.IDBField; -import org.eclipse.net4j.db.ddl.IDBIndex; -import org.eclipse.net4j.db.ddl.IDBTable; -import org.eclipse.net4j.util.ImplementationError; -import org.eclipse.net4j.util.collection.Pair; -import org.eclipse.net4j.util.om.monitor.OMMonitor; -import org.eclipse.net4j.util.om.monitor.OMMonitor.Async; - -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.EReference; -import org.eclipse.emf.ecore.EStructuralFeature; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * @author Eike Stepper - */ -public abstract class ClassMapping implements IClassMapping -{ - private MappingStrategy mappingStrategy; - - private EClass eClass; - - private IDBTable table; - - private Set<IDBTable> affectedTables = new HashSet<IDBTable>(); - - private List<IAttributeMapping> attributeMappings; - - private List<IReferenceMapping> referenceMappings; - - private ThreadLocal<FeatureDeltaWriter> deltaWriter = new ThreadLocal<FeatureDeltaWriter>() - { - @Override - protected FeatureDeltaWriter initialValue() - { - return new FeatureDeltaWriter(); - }; - }; - - public ClassMapping(MappingStrategy mappingStrategy, EClass eClass, EStructuralFeature[] features) - { - this.mappingStrategy = mappingStrategy; - this.eClass = eClass; - - String tableName = mappingStrategy.getTableName(eClass); - table = addTable(tableName); - initTable(table, hasFullRevisionInfo()); - - if (features != null) - { - attributeMappings = createAttributeMappings(features); - referenceMappings = createReferenceMappings(features); - - // // Special handling of CDOResource table - // CDOResourceClass resourceClass = getResourceClass(); - // if (eClass == resourceClass) - // { - // // Create a unique ids to prevent duplicate resource paths - // for (IAttributeMapping attributeMapping : attributeMappings) - // { - // if (attributeMapping.getFeature() == resourceClass.getCDOPathFeature()) - // { - // IDBField versionField = table.getField(CDODBSchema.ATTRIBUTES_VERSION); - // IDBField pathField = attributeMapping.getField(); - // pathField.setPrecision(760);// MYSQL key limitation 767 - // pathField.setNotNull(true); - // - // // Example: Currently a store can not specify that it does not support non-auditing mode! - // if (false && !mappingStrategy.getStore().getRepository().isSupportingAudits()) - // { - // // Create a unique ids to prevent duplicate resource paths - // table.addIndex(IDBIndex.Type.UNIQUE, versionField, pathField); - // } - // - // break; - // } - // } - // } - } - } - - public MappingStrategy getMappingStrategy() - { - return mappingStrategy; - } - - public EClass getEClass() - { - return eClass; - } - - public IDBTable getTable() - { - return table; - } - - public Set<IDBTable> getAffectedTables() - { - return affectedTables; - } - - protected void initTable(IDBTable table, boolean full) - { - IDBField idField = table.addField(CDODBSchema.ATTRIBUTES_ID, DBType.BIGINT, true); - table.addField(CDODBSchema.ATTRIBUTES_VERSION, DBType.INTEGER, true); - if (full) - { - table.addField(CDODBSchema.ATTRIBUTES_CLASS, DBType.BIGINT, true); - table.addField(CDODBSchema.ATTRIBUTES_CREATED, DBType.BIGINT, true); - IDBField revisedField = table.addField(CDODBSchema.ATTRIBUTES_REVISED, DBType.BIGINT, true); - table.addField(CDODBSchema.ATTRIBUTES_RESOURCE, DBType.BIGINT, true); - table.addField(CDODBSchema.ATTRIBUTES_CONTAINER, DBType.BIGINT, true); - table.addField(CDODBSchema.ATTRIBUTES_FEATURE, DBType.INTEGER, true); - - table.addIndex(IDBIndex.Type.NON_UNIQUE, idField, revisedField); - } - } - - protected IDBTable addTable(String name) - { - IDBTable table = mappingStrategy.getStore().getDBSchema().addTable(name); - affectedTables.add(table); - return table; - } - - protected IDBField addField(EStructuralFeature feature, IDBTable table) throws DBException - { - String fieldName = mappingStrategy.getFieldName(feature); - DBType fieldType = getDBType(feature); - int fieldLength = getDBLength(feature); - - IDBField field = table.addField(fieldName, fieldType, fieldLength); - affectedTables.add(table); - return field; - } - - protected DBType getDBType(EStructuralFeature feature) - { - return DBStore.getDBType(feature.getEType()); - } - - protected int getDBLength(EStructuralFeature feature) - { - // Derby: The maximum length for a VARCHAR string is 32,672 characters. - CDOType type = CDOModelUtil.getType(feature.getEType()); - return type == CDOType.STRING || type == CDOType.CUSTOM ? 32672 : IDBField.DEFAULT; - } - - protected IDBAdapter getDBAdapter() - { - IDBStore store = mappingStrategy.getStore(); - return store.getDBAdapter(); - } - - public IFeatureMapping getFeatureMapping(EStructuralFeature feature) - { - if (feature instanceof EReference && mappingStrategy.getToMany() != ToMany.LIKE_ATTRIBUTES) - { - return getReferenceMapping(feature); - } - - return getAttributeMapping(feature); - } - - public List<IAttributeMapping> getAttributeMappings() - { - return attributeMappings; - } - - public List<IReferenceMapping> getReferenceMappings() - { - return referenceMappings; - } - - public IReferenceMapping getReferenceMapping(EStructuralFeature feature) - { - // TODO Optimize this? - for (IReferenceMapping referenceMapping : referenceMappings) - { - if (referenceMapping.getFeature() == feature) - { - return referenceMapping; - } - } - - return null; - } - - public IAttributeMapping getAttributeMapping(EStructuralFeature feature) - { - // TODO Optimize this? - for (IAttributeMapping attributeMapping : attributeMappings) - { - if (attributeMapping.getFeature() == feature) - { - return attributeMapping; - } - } - - return null; - } - - protected List<IAttributeMapping> createAttributeMappings(EStructuralFeature[] features) - { - List<IAttributeMapping> attributeMappings = new ArrayList<IAttributeMapping>(); - for (EStructuralFeature feature : features) - { - if (feature instanceof EReference) - { - if (!feature.isMany()) - { - attributeMappings.add(createToOneReferenceMapping(feature)); - } - } - else - { - attributeMappings.add(createAttributeMapping(feature)); - } - } - - return attributeMappings.isEmpty() ? null : attributeMappings; - } - - protected List<IReferenceMapping> createReferenceMappings(EStructuralFeature[] features) - { - List<IReferenceMapping> referenceMappings = new ArrayList<IReferenceMapping>(); - for (EStructuralFeature feature : features) - { - if (feature instanceof EReference && feature.isMany()) - { - referenceMappings.add(createReferenceMapping(feature)); - } - } - - return referenceMappings.isEmpty() ? null : referenceMappings; - } - - protected AttributeMapping createAttributeMapping(EStructuralFeature feature) - { - CDOType type = CDOModelUtil.getType(feature.getEType()); - if (type == CDOType.BOOLEAN || type == CDOType.BOOLEAN_OBJECT) - { - return new AttributeMapping.AMBoolean(this, feature); - } - else if (type == CDOType.BYTE || type == CDOType.BYTE_OBJECT) - { - return new AttributeMapping.AMByte(this, feature); - } - else if (type == CDOType.CHAR || type == CDOType.CHARACTER_OBJECT) - { - return new AttributeMapping.AMCharacter(this, feature); - } - else if (type == CDOType.DATE) - { - return new AttributeMapping.AMDate(this, feature); - } - else if (type == CDOType.DOUBLE || type == CDOType.DOUBLE_OBJECT) - { - return new AttributeMapping.AMDouble(this, feature); - } - else if (type == CDOType.FLOAT || type == CDOType.FLOAT_OBJECT) - { - return new AttributeMapping.AMFloat(this, feature); - } - else if (type == CDOType.INT || type == CDOType.INTEGER_OBJECT) - { - return new AttributeMapping.AMInteger(this, feature); - } - else if (type == CDOType.LONG || type == CDOType.LONG_OBJECT) - { - return new AttributeMapping.AMLong(this, feature); - } - else if (type == CDOType.OBJECT) - { - return new AttributeMapping.AMObject(this, feature); - } - else if (type == CDOType.SHORT || type == CDOType.SHORT_OBJECT) - { - return new AttributeMapping.AMShort(this, feature); - } - else if (type == CDOType.ENUM) - { - return new AttributeMapping.AMEnum(this, feature); - } - else if (type == CDOType.STRING || type == CDOType.CUSTOM) - { - return new AttributeMapping.AMString(this, feature); - } - - throw new ImplementationError("Unrecognized CDOType: " + type); - } - - protected ToOneReferenceMapping createToOneReferenceMapping(EStructuralFeature feature) - { - return new ToOneReferenceMapping(this, feature); - } - - protected ReferenceMapping createReferenceMapping(EStructuralFeature feature) - { - return new ReferenceMapping(this, feature, ToMany.PER_REFERENCE); - } - - public Object createReferenceMappingKey(EStructuralFeature feature) - { - return feature; - } - - public void writeRevision(IDBStoreAccessor accessor, InternalCDORevision revision, OMMonitor monitor) - { - try - { - // TODO Better monitoring - monitor.begin(10); - - if (revision.getVersion() > 1 && hasFullRevisionInfo() && isAuditing()) - { - writeRevisedRow(accessor, revision); - } - - monitor.worked(); - - if (revision.isResourceFolder() || revision.isResource()) - { - checkDuplicateResources(accessor, revision); - } - - monitor.worked(); - - // Write attribute table always (even without modeled attributes!) - writeAttributes(accessor, revision); - - monitor.worked(); - - // Write reference tables only if they exist - if (referenceMappings != null) - { - writeReferences(accessor, revision); - } - - monitor.worked(7); - } - finally - { - monitor.done(); - } - } - - private boolean isAuditing() - { - return mappingStrategy.getStore().getRevisionTemporality() == IStore.RevisionTemporality.AUDITING; - } - - protected abstract void checkDuplicateResources(IDBStoreAccessor accessor, CDORevision revision) - throws IllegalStateException; - - public void detachObject(IDBStoreAccessor accessor, CDOID id, long revised, OMMonitor monitor) - { - try - { - monitor.begin(); - if (hasFullRevisionInfo()) - { - if (isAuditing()) - { - writeRevisedRow(accessor, id, revised); - monitor.worked(1); - } - else - { - deleteRevision(accessor, id, monitor.fork(1)); - } - } - - // TODO Handle !hasFullRevisionInfo() case - } - finally - { - monitor.done(); - } - } - - protected void deleteRevision(IDBStoreAccessor accessor, CDOID id, OMMonitor monitor) - { - try - { - monitor.begin(2); - deleteAttributes(accessor, id); - monitor.worked(1); - deleteReferences(accessor, id); - monitor.worked(1); - } - finally - { - monitor.done(); - } - } - - protected final void writeRevisedRow(IDBStoreAccessor accessor, InternalCDORevision revision) - { - accessor.getJDBCDelegate().updateRevisedForReplace(revision, this); - } - - protected final void writeRevisedRow(IDBStoreAccessor accessor, CDOID id, long revised) - { - accessor.getJDBCDelegate().updateRevisedForDetach(id, revised, this); - } - - protected final void writeAttributes(IDBStoreAccessor accessor, InternalCDORevision revision) - { - if (revision.getVersion() == 1 || isAuditing()) - { - accessor.getJDBCDelegate().insertAttributes(revision, this); - } - else - { - accessor.getJDBCDelegate().updateAttributes(revision, this); - } - } - - protected final void deleteAttributes(IDBStoreAccessor accessor, CDOID id) - { - accessor.getJDBCDelegate().deleteAttributes(id, this); - } - - protected final void deleteReferences(IDBStoreAccessor accessor, CDOID id) - { - if (referenceMappings != null) - { - for (IReferenceMapping referenceMapping : referenceMappings) - { - referenceMapping.deleteReference(accessor, id); - } - } - } - - protected void writeReferences(IDBStoreAccessor accessor, InternalCDORevision revision) - { - if (mappingStrategy.getStore().getRevisionTemporality() == IStore.RevisionTemporality.NONE) - { - deleteReferences(accessor, revision.getID()); - } - - for (IReferenceMapping referenceMapping : referenceMappings) - { - referenceMapping.writeReference(accessor, revision); - } - } - - public void writeRevisionDelta(IDBStoreAccessor accessor, InternalCDORevisionDelta delta, long created, - OMMonitor monitor) - { - monitor.begin(); - Async async = monitor.forkAsync(); - - try - { - FeatureDeltaWriter writer = deltaWriter.get(); - writer.process(accessor, delta, created); - } - finally - { - async.stop(); - monitor.done(); - } - } - - public boolean readRevision(IDBStoreAccessor accessor, InternalCDORevision revision, int referenceChunk) - { - String where = mappingStrategy.createWhereClause(CDORevision.UNSPECIFIED_DATE); - return readRevision(accessor, revision, where, referenceChunk); - } - - public boolean readRevisionByTime(IDBStoreAccessor accessor, InternalCDORevision revision, long timeStamp, - int referenceChunk) - { - String where = mappingStrategy.createWhereClause(timeStamp); - return readRevision(accessor, revision, where, referenceChunk); - } - - public boolean readRevisionByVersion(IDBStoreAccessor accessor, InternalCDORevision revision, int version, - int referenceChunk) - { - String where = CDODBSchema.ATTRIBUTES_VERSION + "=" + version; - return readRevision(accessor, revision, where, referenceChunk); - } - - /** - * Read a revision. - * - * @return <code>true</code> if the revision has been read successfully.<br> - * <code>false</code> if the revision does not exist in the DB. - */ - protected boolean readRevision(IDBStoreAccessor accessor, InternalCDORevision revision, String where, - int referenceChunk) - { - // Read attribute table always (even without modeled attributes!) - boolean success = readAttributes(accessor, revision, where); - - // Read reference tables only if revision exists and if references exist - if (success && referenceMappings != null) - { - readReferences(accessor, revision, referenceChunk); - } - - return success; - } - - /** - * Read the revision's attributes from the DB. - * - * @return <code>true</code> if the revision has been read successfully.<br> - * <code>false</code> if the revision does not exist in the DB. - */ - protected final boolean readAttributes(IDBStoreAccessor accessor, InternalCDORevision revision, String where) - { - return accessor.getJDBCDelegate().selectRevisionAttributes(revision, this, where); - } - - protected void readReferences(IDBStoreAccessor accessor, InternalCDORevision revision, int referenceChunk) - { - for (IReferenceMapping referenceMapping : referenceMappings) - { - referenceMapping.readReference(accessor, revision, referenceChunk); - } - } - - private class FeatureDeltaWriter implements CDOFeatureDeltaVisitor - { - private CDOID id; - - private int newVersion; - - private long created; - - private IDBStoreAccessor accessor; - - private boolean updateContainer = false; - - private List<Pair<IAttributeMapping, Object>> attributeChanges; - - private int newContainingFeatureID; - - private CDOID newContainerID; - - private CDOID newResourceID; - - public FeatureDeltaWriter() - { - attributeChanges = new ArrayList<Pair<IAttributeMapping, Object>>(); - } - - protected void reset() - { - attributeChanges.clear(); - updateContainer = false; - } - - public void process(IDBStoreAccessor a, CDORevisionDelta d, long c) - { - // set context - - reset(); - id = d.getID(); - newVersion = d.getDirtyVersion(); - created = c; - accessor = a; - - // process revision delta tree - d.accept(this); - - // update attributes - if (updateContainer) - { - accessor.getJDBCDelegate().updateAttributes(id, newVersion, created, newContainerID, newContainingFeatureID, - newResourceID, attributeChanges, ClassMapping.this); - } - else - { - accessor.getJDBCDelegate().updateAttributes(id, newVersion, created, attributeChanges, ClassMapping.this); - } - - // update version number of all references to current version - if (referenceMappings != null) - { - for (IReferenceMapping referenceMapping : getReferenceMappings()) - { - referenceMapping.updateReferenceVersion(accessor, id, newVersion); - } - } - } - - public void visit(CDOMoveFeatureDelta delta) - { - getReferenceMapping(delta.getFeature()).moveReferenceEntry(accessor, id, newVersion, delta.getOldPosition(), - delta.getNewPosition()); - } - - public void visit(CDOSetFeatureDelta delta) - { - if (delta.getFeature().isMany()) - { - IReferenceMapping rm = getReferenceMapping(delta.getFeature()); - if (rm == null) - { - throw new IllegalArgumentException("ReferenceMapping for " + delta.getFeature() + " is null!"); - } - rm.updateReference(accessor, id, newVersion, delta.getIndex(), (CDOID)delta.getValue()); - } - else - { - IAttributeMapping am = getAttributeMapping(delta.getFeature()); - if (am == null) - { - throw new IllegalArgumentException("AttributeMapping for " + delta.getFeature() + " is null!"); - } - attributeChanges.add(new Pair<IAttributeMapping, Object>(am, delta.getValue())); - } - } - - public void visit(CDOUnsetFeatureDelta delta) - { - // TODO Correct this when DBStore implements unsettable features - // see Bugs 259868 and 263010 - IAttributeMapping am = getAttributeMapping(delta.getFeature()); - attributeChanges.add(new Pair<IAttributeMapping, Object>(am, null)); - } - - public void visit(CDOListFeatureDelta delta) - { - for (CDOFeatureDelta listChange : delta.getListChanges()) - { - listChange.accept(this); - } - } - - public void visit(CDOClearFeatureDelta delta) - { - getReferenceMapping(delta.getFeature()).deleteReference(accessor, id); - } - - public void visit(CDOAddFeatureDelta delta) - { - getReferenceMapping(delta.getFeature()).insertReferenceEntry(accessor, id, newVersion, delta.getIndex(), - (CDOID)delta.getValue()); - } - - public void visit(CDORemoveFeatureDelta delta) - { - getReferenceMapping(delta.getFeature()).removeReferenceEntry(accessor, id, delta.getIndex(), newVersion); - } - - public void visit(CDOContainerFeatureDelta delta) - { - newContainingFeatureID = delta.getContainerFeatureID(); - newContainerID = (CDOID)delta.getContainerID(); - newResourceID = delta.getResourceID(); - updateContainer = true; - } - } -} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/FeatureMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/FeatureMapping.java deleted file mode 100644 index 58bfd68d77..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/FeatureMapping.java +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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.net4j.db.IDBAdapter; - -import org.eclipse.emf.ecore.EStructuralFeature; - -/** - * @author Eike Stepper - */ -public class FeatureMapping -{ - private ClassMapping classMapping; - - private EStructuralFeature feature; - - public FeatureMapping(ClassMapping classMapping, EStructuralFeature feature) - { - this.classMapping = classMapping; - this.feature = feature; - } - - public ClassMapping getClassMapping() - { - return classMapping; - } - - public EStructuralFeature getFeature() - { - return feature; - } - - protected IDBAdapter getDBAdapter() - { - return getClassMapping().getMappingStrategy().getStore().getDBAdapter(); - } -} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/HorizontalClassMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/HorizontalClassMapping.java deleted file mode 100644 index fb92edc5f6..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/HorizontalClassMapping.java +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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.id.CDOID; -import org.eclipse.emf.cdo.common.model.CDOModelUtil; -import org.eclipse.emf.cdo.common.revision.CDORevision; -import org.eclipse.emf.cdo.eresource.EresourcePackage; -import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; -import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; - -import org.eclipse.net4j.util.collection.Pair; -import org.eclipse.net4j.util.om.monitor.OMMonitor; - -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.EStructuralFeature; - -import java.text.MessageFormat; - -/** - * @author Eike Stepper - */ -public class HorizontalClassMapping extends ClassMapping -{ - public HorizontalClassMapping(HorizontalMappingStrategy mappingStrategy, EClass eClass) - { - super(mappingStrategy, eClass, CDOModelUtil.getAllPersistentFeatures(eClass)); - } - - @Override - public HorizontalMappingStrategy getMappingStrategy() - { - return (HorizontalMappingStrategy)super.getMappingStrategy(); - } - - @Override - public void writeRevision(IDBStoreAccessor accessor, InternalCDORevision revision, OMMonitor monitor) - { - try - { - monitor.begin(5); - super.writeRevision(accessor, revision, monitor.fork(4)); - if (revision.getVersion() == 1) - { - CDOID id = revision.getID(); - EClass type = revision.getEClass(); - getMappingStrategy().getObjectTypeCache().putObjectType(accessor, id, type); - } - - // TODO Better monitoring - monitor.worked(); - } - finally - { - monitor.done(); - } - } - - @Override - protected void checkDuplicateResources(IDBStoreAccessor accessor, CDORevision revision) throws IllegalStateException - { - CDOID folderID = (CDOID)revision.data().getContainerID(); - String name = (String)revision.data().get(EresourcePackage.eINSTANCE.getCDOResourceNode_Name(), 0); - - CDOID existingID = accessor.readResourceID(folderID, name, revision.getCreated()); - if (existingID != null && !existingID.equals(revision.getID())) - { - throw new IllegalStateException("Duplicate resource or folder: " + name + " in folder " + folderID); - } - } - - @Override - public Object createReferenceMappingKey(EStructuralFeature feature) - { - return new Pair<EClass, EStructuralFeature>(getEClass(), feature); - } - - public boolean hasFullRevisionInfo() - { - return true; - } - - @Override - protected void deleteRevision(IDBStoreAccessor accessor, CDOID id, OMMonitor monitor) - { - try - { - monitor.begin(2); - super.deleteRevision(accessor, id, monitor.fork(1)); - getMappingStrategy().getObjectTypeCache().removeObjectType(accessor, id); - monitor.worked(1); - } - finally - { - monitor.done(); - } - } - - @Override - public String toString() - { - return MessageFormat.format("HorizontalClassMapping[class={0}, table={1}]", getEClass(), getTable()); - } -} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/HorizontalMappingStrategy.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/HorizontalMappingStrategy.java deleted file mode 100644 index 8b9da80ff1..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/HorizontalMappingStrategy.java +++ /dev/null @@ -1,225 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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.id.CDOID; -import org.eclipse.emf.cdo.common.id.CDOIDUtil; -import org.eclipse.emf.cdo.common.model.CDOClassifierRef; -import org.eclipse.emf.cdo.common.model.EMFUtil; -import org.eclipse.emf.cdo.eresource.EresourcePackage; -import org.eclipse.emf.cdo.server.db.IDBStore; -import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; -import org.eclipse.emf.cdo.server.db.IObjectTypeCache; -import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; -import org.eclipse.emf.cdo.server.internal.db.CDODBSchema; -import org.eclipse.emf.cdo.server.internal.db.ObjectTypeCache; -import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageRegistry; - -import org.eclipse.net4j.db.DBException; -import org.eclipse.net4j.util.lifecycle.LifecycleUtil; - -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.EPackage; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author Eike Stepper - */ -public class HorizontalMappingStrategy extends MappingStrategy -{ - private IObjectTypeCache objectTypeCache; - - public HorizontalMappingStrategy() - { - } - - public String getType() - { - return "horizontal"; - } - - public IObjectTypeCache getObjectTypeCache() - { - return objectTypeCache; - } - - public void setObjectTypeCache(IObjectTypeCache objectTypeCache) - { - this.objectTypeCache = objectTypeCache; - } - - public CDOClassifierRef readObjectType(IDBStoreAccessor accessor, CDOID id) - { - return objectTypeCache.getObjectType(accessor, id); - } - - /** - * TODO Stefan: Is this method still needed? - */ - @Deprecated - protected final CDOClassifierRef readObjectTypeFromClassesWithObjectInfo(IDBStoreAccessor accessor, CDOID id) - { - // String prefix = "SELECT DISTINCT " + CDODBSchema.ATTRIBUTES_CLASS + " FROM "; - // String suffix = " WHERE " + CDODBSchema.ATTRIBUTES_ID + "=" + id; - // for (EClass eClass : getClassesWithObjectInfo()) - // { - // IClassMapping mapping = getClassMapping(eClass); - // if (mapping != null) - // { - // IDBTable table = mapping.getTable(); - // if (table != null) - // { - // String sql = prefix + table + suffix; - // if (TRACER.isEnabled()) - // { - // TRACER.trace(sql); - // } - // - // ResultSet resultSet = null; - // - // try - // { - // resultSet = accessor.getJDBCDelegate().getStatement().executeQuery(sql); - // if (resultSet.next()) - // { - // int classID = resultSet.getInt(1); - // return getClassifierRef(accessor, classID); - // } - // } - // catch (SQLException ex) - // { - // throw new DBException(ex); - // } - // finally - // { - // DBUtil.close(resultSet); - // } - // } - // } - // } - - throw new DBException("No object with id " + id); - } - - @Override - protected IClassMapping createClassMapping(EClass eClass) - { - if (eClass.isAbstract() || eClass.isInterface()) - { - return null; - } - - return new HorizontalClassMapping(this, eClass); - } - - @Override - protected List<EClass> getClassesWithObjectInfo() - { - List<EClass> result = new ArrayList<EClass>(); - InternalCDOPackageRegistry packageRegistry = (InternalCDOPackageRegistry)getStore().getRepository() - .getPackageRegistry(); - for (EPackage ePackage : packageRegistry.getEPackages()) - { - for (EClass eClass : EMFUtil.getConcreteClasses(ePackage)) - { - // if (!CDOModelUtil.isRoot(eClass)) - { - result.add(eClass); - } - } - } - - return result; - } - - @Override - protected void doActivate() throws Exception - { - super.doActivate(); - if (objectTypeCache == null) - { - objectTypeCache = createObjectTypeCache(getStore()); - LifecycleUtil.activate(objectTypeCache); - } - } - - @Override - protected String[] getResourceQueries(CDOID folderID, String name, boolean exactMatch) - { - String[] queries = new String[2]; - - IClassMapping resourceFolderMapping = getClassMapping(EresourcePackage.eINSTANCE.getCDOResourceFolder()); - queries[0] = getResourceQuery(folderID, name, exactMatch, resourceFolderMapping); - - IClassMapping resourceMapping = getClassMapping(EresourcePackage.eINSTANCE.getCDOResource()); - queries[1] = getResourceQuery(folderID, name, exactMatch, resourceMapping); - - return queries; - } - - protected String getResourceQuery(CDOID folderID, String name, boolean exactMatch, IClassMapping classMapping) - { - StringBuilder builder = new StringBuilder(); - builder.append("SELECT "); - builder.append(CDODBSchema.ATTRIBUTES_ID); - builder.append(" FROM "); - builder.append(classMapping.getTable()); - builder.append(" WHERE "); - builder.append(CDODBSchema.ATTRIBUTES_CONTAINER); - builder.append("="); - builder.append(CDOIDUtil.getLong(folderID)); - if (exactMatch || name != null) - { - builder.append(" AND "); - builder.append(classMapping.getAttributeMapping(EresourcePackage.eINSTANCE.getCDOResourceNode_Name()).getField()); - if (exactMatch) - { - if (name == null) - { - builder.append(" IS NULL"); - } - else - { - builder.append("=\'"); - builder.append(name); - builder.append("\'"); - } - } - else - { - // Here: name != null - builder.append(" LIKE \'"); - builder.append(name); - builder.append("%\'"); - } - } - - String sql = builder.toString(); - return sql; - } - - @Override - protected void doDeactivate() throws Exception - { - LifecycleUtil.deactivate(objectTypeCache); - objectTypeCache = null; - super.doDeactivate(); - } - - protected IObjectTypeCache createObjectTypeCache(IDBStore store) - { - ObjectTypeCache cache = new ObjectTypeCache(); - cache.setMappingStrategy(this); - return cache; - } -} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/MappingStrategy.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/MappingStrategy.java deleted file mode 100644 index fe5e0d6585..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/MappingStrategy.java +++ /dev/null @@ -1,390 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 - * Victor Roldan Betancort - http://bugs.eclipse.org/208689 - */ -package org.eclipse.emf.cdo.server.internal.db.mapping; - -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.common.revision.CDORevision; -import org.eclipse.emf.cdo.server.IStoreAccessor.QueryResourcesContext; -import org.eclipse.emf.cdo.server.db.IDBStore; -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.IMappingStrategy; -import org.eclipse.emf.cdo.server.internal.db.CDODBSchema; -import org.eclipse.emf.cdo.server.internal.db.ObjectIDIterator; -import org.eclipse.emf.cdo.server.internal.db.ToMany; -import org.eclipse.emf.cdo.server.internal.db.ToOne; -import org.eclipse.emf.cdo.server.internal.db.bundle.OM; - -import org.eclipse.net4j.db.DBException; -import org.eclipse.net4j.db.DBUtil; -import org.eclipse.net4j.db.IDBAdapter; -import org.eclipse.net4j.db.ddl.IDBField; -import org.eclipse.net4j.db.ddl.IDBTable; -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.om.trace.ContextTracer; - -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.EPackage; -import org.eclipse.emf.ecore.EStructuralFeature; - -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -/** - * @author Eike Stepper - */ -public abstract class MappingStrategy extends Lifecycle implements IMappingStrategy -{ - public static final String NAME_SEPARATOR = "_"; - - private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, MappingStrategy.class); - - private IDBStore store; - - private Map<String, String> properties; - - private Map<Object, IDBTable> referenceTables = new HashMap<Object, IDBTable>(); - - private Map<EClass, IClassMapping> classMappings = new HashMap<EClass, IClassMapping>(); - - public MappingStrategy() - { - } - - public IDBStore getStore() - { - return store; - } - - public void setStore(IDBStore store) - { - this.store = store; - } - - public synchronized Map<String, String> getProperties() - { - if (properties == null) - { - properties = new HashMap<String, String>(); - } - - return properties; - } - - public synchronized void setProperties(Map<String, String> properties) - { - this.properties = properties; - } - - public int getMaxTableNameLength() - { - String value = getProperties().get(PROP_MAX_TABLE_NAME_LENGTH); - return value == null ? store.getDBAdapter().getMaxTableNameLength() : Integer.valueOf(value); - } - - public int getMaxFieldNameLength() - { - String value = getProperties().get(PROP_MAX_FIELD_NAME_LENGTH); - return value == null ? store.getDBAdapter().getMaxFieldNameLength() : Integer.valueOf(value); - } - - public String getTableNamePrefix() - { - String value = getProperties().get(PROP_TABLE_NAME_PREFIX); - return StringUtil.safe(value); - } - - public boolean isQualifiedNames() - { - String value = getProperties().get(PROP_QUALIFIED_NAMES); - return value == null ? false : Boolean.valueOf(value); - } - - public boolean isForceNamesWithID() - { - String value = getProperties().get(PROP_FORCE_NAMES_WITH_ID); - return value == null ? false : Boolean.valueOf(value); - } - - public ToMany getToMany() - { - String value = getProperties().get(PROP_TO_MANY_REFERENCE_MAPPING); - return value == null ? ToMany.PER_REFERENCE : ToMany.valueOf(value); - } - - public ToOne getToOne() - { - String value = getProperties().get(PROP_TO_ONE_REFERENCE_MAPPING); - return value == null ? ToOne.LIKE_ATTRIBUTES : ToOne.valueOf(value); - } - - public Map<Object, IDBTable> getReferenceTables() - { - return referenceTables; - } - - public IClassMapping getClassMapping(EClass eClass) - { - synchronized (classMappings) - { - IClassMapping mapping = classMappings.get(eClass); - if (mapping == null) - { - mapping = createClassMapping(eClass); - classMappings.put(eClass, mapping); - } - - if (mapping == NoClassMapping.INSTANCE) - { - return null; - } - - return mapping; - } - } - - public String getTableName(EPackage ePackage) - { - String name = isQualifiedNames() ? EMFUtil.getQualifiedName(ePackage, NAME_SEPARATOR) : ePackage.getName(); - return getTableName(name, "P" + getStore().getMetaID(ePackage)); - } - - public String getTableName(EClass eClass) - { - String name = isQualifiedNames() ? EMFUtil.getQualifiedName(eClass, NAME_SEPARATOR) : eClass.getName(); - return getTableName(name, "C" + getStore().getMetaID(eClass)); - } - - public String getReferenceTableName(EClass eClass, EStructuralFeature feature) - { - String name = isQualifiedNames() ? EMFUtil.getQualifiedName(eClass, NAME_SEPARATOR) : eClass.getName(); - name += NAME_SEPARATOR; - name += feature.getName(); - name += "_refs"; - return getTableName(name, "F" + getStore().getMetaID(feature)); - } - - public String getReferenceTableName(EClass eClass) - { - String name = isQualifiedNames() ? EMFUtil.getQualifiedName(eClass, NAME_SEPARATOR) : eClass.getName(); - name += "_refs"; - return getTableName(name, "F" + getStore().getMetaID(eClass)); - } - - public String getReferenceTableName(EPackage ePackage) - { - String name = isQualifiedNames() ? EMFUtil.getQualifiedName(ePackage, NAME_SEPARATOR) : ePackage.getName(); - name += "_refs"; - return getTableName(name, "F" + getStore().getMetaID(ePackage)); - } - - public String getFieldName(EStructuralFeature feature) - { - return getName(feature.getName(), "F" + getStore().getMetaID(feature), getMaxFieldNameLength()); - } - - private String getTableName(String name, String suffix) - { - String prefix = getTableNamePrefix(); - if (prefix.length() != 0 && !prefix.endsWith(NAME_SEPARATOR)) - { - prefix += NAME_SEPARATOR; - } - - return getName(prefix + name, suffix, getMaxTableNameLength()); - } - - private String getName(String name, String suffix, int maxLength) - { - boolean forceNamesWithID = isForceNamesWithID(); - if (store.getDBAdapter().isReservedWord(name)) - { - forceNamesWithID = true; - } - - if (name.length() > maxLength || forceNamesWithID) - { - suffix = NAME_SEPARATOR + suffix.replace('-', 'S'); - int length = Math.min(name.length(), maxLength - suffix.length()); - name = name.substring(0, length) + suffix; - } - - return name; - } - - public String createWhereClause(long timeStamp) - { - StringBuilder builder = new StringBuilder(); - if (timeStamp == CDORevision.UNSPECIFIED_DATE) - { - builder.append(CDODBSchema.ATTRIBUTES_REVISED); - builder.append("=0"); - } - else - { - builder.append("("); - builder.append(CDODBSchema.ATTRIBUTES_REVISED); - builder.append("=0 OR "); - builder.append(CDODBSchema.ATTRIBUTES_REVISED); - builder.append(">="); - builder.append(timeStamp); - builder.append(") AND "); - builder.append(timeStamp); - builder.append(">="); - builder.append(CDODBSchema.ATTRIBUTES_CREATED); - } - - return builder.toString(); - } - - public final CloseableIterator<CDOID> readObjectIDs(final IDBStoreAccessor accessor) - { - List<EClass> classes = getClassesWithObjectInfo(); - final Iterator<EClass> classIt = classes.iterator(); - return new ObjectIDIterator(this, accessor) - { - @Override - protected ResultSet getNextResultSet() - { - while (classIt.hasNext()) - { - EClass eClass = classIt.next(); - IClassMapping mapping = getClassMapping(eClass); - if (mapping != null) - { - IDBTable table = mapping.getTable(); - if (table != null) - { - StringBuilder builder = new StringBuilder(); - builder.append("SELECT DISTINCT "); - builder.append(CDODBSchema.ATTRIBUTES_ID); - builder.append(" FROM "); - builder.append(table); - String sql = builder.toString(); - - try - { - return accessor.getJDBCDelegate().getStatement().executeQuery(sql); - } - catch (SQLException ex) - { - throw new DBException(ex); - } - } - } - } - - return null; - } - }; - } - - public final void queryResources(IDBStoreAccessor accessor, QueryResourcesContext context) - { - CDOID folderID = context.getFolderID(); - String name = context.getName(); - boolean exactMatch = context.exactMatch(); - String where = createWhereClause(context.getTimeStamp()); - - String[] queries = getResourceQueries(folderID, name, exactMatch); - for (String query : queries) - { - StringBuilder builder = new StringBuilder(); - builder.append(query); - builder.append(" AND ("); - builder.append(where); - builder.append(")"); - - String sql = builder.toString(); - if (TRACER.isEnabled()) - { - TRACER.trace(sql); - } - - ResultSet resultSet = null; - - try - { - resultSet = accessor.getJDBCDelegate().getStatement().executeQuery(sql); - while (resultSet.next()) - { - long longID = resultSet.getLong(1); - CDOID id = CDOIDUtil.createLong(longID); - if (!context.addResource(id)) - { - // No more results allowed - return; - } - } - } - catch (SQLException ex) - { - throw new DBException(ex); - } - finally - { - DBUtil.close(resultSet); - } - } - } - - protected abstract String[] getResourceQueries(CDOID folderID, String name, boolean exactMatch); - - public long repairAfterCrash(IDBAdapter dbAdapter, Connection connection) - { - long maxCDOID = 0L; - for (EClass idClass : getClassesWithObjectInfo()) - { - IClassMapping classMapping = getClassMapping(idClass); - IDBTable table = classMapping.getTable(); - IDBField idField = table.getField(CDODBSchema.ATTRIBUTES_ID); - long classMaxCDOID = DBUtil.selectMaximumLong(connection, idField); - if (TRACER.isEnabled()) - { - TRACER.format("Max CDOID of table {0}: {1}", table, classMaxCDOID); - } - - maxCDOID = Math.max(maxCDOID, classMaxCDOID); - } - - return maxCDOID + 2L; - } - - @Override - public String toString() - { - return getType(); - } - - /** - * The implementation of this method must take care of creating a unique ids to prevent duplicate resource paths. - */ - protected abstract IClassMapping createClassMapping(EClass eClass); - - protected abstract List<EClass> getClassesWithObjectInfo(); - - @Override - protected void doBeforeActivate() throws Exception - { - super.doBeforeActivate(); - checkState(store, "store"); - } -} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/NoClassMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/NoClassMapping.java deleted file mode 100644 index d6f286f2e7..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/NoClassMapping.java +++ /dev/null @@ -1,124 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 - * Stefan Winkler - https://bugs.eclipse.org/bugs/show_bug.cgi?id=259402 - */ -package org.eclipse.emf.cdo.server.internal.db.mapping; - -import org.eclipse.emf.cdo.common.id.CDOID; -import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; -import org.eclipse.emf.cdo.server.db.mapping.IAttributeMapping; -import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; -import org.eclipse.emf.cdo.server.db.mapping.IFeatureMapping; -import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; -import org.eclipse.emf.cdo.server.db.mapping.IReferenceMapping; -import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; -import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta; - -import org.eclipse.net4j.db.ddl.IDBTable; -import org.eclipse.net4j.util.om.monitor.OMMonitor; - -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.EStructuralFeature; - -import java.util.Collections; -import java.util.List; -import java.util.Set; - -/** - * @author Eike Stepper - */ -public class NoClassMapping implements IClassMapping -{ - public static final IClassMapping INSTANCE = new NoClassMapping(); - - private NoClassMapping() - { - } - - public IMappingStrategy getMappingStrategy() - { - return null; - } - - public EClass getEClass() - { - return null; - } - - public IDBTable getTable() - { - return null; - } - - public Set<IDBTable> getAffectedTables() - { - return Collections.emptySet(); - } - - public boolean hasFullRevisionInfo() - { - return false; - } - - public IFeatureMapping getFeatureMapping(EStructuralFeature feature) - { - return null; - } - - public List<IAttributeMapping> getAttributeMappings() - { - return null; - } - - public List<IReferenceMapping> getReferenceMappings() - { - return null; - } - - public IAttributeMapping getAttributeMapping(EStructuralFeature feature) - { - return null; - } - - public IReferenceMapping getReferenceMapping(EStructuralFeature feature) - { - return null; - } - - public void writeRevision(IDBStoreAccessor accessor, InternalCDORevision revision, OMMonitor monitor) - { - } - - public void detachObject(IDBStoreAccessor accessor, CDOID id, long revised, OMMonitor monitor) - { - } - - public boolean readRevision(IDBStoreAccessor accessor, InternalCDORevision revision, int referenceChunk) - { - return false; - } - - public boolean readRevisionByTime(IDBStoreAccessor accessor, InternalCDORevision revision, long timeStamp, - int referenceChunk) - { - return false; - } - - public boolean readRevisionByVersion(IDBStoreAccessor accessor, InternalCDORevision revision, int version, - int referenceChunk) - { - return false; - } - - public void writeRevisionDelta(IDBStoreAccessor accessor, InternalCDORevisionDelta delta, long created, - OMMonitor monitor) - { - } -} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/ReferenceMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/ReferenceMapping.java deleted file mode 100644 index 026b63b6a6..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/ReferenceMapping.java +++ /dev/null @@ -1,198 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 - * Stefan Winkler - https://bugs.eclipse.org/bugs/show_bug.cgi?id=259402 - */ -package org.eclipse.emf.cdo.server.internal.db.mapping; - -import org.eclipse.emf.cdo.common.id.CDOID; -import org.eclipse.emf.cdo.server.IRepository; -import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk; -import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; -import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader; -import org.eclipse.emf.cdo.server.db.IJDBCDelegate; -import org.eclipse.emf.cdo.server.db.mapping.IReferenceMapping; -import org.eclipse.emf.cdo.server.internal.db.CDODBSchema; -import org.eclipse.emf.cdo.server.internal.db.ToMany; -import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; - -import org.eclipse.net4j.db.DBType; -import org.eclipse.net4j.db.ddl.IDBField; -import org.eclipse.net4j.db.ddl.IDBTable; -import org.eclipse.net4j.db.ddl.IDBIndex.Type; - -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.EPackage; -import org.eclipse.emf.ecore.EStructuralFeature; - -import java.text.MessageFormat; -import java.util.List; -import java.util.Map; - -/** - * @author Eike Stepper - */ -public class ReferenceMapping extends FeatureMapping implements IReferenceMapping -{ - private IDBTable table; - - private ToMany toMany; - - private boolean withFeature; - - public ReferenceMapping(ClassMapping classMapping, EStructuralFeature feature, ToMany toMany) - { - super(classMapping, feature); - this.toMany = toMany; - mapReference(classMapping.getEClass(), feature); - } - - public IDBTable getTable() - { - return table; - } - - public boolean isWithFeature() - { - return withFeature; - } - - protected void mapReference(EClass eClass, EStructuralFeature feature) - { - MappingStrategy mappingStrategy = getClassMapping().getMappingStrategy(); - switch (toMany) - { - case PER_REFERENCE: - { - withFeature = false; - String tableName = mappingStrategy.getReferenceTableName(eClass, feature); - Object referenceMappingKey = getReferenceMappingKey(feature); - table = mapReferenceTable(referenceMappingKey, tableName); - break; - } - - case PER_CLASS: - withFeature = true; - table = mapReferenceTable(eClass, mappingStrategy.getReferenceTableName(eClass)); - break; - - case PER_PACKAGE: - withFeature = true; - EPackage ePackage = eClass.getEPackage(); - table = mapReferenceTable(ePackage, mappingStrategy.getReferenceTableName(ePackage)); - break; - - case PER_REPOSITORY: - withFeature = true; - IRepository repository = mappingStrategy.getStore().getRepository(); - table = mapReferenceTable(repository, repository.getName() + "_refs"); - break; - - default: - throw new IllegalArgumentException("Invalid mapping: " + toMany); - } - } - - protected Object getReferenceMappingKey(EStructuralFeature feature) - { - return getClassMapping().createReferenceMappingKey(feature); - } - - protected IDBTable mapReferenceTable(Object key, String tableName) - { - Map<Object, IDBTable> referenceTables = getClassMapping().getMappingStrategy().getReferenceTables(); - IDBTable table = referenceTables.get(key); - if (table == null) - { - table = addReferenceTable(tableName); - referenceTables.put(key, table); - } - - return table; - } - - protected IDBTable addReferenceTable(String tableName) - { - IDBTable table = getClassMapping().addTable(tableName); - if (withFeature) - { - table.addField(CDODBSchema.REFERENCES_FEATURE, DBType.BIGINT); - } - - IDBField sourceField = table.addField(CDODBSchema.REFERENCES_SOURCE, DBType.BIGINT); - IDBField versionField = table.addField(CDODBSchema.REFERENCES_VERSION, DBType.INTEGER); - IDBField idxField = table.addField(CDODBSchema.REFERENCES_IDX, DBType.INTEGER); - table.addField(CDODBSchema.REFERENCES_TARGET, DBType.BIGINT); - - table.addIndex(Type.NON_UNIQUE, sourceField, versionField); - table.addIndex(Type.NON_UNIQUE, idxField); - return table; - } - - public final void writeReference(IDBStoreAccessor accessor, InternalCDORevision revision) - { - int idx = 0; - for (Object element : revision.getList(getFeature())) - { - writeReferenceEntry(accessor, revision.getID(), revision.getVersion(), idx++, (CDOID)element); - } - } - - public final void writeReferenceEntry(IDBStoreAccessor accessor, CDOID id, int version, int idx, CDOID targetId) - { - IJDBCDelegate jdbcDelegate = accessor.getJDBCDelegate(); - jdbcDelegate.insertReference(id, version, idx++, targetId, this); - } - - public void insertReferenceEntry(IDBStoreAccessor accessor, CDOID id, int newVersion, int index, CDOID value) - { - accessor.getJDBCDelegate().insertReferenceRow(id, newVersion, index, value, this); - } - - public void moveReferenceEntry(IDBStoreAccessor accessor, CDOID id, int newVersion, int oldPosition, int newPosition) - { - accessor.getJDBCDelegate().moveReferenceRow(id, newVersion, oldPosition, newPosition, this); - } - - public void removeReferenceEntry(IDBStoreAccessor accessor, CDOID id, int index, int newVersion) - { - accessor.getJDBCDelegate().removeReferenceRow(id, index, newVersion, this); - } - - public void updateReference(IDBStoreAccessor accessor, CDOID id, int newVersion, int index, CDOID value) - { - accessor.getJDBCDelegate().updateReference(id, newVersion, index, value, this); - } - - public void updateReferenceVersion(IDBStoreAccessor accessor, CDOID id, int newVersion) - { - accessor.getJDBCDelegate().updateReferenceVersion(id, newVersion, this); - } - - public void deleteReference(IDBStoreAccessor accessor, CDOID id) - { - accessor.getJDBCDelegate().deleteReferences(id, this); - } - - public final void readReference(IDBStoreAccessor accessor, InternalCDORevision revision, int referenceChunk) - { - accessor.getJDBCDelegate().selectRevisionReferences(revision, this, referenceChunk); - } - - public final void readChunks(IDBStoreChunkReader chunkReader, List<Chunk> chunks, String where) - { - chunkReader.getAccessor().getJDBCDelegate().selectRevisionReferenceChunks(chunkReader, chunks, this, where); - } - - @Override - public String toString() - { - return MessageFormat.format("ReferenceMapping[feature={0}, table={1}]", getFeature(), getTable()); - } -} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/RootClassMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/RootClassMapping.java deleted file mode 100644 index ac16396199..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/RootClassMapping.java +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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.revision.CDORevision; -import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; - -import org.eclipse.emf.ecore.EcorePackage; - -/** - * @author Eike Stepper - */ -public class RootClassMapping extends ClassMapping -{ - public RootClassMapping(VerticalMappingStrategy mappingStrategy) - { - super(mappingStrategy, EcorePackage.eINSTANCE.getEObject(), null); - initTable(getTable(), true); - } - - @Override - public VerticalMappingStrategy getMappingStrategy() - { - return (VerticalMappingStrategy)super.getMappingStrategy(); - } - - public boolean hasFullRevisionInfo() - { - return true; - } - - @Override - protected void checkDuplicateResources(IDBStoreAccessor accessor, CDORevision revision) throws IllegalStateException - { - throw new UnsupportedOperationException(); - } -} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/ToOneReferenceMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/ToOneReferenceMapping.java deleted file mode 100644 index 634698a652..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/ToOneReferenceMapping.java +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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.id.CDOID; -import org.eclipse.emf.cdo.server.db.CDODBUtil; -import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; - -import org.eclipse.emf.ecore.EStructuralFeature; - -/** - * @author Eike Stepper - */ -public class ToOneReferenceMapping extends AttributeMapping.AMObject -{ - public ToOneReferenceMapping(ClassMapping classMapping, EStructuralFeature feature) - { - super(classMapping, feature); - } - - @Override - public Long getRevisionValue(InternalCDORevision revision) - { - CDOID id = (CDOID)super.getRevisionValue(revision); - return CDODBUtil.getLong(id); - } -} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMapping.java new file mode 100644 index 0000000000..697e080113 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/TypeMapping.java @@ -0,0 +1,409 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 + * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 + */ +package org.eclipse.emf.cdo.server.internal.db.mapping; + +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDUtil; +import org.eclipse.emf.cdo.server.db.CDODBUtil; +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.MetaDataManager; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; + +import org.eclipse.net4j.db.DBType; +import org.eclipse.net4j.db.ddl.IDBField; +import org.eclipse.net4j.db.ddl.IDBTable; + +import org.eclipse.emf.ecore.EStructuralFeature; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.Date; + +/** + * This is a default implementation for the {@link ITypeMapping} interface which provides default behavor for all common + * types. + * + * @author Eike Stepper + */ +public abstract class TypeMapping implements ITypeMapping +{ + private IMappingStrategy mappingStrategy; + + private EStructuralFeature feature; + + private IDBField field; + + /** + * Create a new type mapping + * + * @param mappingStrategy + * the associated mapping strategy. + * @param feature + * the feature to be mapped. + */ + public TypeMapping(IMappingStrategy mappingStrategy, EStructuralFeature feature) + { + this.mappingStrategy = mappingStrategy; + this.feature = feature; + } + + public final void setValueFromRevision(PreparedStatement stmt, int index, InternalCDORevision revision) + throws SQLException + { + setValue(stmt, index, getRevisionValue(revision)); + } + + public final void setValue(PreparedStatement stmt, int index, Object value) throws SQLException + { + if (value == null) + { + stmt.setNull(index, getSqlType()); + } + else + { + doSetValue(stmt, index, value); + } + } + + public final void createDBField(IDBTable table) + { + createDBField(table, mappingStrategy.getFieldName(feature)); + } + + public final void createDBField(IDBTable table, String fieldName) + { + DBType fieldType = getDBType(); + int fieldLength = getDBLength(fieldType); + field = table.addField(fieldName, fieldType, fieldLength); + } + + public final IDBField getField() + { + return field; + } + + public final void readValueToRevision(ResultSet resultSet, int index, InternalCDORevision revision) + throws SQLException + { + Object value = readValue(resultSet, index); + revision.setValue(getFeature(), value); + } + + public final Object readValue(ResultSet resultSet, int index) throws SQLException + { + Object value = getResultSetValue(resultSet, index); + if (resultSet.wasNull()) + { + value = null; + } + return value; + } + + public final EStructuralFeature getFeature() + { + return feature; + } + + protected final Object getRevisionValue(InternalCDORevision revision) + { + return revision.getValue(getFeature()); + } + + protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException + { + stmt.setObject(index, value, getSqlType()); + } + + /** + * Returns the SQL type of this TypeMapping. The default implementation considers the type map hold by the meta-data + * manager (@see {@link MetaDataManager#getDBType(org.eclipse.emf.ecore.EClassifier)} Subclasses may override. + * + * @return The sql type of this TypeMapping. + */ + protected int getSqlType() + { + return getDBType().getCode(); + } + + protected DBType getDBType() + { + return mappingStrategy.getStore().getMetaDataManager().getDBType(feature.getEType()); + } + + protected int getDBLength(DBType type) + { + // TODO: implement DBAdapter.getDBLength + // mappingStrategy.getStore().getDBAdapter().getDBLength(type); + return type == DBType.VARCHAR ? 32672 : IDBField.DEFAULT; + } + + protected abstract Object getResultSetValue(ResultSet resultSet, int column) throws SQLException; + + /** + * @author Eike Stepper + */ + public static class TMEnum extends TypeMapping + { + public TMEnum(IMappingStrategy strategy, EStructuralFeature feature) + { + super(strategy, feature); + } + + @Override + public Object getResultSetValue(ResultSet resultSet, int column) throws SQLException + { + // see Bug 271941 + return resultSet.getInt(column); + // EEnum type = (EEnum)getFeature().getEType(); + // int value = resultSet.getInt(column); + // return type.getEEnumLiteral(value); + } + + @Override + protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException + { + super.doSetValue(stmt, index, value); + } + } + + /** + * @author Eike Stepper + */ + public static class TMString extends TypeMapping + { + public TMString(IMappingStrategy strategy, EStructuralFeature feature) + { + super(strategy, feature); + } + + @Override + public Object getResultSetValue(ResultSet resultSet, int column) throws SQLException + { + return resultSet.getString(column); + } + } + + /** + * @author Eike Stepper + */ + public static class TMShort extends TypeMapping + { + public TMShort(IMappingStrategy strategy, EStructuralFeature feature) + { + super(strategy, feature); + } + + @Override + public Object getResultSetValue(ResultSet resultSet, int column) throws SQLException + { + return resultSet.getShort(column); + } + } + + /** + * @author Eike Stepper <br> + * TODO add mapping/unmapping calls for external references here + */ + public static class TMObject extends TypeMapping + { + public TMObject(IMappingStrategy strategy, EStructuralFeature feature) + { + super(strategy, feature); + } + + @Override + public Object getResultSetValue(ResultSet resultSet, int column) throws SQLException + { + long id = resultSet.getLong(column); + if (resultSet.wasNull()) + { + return null; + } + + return CDOIDUtil.createLong(id); + } + + @Override + protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException + { + super.doSetValue(stmt, index, CDODBUtil.getLong((CDOID)value)); + } + } + + /** + * @author Eike Stepper + */ + public static class TMLong extends TypeMapping + { + public TMLong(IMappingStrategy strategy, EStructuralFeature feature) + { + super(strategy, feature); + } + + @Override + public Object getResultSetValue(ResultSet resultSet, int column) throws SQLException + { + return resultSet.getLong(column); + } + } + + /** + * @author Eike Stepper + */ + public static class TMInteger extends TypeMapping + { + public TMInteger(IMappingStrategy strategy, EStructuralFeature feature) + { + super(strategy, feature); + } + + @Override + public Object getResultSetValue(ResultSet resultSet, int column) throws SQLException + { + return resultSet.getInt(column); + } + } + + /** + * @author Eike Stepper + */ + public static class TMFloat extends TypeMapping + { + public TMFloat(IMappingStrategy strategy, EStructuralFeature feature) + { + super(strategy, feature); + } + + @Override + public Object getResultSetValue(ResultSet resultSet, int column) throws SQLException + { + return resultSet.getFloat(column); + } + } + + /** + * @author Eike Stepper + */ + public static class TMDouble extends TypeMapping + { + public TMDouble(IMappingStrategy strategy, EStructuralFeature feature) + { + super(strategy, feature); + } + + @Override + public Object getResultSetValue(ResultSet resultSet, int column) throws SQLException + { + return resultSet.getDouble(column); + } + } + + /** + * @author Eike Stepper + */ + public static class TMDate extends TypeMapping + { + public TMDate(IMappingStrategy strategy, EStructuralFeature feature) + { + super(strategy, feature); + } + + @Override + public Object getResultSetValue(ResultSet resultSet, int column) throws SQLException + { + return resultSet.getTimestamp(column); + } + + @Override + protected void doSetValue(PreparedStatement stmt, int index, Object value) throws SQLException + { + stmt.setTimestamp(index, new Timestamp(((Date)value).getTime())); + } + } + + /** + * @author Eike Stepper + */ + public static class TMCharacter extends TypeMapping + { + public TMCharacter(IMappingStrategy strategy, EStructuralFeature feature) + { + super(strategy, feature); + } + + @Override + public Object getResultSetValue(ResultSet resultSet, int column) throws SQLException + { + String str = resultSet.getString(column); + if (resultSet.wasNull()) + { + return null; + } + + return str.charAt(0); + } + } + + /** + * @author Eike Stepper + */ + public static class TMByte extends TypeMapping + { + public TMByte(IMappingStrategy strategy, EStructuralFeature feature) + { + super(strategy, feature); + } + + @Override + public Object getResultSetValue(ResultSet resultSet, int column) throws SQLException + { + return resultSet.getByte(column); + } + } + + /** + * @author Eike Stepper + */ + public static class TMBytes extends TypeMapping + { + public TMBytes(IMappingStrategy strategy, EStructuralFeature feature) + { + super(strategy, feature); + } + + @Override + public Object getResultSetValue(ResultSet resultSet, int column) throws SQLException + { + return resultSet.getBytes(column); + } + } + + /** + * @author Eike Stepper + */ + public static class TMBoolean extends TypeMapping + { + public TMBoolean(IMappingStrategy strategy, EStructuralFeature feature) + { + super(strategy, feature); + } + + @Override + public Object getResultSetValue(ResultSet resultSet, int column) throws SQLException + { + return resultSet.getBoolean(column); + } + } +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/VerticalClassMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/VerticalClassMapping.java deleted file mode 100644 index 7fdd2d4995..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/VerticalClassMapping.java +++ /dev/null @@ -1,96 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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.revision.CDORevision; -import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; -import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; -import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; - -import org.eclipse.net4j.util.om.monitor.OMMonitor; - -import org.eclipse.emf.ecore.EClass; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author Eike Stepper - */ -public class VerticalClassMapping extends ClassMapping -{ - private List<IClassMapping> superMappings; - - public VerticalClassMapping(VerticalMappingStrategy mappingStrategy, EClass eClass) - { - super(mappingStrategy, eClass, null); - for (EClass superType : eClass.getESuperTypes()) - { - IClassMapping superMapping = mappingStrategy.getClassMapping(superType); - if (superMapping != null) - { - if (superMappings == null) - { - superMappings = new ArrayList<IClassMapping>(0); - } - - superMappings.add(superMapping); - } - } - } - - @Override - public VerticalMappingStrategy getMappingStrategy() - { - return (VerticalMappingStrategy)super.getMappingStrategy(); - } - - public boolean hasFullRevisionInfo() - { - return false; - } - - public List<IClassMapping> getSuperMappings() - { - return superMappings; - } - - @Override - public void writeRevision(IDBStoreAccessor accessor, InternalCDORevision revision, OMMonitor monitor) - { - if (superMappings != null) - { - try - { - monitor.begin(1 + superMappings.size()); - super.writeRevision(accessor, revision, monitor.fork()); - for (IClassMapping superMapping : superMappings) - { - superMapping.writeRevision(accessor, revision, monitor.fork()); - } - } - finally - { - monitor.done(); - } - } - else - { - super.writeRevision(accessor, revision, monitor); - } - } - - @Override - protected void checkDuplicateResources(IDBStoreAccessor accessor, CDORevision revision) throws IllegalStateException - { - throw new UnsupportedOperationException(); - } -} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/VerticalMappingStrategy.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/VerticalMappingStrategy.java deleted file mode 100644 index 34dd89aed3..0000000000 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/VerticalMappingStrategy.java +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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.id.CDOID; -import org.eclipse.emf.cdo.common.model.CDOClassifierRef; -import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; -import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; - -import org.eclipse.emf.ecore.EClass; - -import java.util.Collections; -import java.util.List; - -/** - * @author Eike Stepper - */ -public class VerticalMappingStrategy extends MappingStrategy -{ - private RootClassMapping rootClassMapping; - - public VerticalMappingStrategy() - { - throw new UnsupportedOperationException(); - } - - public String getType() - { - return "vertical"; - } - - public RootClassMapping getRootClassMapping() - { - if (rootClassMapping == null) - { - rootClassMapping = new RootClassMapping(this); - } - - return rootClassMapping; - } - - public CDOClassifierRef readObjectType(IDBStoreAccessor accessor, CDOID id) - { - throw new UnsupportedOperationException(); - } - - @Override - protected IClassMapping createClassMapping(EClass eClass) - { - return new VerticalClassMapping(this, eClass); - } - - @Override - protected List<EClass> getClassesWithObjectInfo() - { - return Collections.singletonList(rootClassMapping.getEClass()); - } - - @Override - protected String[] getResourceQueries(CDOID folderID, String name, boolean exactMatch) - { - throw new UnsupportedOperationException(); - } -} 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 new file mode 100644 index 0000000000..2dec43fb55 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalClassMapping.java @@ -0,0 +1,370 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 + * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 + */ +package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal; + +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDUtil; +import org.eclipse.emf.cdo.common.model.CDOModelUtil; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.eresource.EresourcePackage; +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.ITypeMapping; +import org.eclipse.emf.cdo.server.internal.db.CDODBSchema; +import org.eclipse.emf.cdo.server.internal.db.bundle.OM; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; + +import org.eclipse.net4j.db.DBException; +import org.eclipse.net4j.db.DBType; +import org.eclipse.net4j.db.DBUtil; +import org.eclipse.net4j.db.ddl.IDBField; +import org.eclipse.net4j.db.ddl.IDBIndex; +import org.eclipse.net4j.db.ddl.IDBTable; +import org.eclipse.net4j.util.om.monitor.OMMonitor; +import org.eclipse.net4j.util.om.monitor.OMMonitor.Async; +import org.eclipse.net4j.util.om.trace.ContextTracer; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * @author Eike Stepper + * @since 2.0 + */ +public abstract class AbstractHorizontalClassMapping implements IClassMapping +{ + private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, AbstractHorizontalClassMapping.class); + + private EClass eClass; + + private IDBTable table; + + private AbstractHorizontalMappingStrategy mappingStrategy; + + private List<ITypeMapping> valueMappings; + + private List<IListMapping> listMappings; + + public AbstractHorizontalClassMapping(AbstractHorizontalMappingStrategy mappingStrategy, EClass eClass) + { + this.mappingStrategy = mappingStrategy; + this.eClass = eClass; + + initTable(); + initFeatures(); + } + + private void initTable() + { + String name = getMappingStrategy().getTableName(eClass); + table = getMappingStrategy().getStore().getDBSchema().addTable(name); + + IDBField idField = table.addField(CDODBSchema.ATTRIBUTES_ID, DBType.BIGINT, true); + table.addField(CDODBSchema.ATTRIBUTES_VERSION, DBType.INTEGER, true); + table.addField(CDODBSchema.ATTRIBUTES_CLASS, DBType.BIGINT, true); + table.addField(CDODBSchema.ATTRIBUTES_CREATED, DBType.BIGINT, true); + IDBField revisedField = table.addField(CDODBSchema.ATTRIBUTES_REVISED, DBType.BIGINT, true); + table.addField(CDODBSchema.ATTRIBUTES_RESOURCE, DBType.BIGINT, true); + table.addField(CDODBSchema.ATTRIBUTES_CONTAINER, DBType.BIGINT, true); + table.addField(CDODBSchema.ATTRIBUTES_FEATURE, DBType.INTEGER, true); + + table.addIndex(IDBIndex.Type.NON_UNIQUE, idField, revisedField); + } + + private void initFeatures() + { + EStructuralFeature[] features = CDOModelUtil.getAllPersistentFeatures(eClass); + + if (features == null) + { + valueMappings = Collections.emptyList(); + listMappings = Collections.emptyList(); + } + else + { + valueMappings = createValueMappings(features); + listMappings = createListMappings(features); + } + } + + private List<ITypeMapping> createValueMappings(EStructuralFeature[] features) + { + List<ITypeMapping> mappings = new ArrayList<ITypeMapping>(); + for (EStructuralFeature feature : features) + { + if (!feature.isMany()) + { + ITypeMapping mapping = mappingStrategy.createValueMapping(feature); + mapping.createDBField(getTable()); + mappings.add(mapping); + } + } + + return mappings; + } + + private List<IListMapping> createListMappings(EStructuralFeature[] features) + { + List<IListMapping> listMappings = new ArrayList<IListMapping>(); + for (EStructuralFeature feature : features) + { + if (feature.isMany()) + { + listMappings.add(mappingStrategy.createListMapping(eClass, feature)); + } + } + + return listMappings; + } + + /** + * Read the revision's values from the DB. + * + * @return <code>true</code> if the revision has been read successfully.<br> + * <code>false</code> if the revision does not exist in the DB. + */ + protected final boolean readValuesFromStatement(PreparedStatement pstmt, InternalCDORevision revision) + { + ResultSet resultSet = null; + try + { + if (TRACER.isEnabled()) + { + TRACER.format("Executing Query: {0}", pstmt.toString()); + } + + pstmt.setMaxRows(1); // Optimization: only 1 row + + resultSet = pstmt.executeQuery(); + if (!resultSet.next()) + { + if (TRACER.isEnabled()) + { + TRACER.format("Resultset was empty."); + } + + return false; + } + + int i = 1; + revision.setVersion(resultSet.getInt(i++)); + revision.setCreated(resultSet.getLong(i++)); + revision.setRevised(resultSet.getLong(i++)); + revision.setResourceID(CDOIDUtil.createLong(resultSet.getLong(i++))); + + // TODO add mapping for external container CDOIDs here -> + revision.setContainerID(CDOIDUtil.createLong(resultSet.getLong(i++))); + revision.setContainingFeatureID(resultSet.getInt(i++)); + + for (ITypeMapping mapping : valueMappings) + { + mapping.readValueToRevision(resultSet, i++, revision); + } + + return true; + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + DBUtil.close(resultSet); + } + } + + protected final void readLists(IDBStoreAccessor accessor, InternalCDORevision revision, int listChunk) + { + for (IListMapping listMapping : listMappings) + { + listMapping.readValues(accessor, revision, listChunk); + } + } + + public final void detachObject(IDBStoreAccessor accessor, CDOID id, long revised, OMMonitor monitor) + { + Async async = null; + try + { + monitor.begin(getListMappings().size() + 1); + async = monitor.forkAsync(); + reviseObject(accessor, id, revised); + async.stop(); + async = monitor.forkAsync(getListMappings().size()); + for (IListMapping mapping : getListMappings()) + { + mapping.objectRevised(accessor, id, revised); + } + } + finally + { + async.stop(); + monitor.done(); + } + } + + protected final IMetaDataManager getMetaDataManager() + { + return getMappingStrategy().getStore().getMetaDataManager(); + } + + protected final IMappingStrategy getMappingStrategy() + { + return mappingStrategy; + } + + protected final EClass getEClass() + { + return eClass; + } + + public final List<ITypeMapping> getValueMappings() + { + return valueMappings; + } + + public final ITypeMapping getValueMapping(EStructuralFeature feature) + { + for (ITypeMapping mapping : valueMappings) + { + if (mapping.getFeature() == feature) + { + return mapping; + } + } + return null; + } + + public final List<IListMapping> getListMappings() + { + return listMappings; + } + + public final IListMapping getListMapping(EStructuralFeature feature) + { + for (IListMapping mapping : listMappings) + { + if (mapping.getFeature() == feature) + { + return mapping; + } + } + + throw new IllegalArgumentException("List mapping for feature " + feature + " does not exist."); + } + + protected final IDBTable getTable() + { + return table; + } + + public Collection<IDBTable> getDBTables() + { + ArrayList<IDBTable> tables = new ArrayList<IDBTable>(); + tables.add(table); + + for (IListMapping listMapping : listMappings) + { + tables.addAll(listMapping.getDBTables()); + } + + return tables; + } + + private void checkDuplicateResources(IDBStoreAccessor accessor, CDORevision revision) throws IllegalStateException + { + CDOID folderID = (CDOID)revision.data().getContainerID(); + String name = (String)revision.data().get(EresourcePackage.eINSTANCE.getCDOResourceNode_Name(), 0); + + CDOID existingID = accessor.readResourceID(folderID, name, CDORevision.UNSPECIFIED_DATE); + if (existingID != null && !existingID.equals(revision.getID())) + { + throw new IllegalStateException("Duplicate resource or folder: " + name + " in folder " + folderID); + } + } + + protected void writeLists(IDBStoreAccessor accessor, InternalCDORevision revision) + { + for (IListMapping listMapping : listMappings) + { + listMapping.writeValues(accessor, revision); + } + } + + public void writeRevision(IDBStoreAccessor accessor, InternalCDORevision revision, OMMonitor monitor) + { + Async async = null; + try + { + monitor.begin(10); + async = monitor.forkAsync(); + + CDOID id = revision.getID(); + if (revision.getVersion() == 1) + { + mappingStrategy.putObjectType(accessor, id, eClass); + } + else + { + long revised = revision.getCreated() - 1; + reviseObject(accessor, id, revised); + for (IListMapping mapping : getListMappings()) + { + mapping.objectRevised(accessor, id, revised); + } + } + + async.stop(); + async = monitor.forkAsync(); + + if (revision.isResourceFolder() || revision.isResource()) + { + checkDuplicateResources(accessor, revision); + } + + async.stop(); + async = monitor.forkAsync(); + + // Write attribute table always (even without modeled attributes!) + writeValues(accessor, revision); + + async.stop(); + async = monitor.forkAsync(7); + + // Write list tables only if they exist + if (listMappings != null) + { + writeLists(accessor, revision); + } + } + finally + { + async.stop(); + monitor.done(); + } + } + + protected abstract void writeValues(IDBStoreAccessor accessor, InternalCDORevision revision); + + protected abstract void reviseObject(IDBStoreAccessor accessor, CDOID id, long revised); +} 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 new file mode 100644 index 0000000000..f42f390504 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractHorizontalMappingStrategy.java @@ -0,0 +1,189 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 + * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 + */ +package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal; + +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDUtil; +import org.eclipse.emf.cdo.common.model.CDOClassifierRef; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.eresource.CDOResourceNode; +import org.eclipse.emf.cdo.eresource.EresourcePackage; +import org.eclipse.emf.cdo.server.IStoreAccessor.QueryResourcesContext; +import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; +import org.eclipse.emf.cdo.server.db.IObjectTypeCache; +import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; +import org.eclipse.emf.cdo.server.internal.db.bundle.OM; +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.IDBAdapter; +import org.eclipse.net4j.util.lifecycle.LifecycleUtil; +import org.eclipse.net4j.util.om.trace.ContextTracer; + +import org.eclipse.emf.ecore.EClass; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; + +/** + * * This abstract base class refines {@link AbstractMappingStrategy} by implementing aspects common to horizontal + * mapping strategies -- namely: + * <ul> + * <li>object type cache (table cdo_objects) + * <li>resource query handling + * </ul> + * + * @author Eike Stepper + * @since 2.0 + */ +public abstract class AbstractHorizontalMappingStrategy extends AbstractMappingStrategy +{ + private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, AbstractHorizontalMappingStrategy.class); + + /** + * The associated object type cache. + */ + private IObjectTypeCache objectTypeCache; + + @Override + public CDOClassifierRef readObjectType(IDBStoreAccessor accessor, CDOID id) + { + return objectTypeCache.getObjectType(accessor, id); + } + + public void putObjectType(IDBStoreAccessor accessor, CDOID id, EClass type) + { + objectTypeCache.putObjectType(accessor, id, type); + } + + @Override + public long repairAfterCrash(IDBAdapter dbAdapter, Connection connection) + { + return objectTypeCache.getMaxId(connection) + 1; + } + + @Override + protected Collection<EClass> getClassesWithObjectInfo() + { + return getClassMappings().keySet(); + } + + @Override + protected void doActivate() throws Exception + { + super.doActivate(); + if (objectTypeCache == null) + { + objectTypeCache = createObjectTypeCache(); + LifecycleUtil.activate(objectTypeCache); + } + } + + @Override + protected void doDeactivate() throws Exception + { + LifecycleUtil.deactivate(objectTypeCache); + objectTypeCache = null; + super.doDeactivate(); + } + + private IObjectTypeCache createObjectTypeCache() + { + ObjectTypeCache cache = new ObjectTypeCache(); + cache.setMappingStrategy(this); + return cache; + } + + @Override + public void queryResources(IDBStoreAccessor dbStoreAccessor, QueryResourcesContext context) + { + // only support timestamp in audit mode + if (context.getTimeStamp() != CDORevision.UNSPECIFIED_DATE && !hasAuditSupport()) + { + throw new UnsupportedOperationException("Mapping Strategy does not support audits."); + } + + EresourcePackage resourcesPackage = EresourcePackage.eINSTANCE; + + // first query folders + boolean shallContinue = queryResources(dbStoreAccessor, getClassMapping(resourcesPackage.getCDOResourceFolder()), + context); + + // not enough results? -> query resources + if (shallContinue) + { + queryResources(dbStoreAccessor, getClassMapping(resourcesPackage.getCDOResource()), context); + } + } + + /** + * This is an intermediate implementation. It should be changed after classmappings support a general way to implement + * queries ... + * + * @param accessor + * the accessor to use. + * @param classMapping + * the class mapping of a class instanceof {@link CDOResourceNode} which should be queried. + * @param context + * the query context containing the parameters and the result. + * @return <code>true</code> if result context is not yet full and query should continue false, if result context is + * full and query should stop. + */ + private boolean queryResources(IDBStoreAccessor accessor, IClassMapping classMapping, QueryResourcesContext context) + { + PreparedStatement stmt = null; + ResultSet rset = null; + + CDOID folderID = context.getFolderID(); + String name = context.getName(); + boolean exactMatch = context.exactMatch(); + long timeStamp = context.getTimeStamp(); + + try + { + stmt = classMapping.createResourceQueryStatement(accessor, folderID, name, exactMatch, timeStamp); + rset = stmt.executeQuery(); + + while (rset.next()) + { + long longID = rset.getLong(1); + + if (TRACER.isEnabled()) + { + TRACER.format("Resource Query returned ID {0}", longID); + } + + CDOID id = CDOIDUtil.createLong(longID); + if (!context.addResource(id)) + { + // No more results allowed + return false; // don't continue + } + } + + return true; // continue with other results + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + DBUtil.close(rset); + accessor.getStatementCache().releasePreparedStatement(stmt); + } + } +} 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 new file mode 100644 index 0000000000..1c2509c51d --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AbstractListTableMapping.java @@ -0,0 +1,522 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 + * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 + */ +package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal; + +import org.eclipse.emf.cdo.common.revision.CDOList; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.server.IStoreChunkReader.Chunk; +import org.eclipse.emf.cdo.server.db.CDODBUtil; +import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; +import org.eclipse.emf.cdo.server.db.IDBStoreChunkReader; +import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability; +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.ITypeMapping; +import org.eclipse.emf.cdo.server.internal.db.CDODBSchema; +import org.eclipse.emf.cdo.server.internal.db.bundle.OM; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; + +import org.eclipse.net4j.db.DBException; +import org.eclipse.net4j.db.DBType; +import org.eclipse.net4j.db.DBUtil; +import org.eclipse.net4j.db.ddl.IDBField; +import org.eclipse.net4j.db.ddl.IDBTable; +import org.eclipse.net4j.db.ddl.IDBIndex.Type; +import org.eclipse.net4j.util.collection.MoveableList; +import org.eclipse.net4j.util.om.trace.ContextTracer; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +/** + * This abstract base class provides basic behavior needed for mapping many-valued attributes to tables. + * + * @author Eike Stepper + * @since 2.0 + */ +public abstract class AbstractListTableMapping implements IListMapping +{ + private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, AbstractListTableMapping.class); + + /** + * The feature for this mapping. + */ + private EStructuralFeature feature; + + /** + * The table of this mapping. + */ + private IDBTable table; + + /** + * The type mapping for the value field. + */ + private ITypeMapping typeMapping; + + /** + * The associated mapping strategy. + */ + private IMappingStrategy mappingStrategy; + + // --------- SQL strings - see initSqlStrings() ----------------- + private String sqlSelectChunksPrefix; + + private String sqlOrderByIndex; + + private String sqlInsertEntry; + + private EClass containingClass; + + private String sqlGetListLastIndex; + + public AbstractListTableMapping(IMappingStrategy mappingStrategy, EClass eClass, EStructuralFeature feature) + { + this.mappingStrategy = mappingStrategy; + this.feature = feature; + containingClass = eClass; + + initTable(); + initSqlStrings(); + } + + private void initTable() + { + String tableName = mappingStrategy.getTableName(containingClass, feature); + table = mappingStrategy.getStore().getDBSchema().addTable(tableName); + + // add fields for keys (cdo_id, version, feature_id) + FieldInfo[] fields = getKeyFields(); + IDBField[] dbFields = new IDBField[fields.length]; + + for (int i = 0; i < fields.length; i++) + { + dbFields[i] = table.addField(fields[i].getName(), fields[i].getDbType()); + } + + // add field for list index + IDBField idxField = table.addField(CDODBSchema.LIST_IDX, DBType.INTEGER); + + // add field for value + typeMapping = mappingStrategy.createValueMapping(feature); + typeMapping.createDBField(table, CDODBSchema.LIST_VALUE); + + // add table indexes + table.addIndex(Type.NON_UNIQUE, dbFields); + table.addIndex(Type.NON_UNIQUE, idxField); + } + + protected abstract FieldInfo[] getKeyFields(); + + protected abstract void setKeyFields(PreparedStatement stmt, CDORevision revision) throws SQLException; + + public Collection<IDBTable> getDBTables() + { + return Arrays.asList(table); + } + + private void initSqlStrings() + { + String tableName = getTable().getName(); + FieldInfo[] fields = getKeyFields(); + + // ---------------- SELECT to read chunks ---------------------------- + StringBuilder builder = new StringBuilder(); + builder.append("SELECT "); + builder.append(CDODBSchema.LIST_VALUE); + builder.append(" FROM "); + builder.append(tableName); + builder.append(" WHERE "); + + for (int i = 0; i < fields.length; i++) + { + builder.append(fields[i].getName()); + if (i + 1 < fields.length) + { + // more to come + builder.append("= ? AND "); + } + else + { + // last one + builder.append("= ? "); + } + } + + sqlSelectChunksPrefix = builder.toString(); + + sqlOrderByIndex = " ORDER BY " + CDODBSchema.LIST_IDX; + + // ----------------- count list size -------------------------- + + builder = new StringBuilder("SELECT max("); + builder.append(CDODBSchema.LIST_IDX); + builder.append(") FROM "); + builder.append(tableName); + builder.append(" WHERE "); + + for (int i = 0; i < fields.length; i++) + { + builder.append(fields[i].getName()); + if (i + 1 < fields.length) + { + // more to come + builder.append("= ? AND "); + } + else + { + // last one + builder.append("= ? "); + } + } + + sqlGetListLastIndex = builder.toString(); + + // ----------------- INSERT - reference entry ----------------- + builder = new StringBuilder("INSERT INTO "); + builder.append(tableName); + builder.append(" VALUES ("); + for (int i = 0; i < fields.length; i++) + { + builder.append("?, "); + } + builder.append(" ?, ?)"); + sqlInsertEntry = builder.toString(); + } + + public final EStructuralFeature getFeature() + { + return feature; + } + + public final EClass getContainingClass() + { + return containingClass; + } + + protected final IDBTable getTable() + { + return table; + } + + protected final ITypeMapping getTypeMapping() + { + return typeMapping; + } + + public void readValues(IDBStoreAccessor accessor, InternalCDORevision revision, int listChunk) + { + + MoveableList<Object> list = revision.getList(getFeature()); + int listSize = -1; + + if (listChunk != CDORevision.UNCHUNKED) + { + listSize = getListLastIndex(accessor, revision); + if (listSize == -1) + { + // list is empty - take shortcut + return; + } + else + { + // subtract amount of items we are going to read now + listSize -= listChunk; + } + } + + if (TRACER.isEnabled()) + { + TRACER.format("Reading list values for feature {0}.{1} of {2}v{3}", containingClass.getName(), feature.getName(), + revision.getID(), revision.getVersion()); + } + + PreparedStatement pstmt = null; + ResultSet resultSet = null; + + try + { + String sql = sqlSelectChunksPrefix + sqlOrderByIndex; + + pstmt = accessor.getStatementCache().getPreparedStatement(sql, ReuseProbability.HIGH); + + setKeyFields(pstmt, revision); + + if (TRACER.isEnabled()) + { + TRACER.trace(pstmt.toString()); + } + + if (listChunk != CDORevision.UNCHUNKED) + { + pstmt.setMaxRows(listChunk); // optimization - don't read unneeded rows. + } + + resultSet = pstmt.executeQuery(); + + while ((listChunk == CDORevision.UNCHUNKED || --listChunk >= 0) && resultSet.next()) + { + Object value = typeMapping.readValue(resultSet, 1); + if (TRACER.isEnabled()) + { + TRACER.format("Read value for index {0} from result set: {1}", list.size(), value); + } + list.add(value); + } + + while (listSize-- >= 0) + { + if (TRACER.isEnabled()) + { + TRACER.format("Adding UNINITIALIZED for index {0} ", list.size()); + } + list.add(InternalCDORevision.UNINITIALIZED); + } + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + DBUtil.close(resultSet); + accessor.getStatementCache().releasePreparedStatement(pstmt); + } + + if (TRACER.isEnabled()) + { + TRACER.format("Reading list values done for feature {0}.{1} of {2}v{3}", containingClass.getName(), feature + .getName(), revision.getID(), revision.getVersion()); + } + } + + /** + * Return the last (maximum) list index. (euals to size-1) + * + * @param accessor + * the accessor to use + * @param revision + * the revision to which the feature list belongs + * @return the last index or <code>-1</code> if the list is empty. + */ + private int getListLastIndex(IDBStoreAccessor accessor, InternalCDORevision revision) + { + PreparedStatement pstmt = null; + ResultSet resultSet = null; + + try + { + pstmt = accessor.getStatementCache().getPreparedStatement(sqlGetListLastIndex, ReuseProbability.HIGH); + + setKeyFields(pstmt, revision); + + if (TRACER.isEnabled()) + { + TRACER.trace(pstmt.toString()); + } + + resultSet = pstmt.executeQuery(); + + if (!resultSet.next()) + { + if (TRACER.isEnabled()) + { + TRACER.trace("No last index found -> list is empty. "); + } + return -1; + } + else + { + int result = resultSet.getInt(1); + if (TRACER.isEnabled()) + { + TRACER.trace("Read list last index = " + result); + } + return result; + } + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + DBUtil.close(resultSet); + accessor.getStatementCache().releasePreparedStatement(pstmt); + } + } + + public final void readChunks(IDBStoreChunkReader chunkReader, List<Chunk> chunks, String where) + { + if (TRACER.isEnabled()) + { + TRACER.format("Reading list chunk values for feature {0}.{1} of {2}v{3}", containingClass.getName(), feature + .getName(), chunkReader.getRevision().getID(), chunkReader.getRevision().getVersion()); + } + + PreparedStatement pstmt = null; + ResultSet resultSet = null; + + try + { + StringBuilder builder = new StringBuilder(sqlSelectChunksPrefix); + if (where != null) + { + builder.append(where); + } + builder.append(sqlOrderByIndex); + + String sql = builder.toString(); + + pstmt = chunkReader.getAccessor().getStatementCache().getPreparedStatement(sql, ReuseProbability.LOW); + + setKeyFields(pstmt, chunkReader.getRevision()); + + if (TRACER.isEnabled()) + { + TRACER.trace(pstmt.toString()); + } + + resultSet = pstmt.executeQuery(); + + Chunk chunk = null; + int chunkSize = 0; + int chunkIndex = 0; + int indexInChunk = 0; + + while (resultSet.next()) + { + Object value = typeMapping.readValue(resultSet, 1); + + if (chunk == null) + { + chunk = chunks.get(chunkIndex++); + chunkSize = chunk.size(); + + if (TRACER.isEnabled()) + { + TRACER.format("Current chunk no. {0} is [start = {1}, size = {2}]", chunkIndex - 1, chunk.getStartIndex(), + chunkSize); + } + } + + if (TRACER.isEnabled()) + { + TRACER.format("Read value for chunk index {0} from result set: {1}", indexInChunk, value); + } + chunk.add(indexInChunk++, value); + + if (indexInChunk == chunkSize) + { + if (TRACER.isEnabled()) + { + TRACER.format("Chunk finished."); + } + + chunk = null; + indexInChunk = 0; + } + } + + if (TRACER.isEnabled()) + { + TRACER.format("Reading list chunk values done for feature {0}.{1} of {2}v{3}", containingClass.getName(), + feature.getName(), chunkReader.getRevision().getID(), chunkReader.getRevision().getVersion()); + } + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + DBUtil.close(resultSet); + chunkReader.getAccessor().getStatementCache().releasePreparedStatement(pstmt); + } + } + + public void writeValues(IDBStoreAccessor accessor, InternalCDORevision revision) + { + CDOList values = revision.getList(getFeature()); + + int idx = 0; + for (Object element : values) + { + writeValue(accessor, revision, idx++, element); + } + } + + protected final void writeValue(IDBStoreAccessor accessor, CDORevision revision, int idx, Object value) + { + PreparedStatement stmt = null; + + if (TRACER.isEnabled()) + { + TRACER.format("Writing value for feature {0}.{1} index {2} of {3}v{4} : {5}", containingClass.getName(), feature + .getName(), idx, revision.getID(), revision.getVersion(), value); + } + + try + { + stmt = accessor.getStatementCache().getPreparedStatement(sqlInsertEntry, ReuseProbability.HIGH); + + setKeyFields(stmt, revision); + int stmtIndex = getKeyFields().length + 1; + stmt.setInt(stmtIndex++, idx); + typeMapping.setValue(stmt, stmtIndex++, value); + + CDODBUtil.sqlUpdate(stmt, true); + } + catch (SQLException e) + { + throw new DBException(e); + } + finally + { + accessor.getStatementCache().releasePreparedStatement(stmt); + } + } + + /** + * Used by subclasses to indicate which fields should be in the table. I.e. just a pair of name and DBType ... + * + * @author Stefan Winkler + */ + protected static class FieldInfo + { + private String name; + + private DBType dbType; + + public FieldInfo(String name, DBType dbType) + { + this.name = name; + this.dbType = dbType; + } + + public String getName() + { + return name; + } + + public DBType getDbType() + { + return dbType; + } + } +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditListTableMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditListTableMapping.java new file mode 100644 index 0000000000..d3a3d4cd7d --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/AuditListTableMapping.java @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 + * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 + */ +package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal; + +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDUtil; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; +import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; +import org.eclipse.emf.cdo.server.internal.db.CDODBSchema; + +import org.eclipse.net4j.db.DBType; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; + +import java.sql.PreparedStatement; +import java.sql.SQLException; + +/** + * This is a list-table mapping for audit mode. It has ID and version columns and no delta support. + * + * @author Eike Stepper + * @since 2.0 + */ +public class AuditListTableMapping extends AbstractListTableMapping +{ + private static final FieldInfo[] KEY_FIELDS = { new FieldInfo(CDODBSchema.LIST_REVISION_ID, DBType.BIGINT), + new FieldInfo(CDODBSchema.LIST_REVISION_VERSION, DBType.INTEGER) }; + + public AuditListTableMapping(IMappingStrategy mappingStrategy, EClass eClass, EStructuralFeature feature) + { + super(mappingStrategy, eClass, feature); + } + + @Override + protected FieldInfo[] getKeyFields() + { + return KEY_FIELDS; + } + + @Override + protected void setKeyFields(PreparedStatement stmt, CDORevision revision) throws SQLException + { + stmt.setLong(1, CDOIDUtil.getLong(revision.getID())); + stmt.setInt(2, revision.getVersion()); + } + + public void objectRevised(IDBStoreAccessor accessor, CDOID id, long revised) + { + // the audit list mapping does not care about revised references -> NOP + } +} 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 new file mode 100644 index 0000000000..32b0d58c27 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditClassMapping.java @@ -0,0 +1,401 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 + * Stefan Winkler - major refactoring + */ +package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal; + +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDUtil; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.eresource.EresourcePackage; +import org.eclipse.emf.cdo.server.db.CDODBUtil; +import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; +import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability; +import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; +import org.eclipse.emf.cdo.server.db.mapping.IClassMappingAuditSupport; +import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping; +import org.eclipse.emf.cdo.server.internal.db.CDODBSchema; +import org.eclipse.emf.cdo.server.internal.db.bundle.OM; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; + +import org.eclipse.net4j.db.DBException; +import org.eclipse.net4j.util.ImplementationError; +import org.eclipse.net4j.util.om.trace.ContextTracer; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; + +import java.sql.PreparedStatement; +import java.sql.SQLException; + +/** + * TODO use async monitors + * + * @author Eike Stepper + * @since 2.0 + */ +public class HorizontalAuditClassMapping extends AbstractHorizontalClassMapping implements IClassMapping, + IClassMappingAuditSupport +{ + private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, HorizontalAuditClassMapping.class); + + private String sqlInsertAttributes; + + private String sqlSelectCurrentAttributes; + + private String sqlSelectAllObjectIds; + + private String sqlSelectAttributesByTime; + + private String sqlSelectAttributesByVersion; + + private String sqlReviseAttributes; + + public HorizontalAuditClassMapping(AbstractHorizontalMappingStrategy mappingStrategy, EClass eClass) + { + super(mappingStrategy, eClass); + + initSqlStrings(); + } + + private void initSqlStrings() + { + // ----------- Select Revision --------------------------- + StringBuilder builder = new StringBuilder(); + + builder.append("SELECT "); + builder.append(CDODBSchema.ATTRIBUTES_VERSION); + builder.append(", "); + builder.append(CDODBSchema.ATTRIBUTES_CREATED); + builder.append(", "); + builder.append(CDODBSchema.ATTRIBUTES_REVISED); + builder.append(", "); + builder.append(CDODBSchema.ATTRIBUTES_RESOURCE); + builder.append(", "); + builder.append(CDODBSchema.ATTRIBUTES_CONTAINER); + builder.append(", "); + builder.append(CDODBSchema.ATTRIBUTES_FEATURE); + + for (ITypeMapping singleMapping : getValueMappings()) + { + builder.append(", "); + builder.append(singleMapping.getField().getName()); + } + + builder.append(" FROM "); + builder.append(getTable().getName()); + builder.append(" WHERE "); + builder.append(CDODBSchema.ATTRIBUTES_ID); + builder.append("= ? AND ("); + + String sqlSelectAttributesPrefix = builder.toString(); + + builder.append(CDODBSchema.ATTRIBUTES_REVISED); + builder.append(" = 0 )"); + + sqlSelectCurrentAttributes = builder.toString(); + + builder = new StringBuilder(sqlSelectAttributesPrefix); + + builder.append(CDODBSchema.ATTRIBUTES_CREATED); + builder.append(" <= ? AND ( "); + builder.append(CDODBSchema.ATTRIBUTES_REVISED); + builder.append(" = 0 OR "); + builder.append(CDODBSchema.ATTRIBUTES_REVISED); + builder.append(" >= ?))"); + + sqlSelectAttributesByTime = builder.toString(); + + builder = new StringBuilder(sqlSelectAttributesPrefix); + + builder.append(CDODBSchema.ATTRIBUTES_VERSION); + builder.append(" = ?)"); + + sqlSelectAttributesByVersion = builder.toString(); + + // ----------- Insert Attributes ------------------------- + builder = new StringBuilder(); + builder.append("INSERT INTO "); + builder.append(getTable().getName()); + builder.append(" VALUES (?, ?, "); + builder.append("?, ?, ?, ?, ?, ?"); + for (int i = 0; i < getValueMappings().size(); i++) + { + builder.append(", ?"); + } + builder.append(")"); + sqlInsertAttributes = builder.toString(); + + // ----------- Update to set revised ---------------- + builder = new StringBuilder("UPDATE "); + builder.append(getTable().getName()); + builder.append(" SET "); + builder.append(CDODBSchema.ATTRIBUTES_REVISED); + builder.append(" = ? WHERE "); + builder.append(CDODBSchema.ATTRIBUTES_ID); + builder.append(" = ? AND "); + builder.append(CDODBSchema.ATTRIBUTES_REVISED); + builder.append(" = 0"); + sqlReviseAttributes = builder.toString(); + + // ----------- Select all unrevised Object IDs ------ + builder = new StringBuilder("SELECT "); + builder.append(CDODBSchema.ATTRIBUTES_ID); + builder.append(" FROM "); + builder.append(getTable().getName()); + builder.append(" WHERE "); + builder.append(CDODBSchema.ATTRIBUTES_REVISED); + builder.append(" = 0"); + sqlSelectAllObjectIds = builder.toString(); + } + + public boolean readRevisionByTime(IDBStoreAccessor accessor, InternalCDORevision revision, long timeStamp, + int listChunk) + { + PreparedStatement pstmt = null; + try + { + pstmt = accessor.getStatementCache().getPreparedStatement(sqlSelectAttributesByTime, ReuseProbability.MEDIUM); + pstmt.setLong(1, CDOIDUtil.getLong(revision.getID())); + pstmt.setLong(2, timeStamp); + pstmt.setLong(3, timeStamp); + + // Read singleval-attribute table always (even without modeled attributes!) + boolean success = readValuesFromStatement(pstmt, revision); + + // Read multival tables only if revision exists + if (success) + { + readLists(accessor, revision, listChunk); + } + + return success; + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + accessor.getStatementCache().releasePreparedStatement(pstmt); + } + } + + public boolean readRevisionByVersion(IDBStoreAccessor accessor, InternalCDORevision revision, int version, + int listChunk) + { + PreparedStatement pstmt = null; + try + { + pstmt = accessor.getStatementCache().getPreparedStatement(sqlSelectAttributesByVersion, ReuseProbability.HIGH); + pstmt.setLong(1, CDOIDUtil.getLong(revision.getID())); + pstmt.setInt(2, version); + + // Read singleval-attribute table always (even without modeled attributes!) + boolean success = readValuesFromStatement(pstmt, revision); + + // Read multival tables only if revision exists + if (success) + { + readLists(accessor, revision, listChunk); + } + + return success; + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + accessor.getStatementCache().releasePreparedStatement(pstmt); + } + } + + public PreparedStatement createResourceQueryStatement(IDBStoreAccessor accessor, CDOID folderId, String name, + boolean exactMatch, long timeStamp) + { + EStructuralFeature nameFeature = EresourcePackage.eINSTANCE.getCDOResourceNode_Name(); + + ITypeMapping nameValueMapping = getValueMapping(nameFeature); + if (nameValueMapping == null) + { + throw new ImplementationError(nameFeature + " not found in ClassMapping " + this); + } + + StringBuilder builder = new StringBuilder(); + builder.append("SELECT "); + builder.append(CDODBSchema.ATTRIBUTES_ID); + builder.append(" FROM "); + builder.append(getTable().getName()); + builder.append(" WHERE "); + builder.append(CDODBSchema.ATTRIBUTES_CONTAINER); + builder.append("= ? AND "); + builder.append(nameValueMapping.getField().getName()); + if (name == null) + { + builder.append(" IS NULL"); + } + else + { + builder.append(exactMatch ? " = ? " : " LIKE ? "); + } + + builder.append(" AND ( "); + + if (timeStamp == CDORevision.UNSPECIFIED_DATE) + { + builder.append(CDODBSchema.ATTRIBUTES_REVISED); + builder.append(" = 0 )"); + } + else + { + builder.append(CDODBSchema.ATTRIBUTES_CREATED); + builder.append(" <= ? AND ( "); + builder.append(CDODBSchema.ATTRIBUTES_REVISED); + builder.append(" = 0 OR "); + builder.append(CDODBSchema.ATTRIBUTES_REVISED); + builder.append(" >= ?))"); + } + + PreparedStatement pstmt = null; + try + { + int idx = 1; + + pstmt = accessor.getStatementCache().getPreparedStatement(builder.toString(), ReuseProbability.MEDIUM); + pstmt.setLong(idx++, CDOIDUtil.getLong(folderId)); + + if (name != null) + { + String queryName = exactMatch ? name : name + "%"; + nameValueMapping.setValue(pstmt, idx++, queryName); + } + + if (timeStamp != CDORevision.UNSPECIFIED_DATE) + { + pstmt.setLong(idx++, timeStamp); + pstmt.setLong(idx++, timeStamp); + } + + if (TRACER.isEnabled()) + { + TRACER.format("Created Resource Query: {0}", pstmt.toString()); + } + + return pstmt; + } + catch (SQLException ex) + { + accessor.getStatementCache().releasePreparedStatement(pstmt); // only release on error + throw new DBException(ex); + } + } + + public PreparedStatement createObjectIdStatement(IDBStoreAccessor accessor) + { + if (TRACER.isEnabled()) + { + TRACER.format("Created ObjectID Statement : {0}", sqlSelectAllObjectIds); + } + + return accessor.getStatementCache().getPreparedStatement(sqlSelectAllObjectIds, ReuseProbability.HIGH); + } + + public boolean readRevision(IDBStoreAccessor accessor, InternalCDORevision revision, int listChunk) + { + PreparedStatement pstmt = null; + try + { + pstmt = accessor.getStatementCache().getPreparedStatement(sqlSelectCurrentAttributes, ReuseProbability.HIGH); + pstmt.setLong(1, CDOIDUtil.getLong(revision.getID())); + + // Read singleval-attribute table always (even without modeled attributes!) + boolean success = readValuesFromStatement(pstmt, revision); + + // Read multival tables only if revision exists + if (success) + { + readLists(accessor, revision, listChunk); + } + + return success; + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + accessor.getStatementCache().releasePreparedStatement(pstmt); + } + } + + @Override + protected final void writeValues(IDBStoreAccessor accessor, InternalCDORevision revision) + { + PreparedStatement stmt = null; + + try + { + stmt = accessor.getStatementCache().getPreparedStatement(sqlInsertAttributes, ReuseProbability.HIGH); + + int col = 1; + + stmt.setLong(col++, CDOIDUtil.getLong(revision.getID())); + stmt.setInt(col++, revision.getVersion()); + stmt.setLong(col++, accessor.getStore().getMetaDataManager().getMetaID(revision.getEClass())); + stmt.setLong(col++, revision.getCreated()); + stmt.setLong(col++, revision.getRevised()); + stmt.setLong(col++, CDOIDUtil.getLong(revision.getResourceID())); + stmt.setLong(col++, CDODBUtil.getLong((CDOID)revision.getContainerID())); + stmt.setInt(col++, revision.getContainingFeatureID()); + + for (ITypeMapping mapping : getValueMappings()) + { + mapping.setValueFromRevision(stmt, col++, revision); + } + + CDODBUtil.sqlUpdate(stmt, true); + } + catch (SQLException e) + { + throw new DBException(e); + } + finally + { + accessor.getStatementCache().releasePreparedStatement(stmt); + } + } + + @Override + protected void reviseObject(IDBStoreAccessor accessor, CDOID id, long revised) + { + PreparedStatement stmt = null; + + try + { + stmt = accessor.getStatementCache().getPreparedStatement(sqlReviseAttributes, ReuseProbability.HIGH); + + stmt.setLong(1, revised); + stmt.setLong(2, CDOIDUtil.getLong(id)); + + CDODBUtil.sqlUpdate(stmt, true); + } + catch (SQLException e) + { + throw new DBException(e); + } + finally + { + accessor.getStatementCache().releasePreparedStatement(stmt); + } + } +} 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 new file mode 100644 index 0000000000..d062dd0c82 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalAuditMappingStrategy.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 + * Stefan Winkler - major refactoring + */ +package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal; + +import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; +import org.eclipse.emf.cdo.server.db.mapping.IListMapping; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; + +/** + * @author Eike Stepper + * @since 2.0 + */ +public class HorizontalAuditMappingStrategy extends AbstractHorizontalMappingStrategy +{ + @Override + public IClassMapping doCreateClassMapping(EClass eClass) + { + return new HorizontalAuditClassMapping(this, eClass); + } + + @Override + public IListMapping doCreateListMapping(EClass containingClass, EStructuralFeature feature) + { + return new AuditListTableMapping(this, containingClass, feature); + } + + @Override + public boolean hasAuditSupport() + { + return true; + } + + @Override + public boolean hasDeltaSupport() + { + return false; + } +} 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 new file mode 100644 index 0000000000..ed68197eb7 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalNonAuditClassMapping.java @@ -0,0 +1,563 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 + * Stefan Winkler - major refactoring + */ +package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal; + +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDUtil; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.delta.CDOAddFeatureDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDOClearFeatureDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDOContainerFeatureDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDeltaVisitor; +import org.eclipse.emf.cdo.common.revision.delta.CDOListFeatureDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDOMoveFeatureDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDORemoveFeatureDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDOSetFeatureDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDOUnsetFeatureDelta; +import org.eclipse.emf.cdo.eresource.EresourcePackage; +import org.eclipse.emf.cdo.server.db.CDODBUtil; +import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; +import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability; +import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; +import org.eclipse.emf.cdo.server.db.mapping.IClassMappingDeltaSupport; +import org.eclipse.emf.cdo.server.db.mapping.IListMappingDeltaSupport; +import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping; +import org.eclipse.emf.cdo.server.internal.db.CDODBSchema; +import org.eclipse.emf.cdo.server.internal.db.bundle.OM; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; +import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta; + +import org.eclipse.net4j.db.DBException; +import org.eclipse.net4j.util.ImplementationError; +import org.eclipse.net4j.util.collection.Pair; +import org.eclipse.net4j.util.om.monitor.OMMonitor; +import org.eclipse.net4j.util.om.monitor.OMMonitor.Async; +import org.eclipse.net4j.util.om.trace.ContextTracer; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Eike Stepper + * @since 2.0 + */ +public class HorizontalNonAuditClassMapping extends AbstractHorizontalClassMapping implements IClassMapping, + IClassMappingDeltaSupport +{ + private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, HorizontalNonAuditClassMapping.class); + + private String sqlSelectAllObjectIds; + + private String sqlSelectCurrentAttributes; + + private String sqlInsertAttributes; + + private String sqlDelete; + + private String sqlUpdateAffix; + + private String sqlUpdatePrexix; + + private String sqlUpdateContainerPart; + + private ThreadLocal<FeatureDeltaWriter> deltaWriter = new ThreadLocal<FeatureDeltaWriter>() + { + @Override + protected FeatureDeltaWriter initialValue() + { + return new FeatureDeltaWriter(); + }; + }; + + public HorizontalNonAuditClassMapping(AbstractHorizontalMappingStrategy mappingStrategy, EClass eClass) + { + super(mappingStrategy, eClass); + + initSqlStrings(); + } + + private void initSqlStrings() + { + // ----------- Select Revision --------------------------- + StringBuilder builder = new StringBuilder(); + + builder.append("SELECT "); + builder.append(CDODBSchema.ATTRIBUTES_VERSION); + builder.append(", "); + builder.append(CDODBSchema.ATTRIBUTES_CREATED); + builder.append(", "); + builder.append(CDODBSchema.ATTRIBUTES_REVISED); + builder.append(", "); + builder.append(CDODBSchema.ATTRIBUTES_RESOURCE); + builder.append(", "); + builder.append(CDODBSchema.ATTRIBUTES_CONTAINER); + builder.append(", "); + builder.append(CDODBSchema.ATTRIBUTES_FEATURE); + + for (ITypeMapping singleMapping : getValueMappings()) + { + builder.append(", "); + builder.append(singleMapping.getField().getName()); + } + + builder.append(" FROM "); + builder.append(getTable().getName()); + builder.append(" WHERE "); + builder.append(CDODBSchema.ATTRIBUTES_ID); + builder.append("= ?"); + + sqlSelectCurrentAttributes = builder.toString(); + + // ----------- Insert Attributes ------------------------- + builder = new StringBuilder(); + builder.append("INSERT INTO "); + builder.append(getTable().getName()); + builder.append(" VALUES (?, ?, "); + builder.append("?, ?, ?, ?, ?, ?"); + for (int i = 0; i < getValueMappings().size(); i++) + { + builder.append(", ?"); + } + builder.append(")"); + sqlInsertAttributes = builder.toString(); + + builder = new StringBuilder("DELETE FROM "); + builder.append(getTable().getName()); + builder.append(" WHERE "); + builder.append(CDODBSchema.ATTRIBUTES_ID); + builder.append(" = ? "); + sqlDelete = builder.toString(); + + // ----------- Select all unrevised Object IDs ------ + builder = new StringBuilder("SELECT "); + builder.append(CDODBSchema.ATTRIBUTES_ID); + builder.append(" FROM "); + builder.append(getTable().getName()); + sqlSelectAllObjectIds = builder.toString(); + + // ----------- Update attributes -------------------- + builder = new StringBuilder("UPDATE "); + builder.append(getTable().getName()); + builder.append(" SET "); + builder.append(CDODBSchema.ATTRIBUTES_VERSION); + builder.append(" =? ,"); + builder.append(CDODBSchema.ATTRIBUTES_CREATED); + builder.append(" =? "); + sqlUpdatePrexix = builder.toString(); + + builder = new StringBuilder(", "); + builder.append(CDODBSchema.ATTRIBUTES_RESOURCE); + builder.append(" =? ,"); + builder.append(CDODBSchema.ATTRIBUTES_CONTAINER); + builder.append(" =? ,"); + builder.append(CDODBSchema.ATTRIBUTES_FEATURE); + builder.append(" =? "); + sqlUpdateContainerPart = builder.toString(); + + builder = new StringBuilder(" WHERE "); + builder.append(CDODBSchema.ATTRIBUTES_ID); + builder.append(" = ? "); + sqlUpdateAffix = builder.toString(); + } + + @Override + protected void writeValues(IDBStoreAccessor accessor, InternalCDORevision revision) + { + PreparedStatement stmt = null; + + try + { + stmt = accessor.getStatementCache().getPreparedStatement(sqlInsertAttributes, ReuseProbability.HIGH); + + int col = 1; + + stmt.setLong(col++, CDOIDUtil.getLong(revision.getID())); + stmt.setInt(col++, revision.getVersion()); + stmt.setLong(col++, accessor.getStore().getMetaDataManager().getMetaID(revision.getEClass())); + stmt.setLong(col++, revision.getCreated()); + stmt.setLong(col++, revision.getRevised()); + stmt.setLong(col++, CDOIDUtil.getLong(revision.getResourceID())); + stmt.setLong(col++, CDODBUtil.getLong((CDOID)revision.getContainerID())); + stmt.setInt(col++, revision.getContainingFeatureID()); + + for (ITypeMapping mapping : getValueMappings()) + { + mapping.setValueFromRevision(stmt, col++, revision); + } + + CDODBUtil.sqlUpdate(stmt, true); + } + catch (SQLException e) + { + throw new DBException(e); + } + finally + { + accessor.getStatementCache().releasePreparedStatement(stmt); + } + } + + public PreparedStatement createObjectIdStatement(IDBStoreAccessor accessor) + { + if (TRACER.isEnabled()) + { + TRACER.format("Created ObjectID Statement : {0}", sqlSelectAllObjectIds); + } + + return accessor.getStatementCache().getPreparedStatement(sqlSelectAllObjectIds, ReuseProbability.HIGH); + } + + public PreparedStatement createResourceQueryStatement(IDBStoreAccessor accessor, CDOID folderId, String name, + boolean exactMatch, long timeStamp) + { + if (timeStamp != CDORevision.UNSPECIFIED_DATE) + { + throw new IllegalArgumentException("Non-audit store does not support explicit timeStamp in resource query"); + } + + EStructuralFeature nameFeature = EresourcePackage.eINSTANCE.getCDOResourceNode_Name(); + + ITypeMapping nameValueMapping = getValueMapping(nameFeature); + if (nameValueMapping == null) + { + throw new ImplementationError(nameFeature + " not found in ClassMapping " + this); + } + + StringBuilder builder = new StringBuilder(); + builder.append("SELECT "); + builder.append(CDODBSchema.ATTRIBUTES_ID); + builder.append(" FROM "); + builder.append(getTable().getName()); + builder.append(" WHERE "); + builder.append(CDODBSchema.ATTRIBUTES_CONTAINER); + builder.append("= ? AND "); + builder.append(nameValueMapping.getField().getName()); + if (name == null) + { + builder.append(" IS NULL"); + } + else + { + builder.append(exactMatch ? " = ? " : " LIKE ? "); + } + + PreparedStatement pstmt = null; + try + { + int idx = 1; + + pstmt = accessor.getStatementCache().getPreparedStatement(builder.toString(), ReuseProbability.MEDIUM); + pstmt.setLong(idx++, CDOIDUtil.getLong(folderId)); + + if (name != null) + { + String queryName = exactMatch ? name : name + "%"; + nameValueMapping.setValue(pstmt, idx++, queryName); + } + + if (TRACER.isEnabled()) + { + TRACER.format("Created Resource Query: {0}", pstmt.toString()); + } + + return pstmt; + } + catch (SQLException ex) + { + accessor.getStatementCache().releasePreparedStatement(pstmt); // only release on error + throw new DBException(ex); + } + } + + public boolean readRevision(IDBStoreAccessor accessor, InternalCDORevision revision, int listChunk) + { + PreparedStatement pstmt = null; + try + { + // TODO add caching + pstmt = accessor.getStatementCache().getPreparedStatement(sqlSelectCurrentAttributes, ReuseProbability.HIGH); + pstmt.setLong(1, CDOIDUtil.getLong(revision.getID())); + + // Read singleval-attribute table always (even without modeled attributes!) + boolean success = readValuesFromStatement(pstmt, revision); + + // Read multival tables only if revision exists + if (success) + { + readLists(accessor, revision, listChunk); + } + + return success; + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + accessor.getStatementCache().releasePreparedStatement(pstmt); + } + } + + @Override + protected void reviseObject(IDBStoreAccessor accessor, CDOID id, long revised) + { + PreparedStatement stmt = null; + + try + { + stmt = accessor.getStatementCache().getPreparedStatement(sqlDelete, ReuseProbability.HIGH); + stmt.setLong(1, CDOIDUtil.getLong(id)); + CDODBUtil.sqlUpdate(stmt, true); + } + catch (SQLException e) + { + throw new DBException(e); + } + finally + { + accessor.getStatementCache().releasePreparedStatement(stmt); + } + } + + public void writeRevisionDelta(IDBStoreAccessor accessor, InternalCDORevisionDelta delta, long created, + OMMonitor monitor) + { + monitor.begin(); + Async async = monitor.forkAsync(); + + try + { + FeatureDeltaWriter writer = deltaWriter.get(); + writer.process(accessor, delta, created); + } + finally + { + async.stop(); + monitor.done(); + } + } + + private class FeatureDeltaWriter implements CDOFeatureDeltaVisitor + { + private CDOID id; + + private int oldVersion; + + private int newVersion; + + private long created; + + private IDBStoreAccessor accessor; + + private boolean updateContainer = false; + + private List<Pair<ITypeMapping, Object>> attributeChanges; + + private int newContainingFeatureID; + + private CDOID newContainerID; + + private CDOID newResourceID; + + public FeatureDeltaWriter() + { + attributeChanges = new ArrayList<Pair<ITypeMapping, Object>>(); + } + + protected void reset() + { + attributeChanges.clear(); + updateContainer = false; + } + + public void process(IDBStoreAccessor a, CDORevisionDelta d, long c) + { + // set context + + reset(); + id = d.getID(); + oldVersion = d.getOriginVersion(); + newVersion = d.getDirtyVersion(); + created = c; + accessor = a; + + // process revision delta tree + d.accept(this); + + // update attributes + if (updateContainer) + { + updateAttributes(accessor, id, newVersion, created, newContainerID, newContainingFeatureID, newResourceID, + attributeChanges); + } + else + { + updateAttributes(accessor, id, newVersion, created, attributeChanges); + } + } + + public void visit(CDOMoveFeatureDelta delta) + { + throw new ImplementationError("Should not be called"); + } + + public void visit(CDOSetFeatureDelta delta) + { + if (delta.getFeature().isMany()) + { + throw new ImplementationError("Should not be called"); + } + ITypeMapping am = getValueMapping(delta.getFeature()); + if (am == null) + { + throw new IllegalArgumentException("AttributeMapping for " + delta.getFeature() + " is null!"); + } + attributeChanges.add(new Pair<ITypeMapping, Object>(am, delta.getValue())); + + } + + public void visit(CDOUnsetFeatureDelta delta) + { + // TODO: correct this when DBStore implements unsettable features + // see Bugs 259868 and 263010 + ITypeMapping tm = getValueMapping(delta.getFeature()); + attributeChanges.add(new Pair<ITypeMapping, Object>(tm, null)); + } + + public void visit(CDOListFeatureDelta delta) + { + IListMappingDeltaSupport listMapping = (IListMappingDeltaSupport)getListMapping(delta.getFeature()); + listMapping.processDelta(accessor, id, oldVersion, newVersion, created, delta); + } + + public void visit(CDOClearFeatureDelta delta) + { + throw new ImplementationError("Should not be called"); + } + + public void visit(CDOAddFeatureDelta delta) + { + throw new ImplementationError("Should not be called"); + } + + public void visit(CDORemoveFeatureDelta delta) + { + throw new ImplementationError("Should not be called"); + } + + public void visit(CDOContainerFeatureDelta delta) + { + newContainingFeatureID = delta.getContainerFeatureID(); + newContainerID = (CDOID)delta.getContainerID(); + newResourceID = delta.getResourceID(); + updateContainer = true; + } + } + + public void updateAttributes(IDBStoreAccessor accessor, CDOID id, int newVersion, long created, CDOID newContainerId, + int newContainingFeatureId, CDOID newResourceId, List<Pair<ITypeMapping, Object>> attributeChanges) + { + PreparedStatement stmt = null; + + try + { + stmt = accessor.getStatementCache().getPreparedStatement(buildUpdateStatement(attributeChanges, true), + ReuseProbability.MEDIUM); + + int col = 1; + + stmt.setInt(col++, newVersion); + stmt.setLong(col++, created); + stmt.setLong(col++, CDODBUtil.getLong(newResourceId)); + stmt.setLong(col++, CDODBUtil.getLong(newContainerId)); + stmt.setInt(col++, newContainingFeatureId); + + for (Pair<ITypeMapping, Object> change : attributeChanges) + { + change.getElement1().setValue(stmt, col++, change.getElement2()); + } + + stmt.setLong(col++, CDOIDUtil.getLong(id)); + + CDODBUtil.sqlUpdate(stmt, true); + } + catch (SQLException e) + { + throw new DBException(e); + } + finally + { + accessor.getStatementCache().releasePreparedStatement(stmt); + } + + } + + public void updateAttributes(IDBStoreAccessor accessor, CDOID id, int newVersion, long created, + List<Pair<ITypeMapping, Object>> attributeChanges) + { + PreparedStatement stmt = null; + + try + { + stmt = accessor.getStatementCache().getPreparedStatement(buildUpdateStatement(attributeChanges, false), + ReuseProbability.MEDIUM); + + int col = 1; + + stmt.setInt(col++, newVersion); + stmt.setLong(col++, created); + + for (Pair<ITypeMapping, Object> change : attributeChanges) + { + change.getElement1().setValue(stmt, col++, change.getElement2()); + } + + stmt.setLong(col++, CDOIDUtil.getLong(id)); + + CDODBUtil.sqlUpdate(stmt, true); + } + catch (SQLException e) + { + throw new DBException(e); + } + finally + { + accessor.getStatementCache().releasePreparedStatement(stmt); + } + } + + private String buildUpdateStatement(List<Pair<ITypeMapping, Object>> attributeChanges, boolean withContainment) + { + StringBuilder builder = new StringBuilder(sqlUpdatePrexix); + if (withContainment) + { + builder.append(sqlUpdateContainerPart); + } + + for (Pair<ITypeMapping, Object> change : attributeChanges) + { + builder.append(", "); + builder.append(change.getElement1().getField().getName()); + builder.append(" =? "); + } + + builder.append(sqlUpdateAffix); + return builder.toString(); + } +} 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 new file mode 100644 index 0000000000..8543cb59a1 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/HorizontalNonAuditMappingStrategy.java @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 + * Stefan Winkler - major refactoring + */ +package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal; + +import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; +import org.eclipse.emf.cdo.server.db.mapping.IListMapping; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; + +/** + * @author Eike Stepper + * @since 2.0 + */ +public class HorizontalNonAuditMappingStrategy extends AbstractHorizontalMappingStrategy +{ + + @Override + protected IClassMapping doCreateClassMapping(EClass eClass) + { + return new HorizontalNonAuditClassMapping(this, eClass); + } + + @Override + public IListMapping doCreateListMapping(EClass containingClass, EStructuralFeature feature) + { + return new NonAuditListTableMapping(this, containingClass, feature); + } + + @Override + public boolean hasAuditSupport() + { + return false; + } + + @Override + public boolean hasDeltaSupport() + { + return true; + } +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/NonAuditListTableMapping.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/NonAuditListTableMapping.java new file mode 100644 index 0000000000..6aaac67414 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/NonAuditListTableMapping.java @@ -0,0 +1,514 @@ +/** + * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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 + * Stefan Winkler - 271444: [DB] Multiple refactorings https://bugs.eclipse.org/bugs/show_bug.cgi?id=271444 + */ +package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal; + +import org.eclipse.emf.cdo.common.id.CDOID; +import org.eclipse.emf.cdo.common.id.CDOIDUtil; +import org.eclipse.emf.cdo.common.revision.CDORevision; +import org.eclipse.emf.cdo.common.revision.delta.CDOAddFeatureDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDOClearFeatureDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDOContainerFeatureDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDeltaVisitor; +import org.eclipse.emf.cdo.common.revision.delta.CDOListFeatureDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDOMoveFeatureDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDORemoveFeatureDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDOSetFeatureDelta; +import org.eclipse.emf.cdo.common.revision.delta.CDOUnsetFeatureDelta; +import org.eclipse.emf.cdo.server.db.CDODBUtil; +import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; +import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability; +import org.eclipse.emf.cdo.server.db.mapping.IListMapping; +import org.eclipse.emf.cdo.server.db.mapping.IListMappingDeltaSupport; +import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; +import org.eclipse.emf.cdo.server.internal.db.CDODBSchema; + +import org.eclipse.net4j.db.DBException; +import org.eclipse.net4j.db.DBType; +import org.eclipse.net4j.util.ImplementationError; + +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EStructuralFeature; + +import java.sql.PreparedStatement; +import java.sql.SQLException; + +/** + * This is a list-to-table mapping optimized for non-audit-mode. It doesn't care about version and has delta support. + * + * @author Eike Stepper + * @since 2.0 + */ +public class NonAuditListTableMapping extends AbstractListTableMapping implements IListMapping, + IListMappingDeltaSupport +{ + private static final FieldInfo[] KEY_FIELDS = { new FieldInfo(CDODBSchema.LIST_REVISION_ID, DBType.BIGINT) }; + + private static final int TEMP_INDEX = -1; + + private static final int UNBOUNDED_MOVE = -1; + + private String sqlClear; + + private String sqlUpdateValue; + + private String sqlUpdateIndex; + + private String sqlInsertValue; + + private String sqlDeleteItem; + + private String sqlMoveDownWithLimit; + + private String sqlMoveDown; + + private String sqlMoveUpWithLimit; + + private String sqlMoveUp; + + public NonAuditListTableMapping(IMappingStrategy mappingStrategy, EClass eClass, EStructuralFeature feature) + { + super(mappingStrategy, eClass, feature); + + initSqlStrings(); + } + + private void initSqlStrings() + { + // ----------- clear list ------------------------- + StringBuilder builder = new StringBuilder(); + + builder.append("DELETE FROM "); + builder.append(getTable().getName()); + builder.append(" WHERE "); + builder.append(CDODBSchema.LIST_REVISION_ID); + builder.append(" = ? "); + + sqlClear = builder.toString(); + + builder.append(" AND "); + builder.append(CDODBSchema.LIST_IDX); + builder.append(" = ? "); + + sqlDeleteItem = builder.toString(); + + // ----------- update one item -------------------- + builder = new StringBuilder(); + builder.append("UPDATE "); + builder.append(getTable().getName()); + builder.append(" SET "); + builder.append(CDODBSchema.LIST_VALUE); + builder.append(" = ? "); + builder.append(" WHERE "); + builder.append(CDODBSchema.LIST_REVISION_ID); + builder.append(" = ? AND "); + builder.append(CDODBSchema.LIST_IDX); + builder.append(" = ? "); + sqlUpdateValue = builder.toString(); + + // ----------- insert one item -------------------- + builder = new StringBuilder(); + builder.append("INSERT INTO "); + builder.append(getTable().getName()); + builder.append(" VALUES(?, ?, ?) "); + sqlInsertValue = builder.toString(); + + // ----------- update one item index -------------- + builder = new StringBuilder(); + builder.append("UPDATE "); + builder.append(getTable().getName()); + builder.append(" SET "); + builder.append(CDODBSchema.LIST_IDX); + builder.append(" = ? "); + builder.append(" WHERE "); + builder.append(CDODBSchema.LIST_REVISION_ID); + builder.append(" = ? AND "); + builder.append(CDODBSchema.LIST_IDX); + builder.append(" = ? "); + sqlUpdateIndex = builder.toString(); + + // ----------- move down -------------- + builder = new StringBuilder(); + builder.append("UPDATE "); + builder.append(getTable().getName()); + builder.append(" SET "); + builder.append(CDODBSchema.LIST_IDX); + builder.append(" = "); + builder.append(CDODBSchema.LIST_IDX); + builder.append("-1 WHERE "); + builder.append(CDODBSchema.LIST_REVISION_ID); + builder.append("= ? AND "); + builder.append(CDODBSchema.LIST_IDX); + builder.append(" > ? "); + sqlMoveDown = builder.toString(); + + builder.append(" AND "); + builder.append(CDODBSchema.LIST_IDX); + builder.append(" <= ?"); + sqlMoveDownWithLimit = builder.toString(); + + // ----------- move up -------------- + builder = new StringBuilder(); + builder.append("UPDATE "); + builder.append(getTable().getName()); + builder.append(" SET "); + builder.append(CDODBSchema.LIST_IDX); + builder.append(" = "); + builder.append(CDODBSchema.LIST_IDX); + builder.append("+1 WHERE "); + builder.append(CDODBSchema.LIST_REVISION_ID); + builder.append("= ? AND "); + builder.append(CDODBSchema.LIST_IDX); + builder.append(" >= ? "); + sqlMoveUp = builder.toString(); + + builder.append(" AND "); + builder.append(CDODBSchema.LIST_IDX); + builder.append(" < ?"); + sqlMoveUpWithLimit = builder.toString(); + + } + + @Override + protected FieldInfo[] getKeyFields() + { + return KEY_FIELDS; + } + + @Override + protected void setKeyFields(PreparedStatement stmt, CDORevision revision) throws SQLException + { + stmt.setLong(1, CDOIDUtil.getLong(revision.getID())); + } + + public void objectRevised(IDBStoreAccessor accessor, CDOID id, long revised) + { + clearList(accessor, id); + } + + /** + * Clear a list of a given revision. + * + * @param accessor + * the accessor to use + * @param id + * the id of the revision from which to remove all items + */ + public void clearList(IDBStoreAccessor accessor, CDOID id) + { + PreparedStatement stmt = null; + + try + { + stmt = accessor.getStatementCache().getPreparedStatement(sqlClear, ReuseProbability.HIGH); + stmt.setLong(1, CDOIDUtil.getLong(id)); + CDODBUtil.sqlUpdate(stmt, false); + } + catch (SQLException e) + { + throw new DBException(e); + } + finally + { + accessor.getStatementCache().releasePreparedStatement(stmt); + } + } + + /** + * Insert a list item at a specified position. + * + * @param accessor + * the accessor to use + * @param id + * the id of the revision to insert the value + * @param index + * the index where to insert the element + * @param value + * the value to insert. + */ + public void insertListItem(IDBStoreAccessor accessor, CDOID id, int index, Object value) + { + move1up(accessor, id, index, UNBOUNDED_MOVE); + insertValue(accessor, id, index, value); + } + + private void insertValue(IDBStoreAccessor accessor, CDOID id, int index, Object value) + { + PreparedStatement stmt = null; + + try + { + stmt = accessor.getStatementCache().getPreparedStatement(sqlInsertValue, ReuseProbability.HIGH); + stmt.setLong(1, CDOIDUtil.getLong(id)); + stmt.setInt(2, index); + getTypeMapping().setValue(stmt, 3, value); + + CDODBUtil.sqlUpdate(stmt, true); + } + catch (SQLException e) + { + throw new DBException(e); + } + finally + { + accessor.getStatementCache().releasePreparedStatement(stmt); + } + } + + /** + * Move a list item from one position to another. Indices between both positions are updated so that the list remains + * consistent. + * + * @param accessor + * the accessor to use + * @param id + * the id of the revision in which to move the item + * @param oldPosition + * the old position of the item. + * @param newPosition + * the new position of the item. + */ + public void moveListItem(IDBStoreAccessor accessor, CDOID id, int oldPosition, int newPosition) + { + if (oldPosition == newPosition) + { + return; + } + + // move element away temporarily + updateOneIndex(accessor, id, oldPosition, TEMP_INDEX); + + // move elements in between + if (oldPosition < newPosition) + { + move1down(accessor, id, oldPosition, newPosition); + } + else + { + // oldPosition > newPosition -- equal case is handled above + move1up(accessor, id, newPosition, oldPosition); + } + + // move temporary element to new position + updateOneIndex(accessor, id, TEMP_INDEX, newPosition); + } + + private void updateOneIndex(IDBStoreAccessor accessor, CDOID id, int oldIndex, int newIndex) + { + PreparedStatement stmt = null; + + try + { + stmt = accessor.getStatementCache().getPreparedStatement(sqlUpdateIndex, ReuseProbability.HIGH); + stmt.setInt(1, newIndex); + stmt.setLong(2, CDOIDUtil.getLong(id)); + stmt.setInt(3, oldIndex); + CDODBUtil.sqlUpdate(stmt, true); + } + catch (SQLException e) + { + throw new DBException(e); + } + finally + { + accessor.getStatementCache().releasePreparedStatement(stmt); + } + } + + /** + * Remove a list item from a specified a position. + * + * @param accessor + * the accessor to use + * @param id + * the id of the revision from which to remove the item + * @param index + * the index of the item to remoce + */ + public void removeListItem(IDBStoreAccessor accessor, CDOID id, int index) + { + deleteItem(accessor, id, index); + move1down(accessor, id, index, UNBOUNDED_MOVE); + } + + /** + * Move references downwards to close a gap at position <code>index</code>. Only indexes starting with + * <code>index + 1</code> and ending with <code>upperIndex</code> are moved down. + */ + private void move1down(IDBStoreAccessor accessor, CDOID id, int index, int upperIndex) + { + PreparedStatement stmt = null; + + try + { + stmt = accessor.getStatementCache().getPreparedStatement( + upperIndex == UNBOUNDED_MOVE ? sqlMoveDown : sqlMoveDownWithLimit, ReuseProbability.HIGH); + + stmt.setLong(1, CDOIDUtil.getLong(id)); + stmt.setInt(2, index); + if (upperIndex != UNBOUNDED_MOVE) + { + stmt.setInt(3, upperIndex); + } + + CDODBUtil.sqlUpdate(stmt, false); + } + catch (SQLException e) + { + throw new DBException(e); + } + finally + { + accessor.getStatementCache().releasePreparedStatement(stmt); + } + } + + /** + * Move references downwards to close a gap at position <code>index</code>. Only indexes starting with + * <code>index + 1</code> and ending with <code>upperIndex</code> are moved down. + */ + private void move1up(IDBStoreAccessor accessor, CDOID id, int index, int upperIndex) + { + PreparedStatement stmt = null; + + try + { + stmt = accessor.getStatementCache().getPreparedStatement( + upperIndex == UNBOUNDED_MOVE ? sqlMoveUp : sqlMoveUpWithLimit, ReuseProbability.HIGH); + stmt.setLong(1, CDOIDUtil.getLong(id)); + stmt.setInt(2, index); + if (upperIndex != UNBOUNDED_MOVE) + { + stmt.setInt(3, upperIndex); + } + + CDODBUtil.sqlUpdate(stmt, false); + } + catch (SQLException e) + { + throw new DBException(e); + } + finally + { + accessor.getStatementCache().releasePreparedStatement(stmt); + } + } + + private void deleteItem(IDBStoreAccessor accessor, CDOID id, int index) + { + PreparedStatement stmt = null; + + try + { + stmt = accessor.getStatementCache().getPreparedStatement(sqlDeleteItem, ReuseProbability.HIGH); + stmt.setLong(1, CDOIDUtil.getLong(id)); + stmt.setInt(2, index); + CDODBUtil.sqlUpdate(stmt, true); + } + catch (SQLException e) + { + throw new DBException(e); + } + finally + { + accessor.getStatementCache().releasePreparedStatement(stmt); + } + } + + /** + * Set a value at a specified position to the given value. + * + * @param accessor + * the accessor to use + * @param id + * the id of the revision to set the value + * @param index + * the index of the item to set + * @param value + * the value to be set. + */ + public void setListItem(IDBStoreAccessor accessor, CDOID id, int index, Object value) + { + PreparedStatement stmt = null; + + try + { + stmt = accessor.getStatementCache().getPreparedStatement(sqlUpdateValue, ReuseProbability.HIGH); + getTypeMapping().setValue(stmt, 1, value); + stmt.setLong(2, CDOIDUtil.getLong(id)); + stmt.setInt(3, index); + CDODBUtil.sqlUpdate(stmt, true); + } + catch (SQLException e) + { + throw new DBException(e); + } + finally + { + accessor.getStatementCache().releasePreparedStatement(stmt); + } + } + + public void processDelta(final IDBStoreAccessor accessor, final CDOID id, int oldVersion, final int newVersion, + long created, CDOListFeatureDelta listDelta) + { + CDOFeatureDeltaVisitor visitor = new CDOFeatureDeltaVisitor() + { + + public void visit(CDOMoveFeatureDelta delta) + { + moveListItem(accessor, id, delta.getOldPosition(), delta.getNewPosition()); + } + + public void visit(CDOAddFeatureDelta delta) + { + insertListItem(accessor, id, delta.getIndex(), delta.getValue()); + } + + public void visit(CDORemoveFeatureDelta delta) + { + removeListItem(accessor, id, delta.getIndex()); + } + + public void visit(CDOSetFeatureDelta delta) + { + setListItem(accessor, id, delta.getIndex(), delta.getValue()); + } + + public void visit(CDOUnsetFeatureDelta delta) + { + throw new ImplementationError("Should not be called"); + } + + public void visit(CDOListFeatureDelta delta) + { + throw new ImplementationError("Should not be called"); + } + + public void visit(CDOClearFeatureDelta delta) + { + clearList(accessor, id); + } + + public void visit(CDOContainerFeatureDelta delta) + { + throw new ImplementationError("Should not be called"); + } + + }; + + for (CDOFeatureDelta delta : listDelta.getListChanges()) + { + delta.accept(visitor); + } + } +} diff --git a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/ObjectTypeCache.java b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeCache.java index ba9cc010f2..512c24f67d 100644 --- a/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/ObjectTypeCache.java +++ b/plugins/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/ObjectTypeCache.java @@ -8,15 +8,19 @@ * Contributors: * Eike Stepper - initial API and implementation * Stefan Winkler - https://bugs.eclipse.org/bugs/show_bug.cgi?id=259402 + * Stefan Winkler - redesign (prepared statements) */ -package org.eclipse.emf.cdo.server.internal.db; +package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.id.CDOIDUtil; import org.eclipse.emf.cdo.common.model.CDOClassifierRef; import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; +import org.eclipse.emf.cdo.server.db.IMetaDataManager; import org.eclipse.emf.cdo.server.db.IObjectTypeCache; +import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; +import org.eclipse.emf.cdo.server.internal.db.CDODBSchema; import org.eclipse.net4j.db.DBException; import org.eclipse.net4j.db.DBType; @@ -30,12 +34,15 @@ import org.eclipse.net4j.util.lifecycle.Lifecycle; import org.eclipse.emf.ecore.EClass; +import java.sql.Connection; +import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; /** * @author Eike Stepper + * @since 2.0 */ public class ObjectTypeCache extends Lifecycle implements IObjectTypeCache { @@ -49,6 +56,14 @@ public class ObjectTypeCache extends Lifecycle implements IObjectTypeCache private transient Object initializeLock = new Object(); + private String sqlDelete; + + private String sqlInsert; + + private String sqlSelect; + + private IMetaDataManager metaDataManager; + public ObjectTypeCache() { } @@ -65,26 +80,18 @@ public class ObjectTypeCache extends Lifecycle implements IObjectTypeCache public final CDOClassifierRef getObjectType(IDBStoreAccessor accessor, CDOID id) { - Statement statement = accessor.getJDBCDelegate().getStatement(); - initialize(statement); - - StringBuilder builder = new StringBuilder(); - builder.append("SELECT "); - builder.append(typeField); - builder.append(" FROM "); - builder.append(table); - builder.append(" WHERE "); - builder.append(idField); - builder.append("="); - builder.append(CDOIDUtil.getLong(id)); - String sql = builder.toString(); - DBUtil.trace(sql); - - ResultSet resultSet = null; + Connection connection = accessor.getConnection(); + initialize(connection); + + PreparedStatement stmt = null; try { - resultSet = statement.executeQuery(sql); + stmt = accessor.getStatementCache().getPreparedStatement(sqlSelect, ReuseProbability.MAX); + stmt.setLong(1, CDOIDUtil.getLong(id)); + DBUtil.trace(stmt.toString()); + ResultSet resultSet = stmt.executeQuery(); + if (!resultSet.next()) { DBUtil.trace("ClassID for CDOID " + id + " not found"); @@ -92,7 +99,7 @@ public class ObjectTypeCache extends Lifecycle implements IObjectTypeCache } long classID = resultSet.getLong(1); - EClass eClass = (EClass)mappingStrategy.getStore().getMetaInstance(classID); + EClass eClass = (EClass)metaDataManager.getMetaInstance(classID); return new CDOClassifierRef(eClass); } catch (SQLException ex) @@ -101,59 +108,55 @@ public class ObjectTypeCache extends Lifecycle implements IObjectTypeCache } finally { - DBUtil.close(resultSet); + accessor.getStatementCache().releasePreparedStatement(stmt); } } public final void putObjectType(IDBStoreAccessor accessor, CDOID id, EClass type) { - Statement statement = accessor.getJDBCDelegate().getStatement(); - initialize(statement); - - StringBuilder builder = new StringBuilder(); - builder.append("INSERT INTO "); - builder.append(table); - builder.append(" VALUES ("); - builder.append(CDOIDUtil.getLong(id)); - builder.append(", "); - builder.append(accessor.getStore().getMetaID(type)); - builder.append(")"); - String sql = builder.toString(); - DBUtil.trace(sql); + Connection connection = accessor.getConnection(); + initialize(connection); + + PreparedStatement stmt = null; try { - statement.execute(sql); - if (statement.getUpdateCount() != 1) + stmt = accessor.getStatementCache().getPreparedStatement(sqlInsert, ReuseProbability.MAX); + stmt.setLong(1, CDOIDUtil.getLong(id)); + stmt.setLong(2, metaDataManager.getMetaID(type)); + DBUtil.trace(stmt.toString()); + int result = stmt.executeUpdate(); + + if (result != 1) { - throw new DBException("Object type not inserted: " + id + " -> " + type); + throw new DBException("Object type could not be deleted: " + id); } } catch (SQLException ex) { throw new DBException(ex); } + finally + { + accessor.getStatementCache().releasePreparedStatement(stmt); + } } public final void removeObjectType(IDBStoreAccessor accessor, CDOID id) { - Statement statement = accessor.getJDBCDelegate().getStatement(); - initialize(statement); - - StringBuilder builder = new StringBuilder(); - builder.append("DELETE FROM "); - builder.append(table); - builder.append(" WHERE "); - builder.append(idField); - builder.append(" = "); - builder.append(CDOIDUtil.getLong(id)); - String sql = builder.toString(); - DBUtil.trace(sql); + Connection connection = accessor.getConnection(); + initialize(connection); + + PreparedStatement stmt = null; try { - statement.execute(sql); - if (statement.getUpdateCount() != 1) + stmt = accessor.getStatementCache().getPreparedStatement(sqlDelete, ReuseProbability.MAX); + stmt.setLong(1, CDOIDUtil.getLong(id)); + DBUtil.trace(stmt.toString()); + int result = stmt.executeUpdate(); + + if (result != 1) { throw new DBException("Object type could not be deleted: " + id); } @@ -162,10 +165,16 @@ public class ObjectTypeCache extends Lifecycle implements IObjectTypeCache { throw new DBException(ex); } + finally + { + accessor.getStatementCache().releasePreparedStatement(stmt); + } } - private void initialize(Statement statement) + private void initialize(Connection connection) { + // TODO - is there a better way to initialize this + // e.g. doActivate() - only problem there is to get hold of a statement .... synchronized (initializeLock) { if (table == null) @@ -177,11 +186,37 @@ public class ObjectTypeCache extends Lifecycle implements IObjectTypeCache table.addIndex(IDBIndex.Type.UNIQUE, idField); IDBAdapter dbAdapter = mappingStrategy.getStore().getDBAdapter(); - dbAdapter.createTable(table, statement); + + Statement statement = null; + try + { + statement = connection.createStatement(); + dbAdapter.createTable(table, statement); + } + catch (SQLException ex) + { + throw new DBException(ex); + } + finally + { + DBUtil.close(statement); + } } + + sqlSelect = "SELECT " + typeField.getName() + " FROM " + table.getName() + " WHERE " + idField.getName() + " = ?"; + + sqlInsert = "INSERT INTO " + table.getName() + " VALUES (?,?)"; + + sqlDelete = "DELETE FROM " + table.getName() + " WHERE " + idField.getName() + " = ?"; } } + public long getMaxId(Connection connection) + { + initialize(connection); + return DBUtil.selectMaximumLong(connection, idField); + } + @Override protected void doBeforeActivate() throws Exception { @@ -190,6 +225,12 @@ public class ObjectTypeCache extends Lifecycle implements IObjectTypeCache } @Override + protected void doActivate() throws Exception + { + metaDataManager = getMappingStrategy().getStore().getMetaDataManager(); + } + + @Override protected void doDeactivate() throws Exception { table = null; @@ -197,4 +238,5 @@ public class ObjectTypeCache extends Lifecycle implements IObjectTypeCache typeField = null; super.doDeactivate(); } + } diff --git a/plugins/org.eclipse.emf.cdo.tests/CDO AllTests (Hsqldb).launch b/plugins/org.eclipse.emf.cdo.tests/CDO AllTests (Hsqldb).launch index 619b47ff83..6aaff2769c 100644 --- a/plugins/org.eclipse.emf.cdo.tests/CDO AllTests (Hsqldb).launch +++ b/plugins/org.eclipse.emf.cdo.tests/CDO AllTests (Hsqldb).launch @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <launchConfiguration type="org.eclipse.jdt.junit.launchconfig"> <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS"> -<listEntry value="/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsDBHsqldbPrepStmt.java"/> +<listEntry value="/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsDBHsqldb.java"/> </listAttribute> <listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES"> <listEntry value="1"/> @@ -14,7 +14,7 @@ <booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/> <stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/> <stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit3"/> -<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.eclipse.emf.cdo.tests.AllTestsDBHsqldbPrepStmt"/> +<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="org.eclipse.emf.cdo.tests.AllTestsDBHsqldb"/> <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.emf.cdo.tests"/> <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Xms40m -Xmx512m"/> </launchConfiguration> diff --git a/plugins/org.eclipse.emf.cdo.tests/META-INF/MANIFEST.MF b/plugins/org.eclipse.emf.cdo.tests/META-INF/MANIFEST.MF index 4114614b04..84358ea184 100644 --- a/plugins/org.eclipse.emf.cdo.tests/META-INF/MANIFEST.MF +++ b/plugins/org.eclipse.emf.cdo.tests/META-INF/MANIFEST.MF @@ -9,7 +9,8 @@ Bundle-ActivationPolicy: lazy Bundle-Activator: org.eclipse.emf.cdo.tests.bundle.OM$Activator Bundle-RequiredExecutionEnvironment: J2SE-1.5 Bundle-ClassPath: . -Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.4.0,4.0.0)", +Require-Bundle: com.springsource.com.mysql.jdbc;bundle-version="[5.0.0,6.0.0)";visibility:=reexport, + org.eclipse.core.runtime;bundle-version="[3.4.0,4.0.0)", org.eclipse.emf.ecore.xmi;bundle-version="[2.4.0,3.0.0)";visibility:=reexport, org.eclipse.net4j.db.hsqldb;bundle-version="[2.0.0,3.0.0)";visibility:=reexport, org.eclipse.net4j.db.derby;bundle-version="[2.0.0,3.0.0)";visibility:=reexport, @@ -48,8 +49,7 @@ Export-Package: base;version="2.0.0", reference;version="2.0.0", reference.impl;version="2.0.0", reference.util;version="2.0.0" -Import-Package: com.mysql.jdbc.jdbc2.optional;version="[5.1.0,6.0.0)";resolution:=optional, - org.apache.commons.collections;version="[3.2.0,4.0.0)";resolution:=optional, +Import-Package: org.apache.commons.collections;version="[3.2.0,4.0.0)";resolution:=optional, org.apache.commons.logging;version="[1.1.0,2.0.0)";resolution:=optional, org.apache.derby.jdbc;resolution:=optional, org.dom4j;version="[1.6.0,2.0.0)";resolution:=optional, diff --git a/plugins/org.eclipse.emf.cdo.tests/net4j/org/eclipse/net4j/tests/AbstractOMTest.java b/plugins/org.eclipse.emf.cdo.tests/net4j/org/eclipse/net4j/tests/AbstractOMTest.java index 4774092d4c..91873ca852 100644 --- a/plugins/org.eclipse.emf.cdo.tests/net4j/org/eclipse/net4j/tests/AbstractOMTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/net4j/org/eclipse/net4j/tests/AbstractOMTest.java @@ -42,7 +42,9 @@ public abstract class AbstractOMTest extends TestCase if (!SUPPRESS_OUTPUT) { IOUtil.OUT().println("*******************************************************"); + sleep(1L); IOUtil.ERR().println(this); + sleep(1L); IOUtil.OUT().println("*******************************************************"); } diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AbstractCDOTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AbstractCDOTest.java index 3570b1f9b3..efb5f42fd8 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AbstractCDOTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AbstractCDOTest.java @@ -39,13 +39,19 @@ public abstract class AbstractCDOTest extends ConfigTest @Override protected void doSetUp() throws Exception { - super.doSetUp(); - org.eclipse.emf.internal.cdo.bundle.OM.PREF_COMMIT_MONITOR_PROGRESS_SECONDS.setValue(60); - org.eclipse.emf.internal.cdo.bundle.OM.PREF_COMMIT_MONITOR_TIMEOUT_SECONDS.setValue(60 * 60); - org.eclipse.internal.net4j.bundle.OM.DEBUG.setEnabled(false); - org.eclipse.net4j.internal.tcp.bundle.OM.DEBUG.setEnabled(false); - CDOPackageTypeRegistry.INSTANCE.reset(); - startTransport(); + try + { + super.doSetUp(); + } + finally + { + org.eclipse.emf.internal.cdo.bundle.OM.PREF_COMMIT_MONITOR_PROGRESS_SECONDS.setValue(60); + org.eclipse.emf.internal.cdo.bundle.OM.PREF_COMMIT_MONITOR_TIMEOUT_SECONDS.setValue(60 * 60); + org.eclipse.internal.net4j.bundle.OM.DEBUG.setEnabled(false); + org.eclipse.net4j.internal.tcp.bundle.OM.DEBUG.setEnabled(false); + CDOPackageTypeRegistry.INSTANCE.reset(); + startTransport(); + } } public static void assertEquals(Object expected, Object actual) diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTests.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTests.java index 2a75eee075..1e019c2f51 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTests.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTests.java @@ -4,7 +4,7 @@ * 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 */ @@ -26,6 +26,6 @@ public class AllTests extends AllTestsAllConfigs @Override protected void initConfigSuites(TestSuite parent) { - addScenario(parent, COMBINED, MEM, TCP, NATIVE); + addScenario(parent, COMBINED, MEM, JVM, NATIVE); } } diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsDBHsqldb.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsDBHsqldb.java index 857d86f437..7e8b829253 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsDBHsqldb.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsDBHsqldb.java @@ -4,12 +4,17 @@ * 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.tests; +import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_266982_Test; +import org.eclipse.emf.cdo.tests.config.impl.ConfigTest; + +import java.util.List; + import junit.framework.Test; import junit.framework.TestSuite; @@ -26,6 +31,15 @@ public class AllTestsDBHsqldb extends AllTestsAllConfigs @Override protected void initConfigSuites(TestSuite parent) { - addScenario(parent, COMBINED, DB_HSQL_HORIZONTAL, TCP, NATIVE); + addScenario(parent, COMBINED, DB_HSQL, TCP, NATIVE); + } + + @Override + protected void initTestClasses(List<Class<? extends ConfigTest>> testClasses) + { + super.initTestClasses(testClasses); + + // this takes ages ... + testClasses.remove(Bugzilla_266982_Test.class); } } diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsDBHsqldbNonAudit.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsDBHsqldbNonAudit.java index 751b35c9e5..4e9ff8b383 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsDBHsqldbNonAudit.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsDBHsqldbNonAudit.java @@ -4,7 +4,7 @@ * 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: * Stefan Winkler - initial API and implementation */ @@ -33,7 +33,7 @@ public class AllTestsDBHsqldbNonAudit extends AllTestsAllConfigs @Override protected void initConfigSuites(TestSuite parent) { - addScenario(parent, COMBINED, DB_HSQL_HORIZONTAL_NONAUDIT, TCP, NATIVE); + addScenario(parent, COMBINED, DB_HSQL_NONAUDIT, TCP, NATIVE); } @Override diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsDBHsqldbPrepStmt.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsDBHsqldbPrepStmt.java deleted file mode 100644 index 0402d4a8b1..0000000000 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsDBHsqldbPrepStmt.java +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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.tests; - -import junit.framework.Test; -import junit.framework.TestSuite; - -/** - * @author Eike Stepper - */ -public class AllTestsDBHsqldbPrepStmt extends AllTestsAllConfigs -{ - public static Test suite() - { - return new AllTestsDBHsqldbPrepStmt().getTestSuite("CDO Tests (DB Hsql Horizontal PrepStmt)"); - } - - @Override - protected void initConfigSuites(TestSuite parent) - { - addScenario(parent, COMBINED, DB_HSQL_HORIZONTAL_PREPSTMT, TCP, NATIVE); - } -} diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsDBHsqldbPrepStmtNonAudit.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsDBHsqldbPrepStmtNonAudit.java deleted file mode 100644 index 412d9c9a5d..0000000000 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/AllTestsDBHsqldbPrepStmtNonAudit.java +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright (c) 2004 - 2009 Eike Stepper (Berlin, 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.tests; - -import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_252214_Test; -import org.eclipse.emf.cdo.tests.bugzilla.Bugzilla_261218_Test; -import org.eclipse.emf.cdo.tests.config.impl.ConfigTest; - -import java.util.List; - -import junit.framework.Test; -import junit.framework.TestSuite; - -/** - * @author Stefan Winkler - */ -public class AllTestsDBHsqldbPrepStmtNonAudit extends AllTestsAllConfigs -{ - public static Test suite() - { - return new AllTestsDBHsqldbPrepStmtNonAudit().getTestSuite("CDO Tests (DB Hsql Horizontal PrepStmt Non-Audit)"); - } - - @Override - protected void initConfigSuites(TestSuite parent) - { - addScenario(parent, COMBINED, DB_HSQL_HORIZONTAL_PREPSTMT_NONAUDIT, TCP, NATIVE); - } - - @Override - protected void initTestClasses(List<Class<? extends ConfigTest>> testClasses) - { - super.initTestClasses(testClasses); - - // non-audit mode - remove audit tests - testClasses.remove(AuditTest.class); - testClasses.remove(AuditTest.LocalAuditTest.class); - testClasses.remove(Bugzilla_252214_Test.class); - - // this takes ages - so for now, we disable it - testClasses.remove(Bugzilla_261218_Test.class); - } -} diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ChunkingTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ChunkingTest.java index 79be96a5a2..969f443749 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ChunkingTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/ChunkingTest.java @@ -4,7 +4,7 @@ * 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 */ @@ -14,13 +14,18 @@ import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.session.CDOSession; import org.eclipse.emf.cdo.tests.model1.Customer; import org.eclipse.emf.cdo.tests.model1.SalesOrder; +import org.eclipse.emf.cdo.tests.model5.GenListOfInt; +import org.eclipse.emf.cdo.tests.model5.Model5Factory; import org.eclipse.emf.cdo.transaction.CDOTransaction; import org.eclipse.emf.cdo.util.CDOUtil; +import org.eclipse.emf.cdo.view.CDOView; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; +import java.util.Arrays; import java.util.Iterator; +import java.util.List; /** * @author Eike Stepper @@ -235,4 +240,127 @@ public class ChunkingTest extends AbstractCDOTest assertEquals(i - 20, saleOrders.getId()); } } + + private static final String RESOURCE_PATH = "/test"; + + public void testPartiallyLoadedAdd() + { + createInitialList(); + + CDOSession session = openSession(getModel5Package()); + session.options().setCollectionLoadingPolicy(CDOUtil.createCollectionLoadingPolicy(3, 1)); + CDOTransaction tx = session.openTransaction(); + CDOResource resource = tx.getResource(RESOURCE_PATH); + + GenListOfInt list = (GenListOfInt)resource.getContents().get(0); + list.getElements().add(9); + + tx.commit(); + tx.close(); + session.close(); + clearCache(getRepository().getRevisionManager()); + + testListResult(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); + } + + public void testPartiallyLoadedAddAtIndex() + { + createInitialList(); + + CDOSession session = openSession(getModel5Package()); + session.options().setCollectionLoadingPolicy(CDOUtil.createCollectionLoadingPolicy(3, 1)); + CDOTransaction tx = session.openTransaction(); + CDOResource resource = tx.getResource(RESOURCE_PATH); + + GenListOfInt list = (GenListOfInt)resource.getContents().get(0); + list.getElements().add(5, 9); + + tx.commit(); + tx.close(); + session.close(); + clearCache(getRepository().getRevisionManager()); + + testListResult(0, 1, 2, 3, 4, 9, 5, 6, 7, 8); + } + + public void testPartiallyLoadedSet() + { + createInitialList(); + + CDOSession session = openSession(getModel5Package()); + session.options().setCollectionLoadingPolicy(CDOUtil.createCollectionLoadingPolicy(3, 1)); + CDOTransaction tx = session.openTransaction(); + CDOResource resource = tx.getResource(RESOURCE_PATH); + + GenListOfInt list = (GenListOfInt)resource.getContents().get(0); + list.getElements().set(5, 9); + + tx.commit(); + tx.close(); + session.close(); + clearCache(getRepository().getRevisionManager()); + + testListResult(0, 1, 2, 3, 4, 9, 6, 7, 8); + } + + public void testPartiallyLoadedRemoveIndex() + { + createInitialList(); + + CDOSession session = openSession(getModel5Package()); + session.options().setCollectionLoadingPolicy(CDOUtil.createCollectionLoadingPolicy(3, 1)); + CDOTransaction tx = session.openTransaction(); + CDOResource resource = tx.getResource(RESOURCE_PATH); + + GenListOfInt list = (GenListOfInt)resource.getContents().get(0); + list.getElements().remove(5); + + tx.commit(); + tx.close(); + session.close(); + clearCache(getRepository().getRevisionManager()); + + testListResult(0, 1, 2, 3, 4, 6, 7, 8); + } + + private void createInitialList() + { + CDOSession session = openSession(getModel5Package()); + CDOTransaction tx = session.openTransaction(); + CDOResource resource = tx.createResource(RESOURCE_PATH); + + GenListOfInt list = Model5Factory.eINSTANCE.createGenListOfInt(); + + list.getElements().addAll(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8)); + + resource.getContents().add(list); + + tx.commit(); + tx.close(); + session.close(); + + clearCache(getRepository().getRevisionManager()); + } + + private void testListResult(Integer... expected) + { + List<Integer> expectedList = Arrays.asList(expected); + + CDOSession session = openSession(getModel5Package()); + CDOView view = session.openView(); + CDOResource resource = view.getResource(RESOURCE_PATH); + + EList<Integer> actualList = ((GenListOfInt)resource.getContents().get(0)).getElements(); + + assertEquals("List sizes differ", expectedList.size(), actualList.size()); + + for (int index = 0; index < expectedList.size(); index++) + { + assertEquals("Entry at index " + index + " differs", expectedList.get(index), actualList.get(index)); + } + + view.close(); + session.close(); + } + } diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/MetaTest.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/MetaTest.java index ced470c777..100684fb78 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/MetaTest.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/MetaTest.java @@ -13,7 +13,6 @@ package org.eclipse.emf.cdo.tests; import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.session.CDOSession; import org.eclipse.emf.cdo.tests.model3.MetaRef; -import org.eclipse.emf.cdo.tests.model3.Model3Package; import org.eclipse.emf.cdo.transaction.CDOTransaction; /** @@ -29,19 +28,39 @@ public class MetaTest extends AbstractCDOTest CDOResource res = transaction.createResource("/res"); MetaRef metaRef = getModel3Factory().createMetaRef(); - metaRef.setEPackageRef(Model3Package.eINSTANCE); + metaRef.setEPackageRef(getModel3Package()); res.getContents().add(metaRef); transaction.commit(); session.close(); } + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource res = transaction.getResource("/res"); + + MetaRef metaRef = (MetaRef)res.getContents().get(0); + assertEquals(getModel3Package(), metaRef.getEPackageRef()); + } + + public void testMetaReferenceAttachFirst() throws Exception + { { - CDOSession session = openSession(); + CDOSession session = openModel3Session(); CDOTransaction transaction = session.openTransaction(); - CDOResource res = transaction.getResource("/res"); + CDOResource res = transaction.createResource("/res"); - MetaRef metaRef = (MetaRef)res.getContents().get(0); - assertEquals(Model3Package.eINSTANCE, metaRef.getEPackageRef()); + MetaRef metaRef = getModel3Factory().createMetaRef(); + res.getContents().add(metaRef); + metaRef.setEPackageRef(getModel3Package()); + transaction.commit(); + session.close(); } + + CDOSession session = openSession(); + CDOTransaction transaction = session.openTransaction(); + CDOResource res = transaction.getResource("/res"); + + MetaRef metaRef = (MetaRef)res.getContents().get(0); + assertEquals(getModel3Package(), metaRef.getEPackageRef()); } } diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_248052_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_248052_Test.java index f86ba81a33..24c04f0eb6 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_248052_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_248052_Test.java @@ -11,17 +11,9 @@ */ package org.eclipse.emf.cdo.tests.bugzilla; -import org.eclipse.emf.cdo.eresource.CDOResource; -import org.eclipse.emf.cdo.internal.common.revision.CDORevisionResolverImpl; import org.eclipse.emf.cdo.server.IRepository; -import org.eclipse.emf.cdo.session.CDOSession; import org.eclipse.emf.cdo.tests.AbstractCDOTest; -import org.eclipse.emf.cdo.tests.model1.Customer; -import org.eclipse.emf.cdo.transaction.CDOTransaction; - -import org.eclipse.emf.internal.cdo.util.FSMUtil; - -import org.eclipse.emf.spi.cdo.InternalCDOObject; +import org.eclipse.emf.cdo.tests.bundle.OM; import java.util.Map; @@ -42,26 +34,21 @@ public class Bugzilla_248052_Test extends AbstractCDOTest return testProperties; } - public void testNoSupportingDeltas() throws Exception + @Override + protected void doSetUp() throws Exception { - CDOSession session = openModel1Session(); - - CDOTransaction transaction1 = session.openTransaction(); - CDOResource res = transaction1.createResource("/test1"); - - Customer customer = getModel1Factory().createCustomer(); - - res.getContents().add(customer); - - msg("Committing"); - transaction1.commit(); - - InternalCDOObject cdoCustomer = FSMUtil.adapt(customer, transaction1); - CDORevisionResolverImpl revisionManager = (CDORevisionResolverImpl)getRepository().getRevisionManager(); - revisionManager.removeCachedRevision(cdoCustomer.cdoID(), cdoCustomer.cdoRevision().getVersion()); - - customer.setName("OTTAWA"); + try + { + super.doSetUp(); + } + catch (IllegalStateException ex) + { + OM.LOG.info("Expected IllegalStateException", ex); + } + } - transaction1.commit(); + public void testNoSupportingDeltas() throws Exception + { + // Possible failure already in doSetup() } } diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_251752_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_251752_Test.java index 8ea6944453..e3105d86a8 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_251752_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_251752_Test.java @@ -28,7 +28,6 @@ import org.eclipse.emf.cdo.util.CDOUtil; */ public class Bugzilla_251752_Test extends AbstractCDOTest { - public void testBug_251752() throws Exception { CDOSession session = openSession(); @@ -36,11 +35,13 @@ public class Bugzilla_251752_Test extends AbstractCDOTest CDOResource res = transaction1.createResource("/test1"); res.getContents().add(getModel1Factory().createCompany()); transaction1.commit(); + CDOTransaction transaction2 = session.openTransaction(); CDOResource res2 = transaction2.getResource("/test1"); res.getContents().add(getModel1Factory().createCompany()); res2.getContents().add(getModel1Factory().createCompany()); transaction2.commit(); + try { transaction1.commit(); @@ -49,6 +50,7 @@ public class Bugzilla_251752_Test extends AbstractCDOTest catch (Exception ex) { } + assertTrue(res.cdoRevision().isTransactional()); } @@ -61,6 +63,7 @@ public class Bugzilla_251752_Test extends AbstractCDOTest CDOResource res = transaction1.createResource("/test1"); res.getContents().add(getModel1Factory().createCompany()); transaction1.commit(); + CDOTransaction transaction2 = session.openTransaction(); CDOResource res2 = transaction2.getResource("/test1"); res.getContents().add(getModel1Factory().createCompany()); @@ -75,6 +78,7 @@ public class Bugzilla_251752_Test extends AbstractCDOTest catch (Exception ex) { } + assertTrue(res.cdoRevision().isTransactional()); } } diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_272861_Test.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_272861_Test.java index 9d76619c9b..ef0b340d09 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_272861_Test.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/bugzilla/Bugzilla_272861_Test.java @@ -24,39 +24,37 @@ public class Bugzilla_272861_Test extends AbstractCDOTest { public void test_Bugzilla_271861_Case1() throws IOException { - CDOSession session = openModel1Session(); CDOTransaction trans = session.openTransaction(); CDOResource res = trans.createResource("/test/1"); - trans.commit(); res.delete(null); res = trans.createResource("/test/1"); trans.commit(); + trans.close(); session.close(); - } // TODO SIMON Is it a bug or not?? public void te2st_Bugzilla_272861_Case2() throws IOException { - CDOSession session = openModel1Session(); CDOTransaction trans1 = session.openTransaction(); - CDOTransaction trans2 = session.openTransaction(); - CDOResource res1 = trans1.createResource("/test1"); - CDOResource res2 = trans2.createResource("/test2"); + + trans1.createResource("/test1"); + trans2.createResource("/test2"); trans1.commit(); trans2.commit(); + trans1.close(); trans2.close(); - session.close(); + session.close(); } } diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/IConstants.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/IConstants.java index 0f771df9bb..be3a16810f 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/IConstants.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/IConstants.java @@ -33,21 +33,13 @@ public interface IConstants public static final RepositoryConfig MEM = RepositoryConfig.MEM.INSTANCE; - public static final RepositoryConfig DB_HSQL_HORIZONTAL = RepositoryConfig.DB.Hsqldb.Stmt.INSTANCE; + public static final RepositoryConfig DB_HSQL = RepositoryConfig.DB.Hsqldb.INSTANCE; - public static final RepositoryConfig DB_HSQL_HORIZONTAL_NONAUDIT = RepositoryConfig.DB.Hsqldb.StmtNonAudit.INSTANCE; + public static final RepositoryConfig DB_HSQL_NONAUDIT = RepositoryConfig.DB.HsqldbNonAudit.INSTANCE; - public static final RepositoryConfig DB_HSQL_HORIZONTAL_PREPSTMT = RepositoryConfig.DB.Hsqldb.PrepStmt.INSTANCE; + public static final RepositoryConfig DB_DERBY = RepositoryConfig.DB.Derby.INSTANCE; - public static final RepositoryConfig DB_HSQL_HORIZONTAL_PREPSTMT_NONAUDIT = RepositoryConfig.DB.Hsqldb.PrepStmtNonAudit.INSTANCE; - - public static final RepositoryConfig DB_DERBY_HORIZONTAL = RepositoryConfig.DB.Derby.Stmt.INSTANCE; - - public static final RepositoryConfig DB_DERBY_HORIZONTAL_PREPSTMT = RepositoryConfig.DB.Derby.PrepStmt.INSTANCE; - - // public static final RepositoryConfig DB_MYSQL_HORIZONTAL = RepositoryConfig.DB.Mysql.Stmt.INSTANCE; - // - // public static final RepositoryConfig DB_MYSQL_HORIZONTAL_PREPSTMT = RepositoryConfig.DB.Mysql.PrepStmt.INSTANCE; + public static final RepositoryConfig DB_MYSQL = RepositoryConfig.DB.Mysql.INSTANCE; public static final SessionConfig JVM = SessionConfig.JVM.INSTANCE; diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java index b29a90ecb9..18c926abe4 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/RepositoryConfig.java @@ -4,7 +4,7 @@ * 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 * Stefan Winkler - https://bugs.eclipse.org/bugs/show_bug.cgi?id=259402 @@ -19,11 +19,11 @@ import org.eclipse.emf.cdo.server.IRepositoryProvider; import org.eclipse.emf.cdo.server.IStore; import org.eclipse.emf.cdo.server.IRepository.Props; import org.eclipse.emf.cdo.server.db.CDODBUtil; -import org.eclipse.emf.cdo.server.db.IJDBCDelegateProvider; import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy; import org.eclipse.emf.cdo.server.mem.MEMStoreUtil; import org.eclipse.emf.cdo.tests.bundle.OM; import org.eclipse.emf.cdo.tests.config.IRepositoryConfig; +import org.eclipse.emf.cdo.tests.store.verifier.AbstractDBStoreVerifier; import org.eclipse.emf.cdo.tests.store.verifier.AuditDBStoreIntegrityVerifier; import org.eclipse.emf.cdo.tests.store.verifier.NonAuditDBStoreIntegrityVerifier; @@ -32,12 +32,15 @@ import org.eclipse.net4j.db.IDBAdapter; import org.eclipse.net4j.db.derby.EmbeddedDerbyAdapter; import org.eclipse.net4j.db.hsqldb.HSQLDBAdapter; import org.eclipse.net4j.db.hsqldb.HSQLDBDataSource; +import org.eclipse.net4j.db.mysql.MYSQLAdapter; import org.eclipse.net4j.util.ObjectUtil; import org.eclipse.net4j.util.container.IManagedContainer; import org.eclipse.net4j.util.io.IOUtil; import org.eclipse.net4j.util.io.TMPUtil; import org.eclipse.net4j.util.lifecycle.LifecycleUtil; +import com.mysql.jdbc.jdbc2.optional.MysqlDataSource; + import org.apache.derby.jdbc.EmbeddedDataSource; import javax.sql.DataSource; @@ -57,10 +60,9 @@ import java.util.Map.Entry; public abstract class RepositoryConfig extends Config implements IRepositoryConfig { public static final RepositoryConfig[] CONFIGS = { MEM.INSTANCE, // - DB.Hsqldb.Stmt.INSTANCE, DB.Hsqldb.PrepStmt.INSTANCE, // - DB.Derby.Stmt.INSTANCE, DB.Derby.PrepStmt.INSTANCE /* - * , // DB.Mysql.Stmt.INSTANCE, DB.Mysql.PrepStmt.INSTANCE - */}; + DB.Hsqldb.INSTANCE, // + DB.Derby.INSTANCE, // + DB.Mysql.INSTANCE }; public static final String PROP_TEST_REPOSITORY = "test.repository"; @@ -233,13 +235,9 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf IMappingStrategy mappingStrategy = createMappingStrategy(); IDBAdapter dbAdapter = createDBAdapter(); DataSource dataSource = createDataSource(); - IJDBCDelegateProvider delegateProvider = createDelegateProvider(); - return CDODBUtil.createStore(mappingStrategy, dbAdapter, DBUtil.createConnectionProvider(dataSource), - delegateProvider); + return CDODBUtil.createStore(mappingStrategy, dbAdapter, DBUtil.createConnectionProvider(dataSource)); } - protected abstract IJDBCDelegateProvider createDelegateProvider(); - protected abstract IMappingStrategy createMappingStrategy(); protected abstract IDBAdapter createDBAdapter(); @@ -249,10 +247,14 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf /** * @author Eike Stepper */ - public abstract static class Hsqldb extends DB + public static class Hsqldb extends DB { private static final long serialVersionUID = 1L; + public static boolean USE_VERIFIER = false; + + public static final Hsqldb INSTANCE = new Hsqldb("HSQLDB"); + private transient HSQLDBDataSource dataSource; public Hsqldb(String name) @@ -294,8 +296,33 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf @Override public void tearDown() throws Exception { - super.tearDown(); - shutDownHsqldb(); + try + { + if (USE_VERIFIER) + { + IRepository testRepository = getRepository(REPOSITORY_NAME); + if (testRepository != null) + { + getVerifier(testRepository).verify(); + } + } + } + finally + { + try + { + super.tearDown(); + } + finally + { + shutDownHsqldb(); + } + } + } + + protected AbstractDBStoreVerifier getVerifier(IRepository repository) + { + return new AuditDBStoreIntegrityVerifier(repository); } private void shutDownHsqldb() throws SQLException @@ -319,143 +346,48 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf } } } + } - public static class Stmt extends Hsqldb - { - private static final long serialVersionUID = 1L; - - public static final Stmt INSTANCE = new Stmt("HsqldbHorizontalStmt"); + public static class HsqldbNonAudit extends Hsqldb + { + private static final long serialVersionUID = 1L; - public Stmt(String name) - { - super(name); - } + public static final HsqldbNonAudit INSTANCE = new HsqldbNonAudit("DBStore: Hsqldb (non audit)"); - @Override - protected IJDBCDelegateProvider createDelegateProvider() - { - return CDODBUtil.createStatementJDBCDelegateProvider(); - } + public HsqldbNonAudit(String name) + { + super(name); } - public static class StmtNonAudit extends Hsqldb + @Override + protected void initRepositoryProperties(Map<String, String> props) { - private static final long serialVersionUID = 1L; - - public static final StmtNonAudit INSTANCE = new StmtNonAudit("HsqldbHorizontalNonAudit"); - - public StmtNonAudit(String name) - { - super(name); - } - - @Override - protected void initRepositoryProperties(Map<String, String> props) - { - super.initRepositoryProperties(props); - props.put(IRepository.Props.SUPPORTING_AUDITS, "false"); - } - - @Override - protected IJDBCDelegateProvider createDelegateProvider() - { - return CDODBUtil.createStatementJDBCDelegateProvider(); - } - - @Override - public void tearDown() throws Exception - { - try - { - // verify DB integrity - new NonAuditDBStoreIntegrityVerifier(getRepository(REPOSITORY_NAME)).verify(); - } - finally - { - super.tearDown(); - } - } + super.initRepositoryProperties(props); + props.put(IRepository.Props.SUPPORTING_AUDITS, "false"); } - public static class PrepStmt extends Hsqldb + @Override + protected IMappingStrategy createMappingStrategy() { - private static final long serialVersionUID = 1L; - - public static final PrepStmt INSTANCE = new PrepStmt("HsqldbHorizontalPrepStmt"); - - public PrepStmt(String name) - { - super(name); - } - - @Override - public void tearDown() throws Exception - { - try - { - // verify DB integrity - new AuditDBStoreIntegrityVerifier(getRepository(REPOSITORY_NAME)).verify(); - } - finally - { - super.tearDown(); - } - } - - @Override - protected IJDBCDelegateProvider createDelegateProvider() - { - return CDODBUtil.createPreparedStatementJDBCDelegateProvider(); - } + return CDODBUtil.createHorizontalNonAuditMappingStrategy(); } - public static class PrepStmtNonAudit extends Hsqldb + @Override + protected AbstractDBStoreVerifier getVerifier(IRepository repository) { - private static final long serialVersionUID = 1L; - - public static final PrepStmtNonAudit INSTANCE = new PrepStmtNonAudit("HsqldbHorizontalPrepStmtNonAudit"); - - public PrepStmtNonAudit(String name) - { - super(name); - } - - @Override - protected void initRepositoryProperties(Map<String, String> props) - { - super.initRepositoryProperties(props); - props.put(IRepository.Props.SUPPORTING_AUDITS, "false"); - } - - @Override - protected IJDBCDelegateProvider createDelegateProvider() - { - return CDODBUtil.createPreparedStatementJDBCDelegateProvider(); - } - - @Override - public void tearDown() throws Exception - { - try - { - // verify DB integrity - new NonAuditDBStoreIntegrityVerifier(getRepository(REPOSITORY_NAME)).verify(); - } - finally - { - super.tearDown(); - } - } + return new NonAuditDBStoreIntegrityVerifier(repository); } } /** * @author Eike Stepper */ - public abstract static class Derby extends DB + public static class Derby extends DB { private static final long serialVersionUID = 1L; + public static final Derby INSTANCE = new Derby("DBStore: Derby"); + private transient File dbFolder; private transient EmbeddedDataSource dataSource; @@ -500,176 +432,105 @@ public abstract class RepositoryConfig extends Config implements IRepositoryConf { IOUtil.delete(dbFolder); } + } + + /** + * @author Simon McDuff + */ + public static class Mysql extends DB + { + private static final long serialVersionUID = 1L; + + public static final Mysql INSTANCE = new Mysql("DBStore: Mysql"); + + private transient MysqlDataSource setupDataSource; + + private transient MysqlDataSource dataSource; + + public Mysql(String name) + { + super(name); + } - public static class Stmt extends Derby + @Override + protected IMappingStrategy createMappingStrategy() + { + return CDODBUtil.createHorizontalMappingStrategy(); + } + + @Override + protected IDBAdapter createDBAdapter() + { + return new MYSQLAdapter(); + } + + private MysqlDataSource getSetupDataSource() { - private static final long serialVersionUID = 1L; + if (setupDataSource == null) + { + setupDataSource = new MysqlDataSource(); + setupDataSource.setUrl("jdbc:mysql://localhost"); + setupDataSource.setUser("sa"); + } - public static final Stmt INSTANCE = new Stmt("DerbyHorizontalStmt"); + return setupDataSource; + } - public Stmt(String name) + @Override + public void setUp() throws Exception + { + dropDatabase(); + Connection connection = null; + try { - super(name); + connection = getSetupDataSource().getConnection(); + connection.prepareStatement("create database cdodb1").execute(); } + catch (SQLException ignore) + { - @Override - protected IJDBCDelegateProvider createDelegateProvider() + } + finally { - return CDODBUtil.createStatementJDBCDelegateProvider(); + connection.close(); } + super.setUp(); } - public static class PrepStmt extends Derby + @Override + protected DataSource createDataSource() { - private static final long serialVersionUID = 1L; + dataSource = new MysqlDataSource(); + dataSource.setUrl("jdbc:mysql://localhost/cdodb1"); + dataSource.setUser("sa"); + return dataSource; + } - public static final PrepStmt INSTANCE = new PrepStmt("DerbyHorizontalPrepStmt"); + @Override + public void tearDown() throws Exception + { + super.tearDown(); + dropDatabase(); + } - public PrepStmt(String name) + private void dropDatabase() throws Exception + { + Connection connection = null; + try { - super(name); + connection = getSetupDataSource().getConnection(); + connection.prepareStatement("DROP database cdodb1").execute(); } + catch (SQLException ignore) + { - @Override - protected IJDBCDelegateProvider createDelegateProvider() + } + finally { - return CDODBUtil.createPreparedStatementJDBCDelegateProvider(); + connection.close(); } } - } - // XXX - // /** - // * @author Simon McDuff - // */ - // public static abstract class Mysql extends DB - // { - // private static final long serialVersionUID = 1L; - // - // private transient MysqlDataSource setupDataSource; - // - // private transient MysqlDataSource dataSource; - // - // public Mysql(String name) - // { - // super(name); - // } - // - // @Override - // protected IMappingStrategy createMappingStrategy() - // { - // return CDODBUtil.createHorizontalMappingStrategy(); - // } - // - // @Override - // protected IDBAdapter createDBAdapter() - // { - // return new MYSQLAdapter(); - // } - // - // private MysqlDataSource getSetupDataSource() - // { - // if (setupDataSource == null) - // { - // setupDataSource = new MysqlDataSource(); - // setupDataSource.setUrl("jdbc:mysql://localhost"); - // setupDataSource.setUser("sa"); - // } - // - // return setupDataSource; - // } - // - // @Override - // public void setUp() throws Exception - // { - // dropDatabase(); - // Connection connection = null; - // try - // { - // connection = getSetupDataSource().getConnection(); - // connection.prepareStatement("create database cdodb1").execute(); - // } - // catch (SQLException ignore) - // { - // - // } - // finally - // { - // connection.close(); - // } - // super.setUp(); - // } - // - // @Override - // protected DataSource createDataSource() - // { - // dataSource = new MysqlDataSource(); - // dataSource.setUrl("jdbc:mysql://localhost/cdodb1"); - // dataSource.setUser("sa"); - // return dataSource; - // } - // - // @Override - // public void tearDown() throws Exception - // { - // super.tearDown(); - // dropDatabase(); - // } - // - // private void dropDatabase() throws Exception - // { - // Connection connection = null; - // try - // { - // connection = getSetupDataSource().getConnection(); - // connection.prepareStatement("DROP database cdodb1").execute(); - // } - // catch (SQLException ignore) - // { - // - // } - // finally - // { - // connection.close(); - // } - // } - // - // public static class Stmt extends Mysql - // { - // private static final long serialVersionUID = 1L; - // - // public static final Stmt INSTANCE = new Stmt("MysqlHorizontalStmt"); - // - // public Stmt(String name) - // { - // super(name); - // } - // - // @Override - // protected IJDBCDelegateProvider createDelegateProvider() - // { - // return CDODBUtil.createStatementJDBCDelegateProvider(); - // } - // } - // - // public static class PrepStmt extends Mysql - // { - // private static final long serialVersionUID = 1L; - // - // public static final PrepStmt INSTANCE = new PrepStmt("MysqlHorizontalPrepStmt"); - // - // public PrepStmt(String name) - // { - // super(name); - // } - // - // @Override - // protected IJDBCDelegateProvider createDelegateProvider() - // { - // return CDODBUtil.createPreparedStatementJDBCDelegateProvider(); - // } - // } - // } + } } - } diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/Scenario.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/Scenario.java index 25a4a7b079..a37437d150 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/Scenario.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/Scenario.java @@ -179,10 +179,28 @@ public class Scenario implements IScenario public synchronized void setUp() throws Exception { - getContainerConfig().setUp(); - getRepositoryConfig().setUp(); - getSessionConfig().setUp(); - getModelConfig().setUp(); + try + { + getContainerConfig().setUp(); + } + finally + { + try + { + getRepositoryConfig().setUp(); + } + finally + { + try + { + getSessionConfig().setUp(); + } + finally + { + getModelConfig().setUp(); + } + } + } } public synchronized void tearDown() throws Exception diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/SessionConfig.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/SessionConfig.java index b64be0a821..0408de451f 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/SessionConfig.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/config/impl/SessionConfig.java @@ -138,16 +138,19 @@ public abstract class SessionConfig extends Config implements ISessionConfig { try { - for (CDOSession session : sessions) + if (sessions != null) { - session.removeListener(sessionListener); - LifecycleUtil.deactivate(session); + for (CDOSession session : sessions) + { + session.removeListener(sessionListener); + LifecycleUtil.deactivate(session); + } + + sessions.clear(); + sessions = null; } sessionListener = null; - sessions.clear(); - sessions = null; - stopTransport(); super.tearDown(); } diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/store/verifier/AbstractDBStoreVerifier.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/store/verifier/AbstractDBStoreVerifier.java index 87f2babdb8..01af44df1a 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/store/verifier/AbstractDBStoreVerifier.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/store/verifier/AbstractDBStoreVerifier.java @@ -4,7 +4,7 @@ * 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: * Stefan Winkler - initial API and implementation */ @@ -45,7 +45,10 @@ public abstract class AbstractDBStoreVerifier public AbstractDBStoreVerifier(IRepository repository) { this.repository = repository; - assertTrue(repository.getStore() instanceof IDBStore); + if (repository != null) + { + assertTrue(repository.getStore() instanceof IDBStore); + } } protected IRepository getRepository() @@ -65,7 +68,15 @@ public abstract class AbstractDBStoreVerifier accessor = (IDBStoreAccessor)repository.getStore().getReader(null); } - return accessor.getJDBCDelegate().getStatement(); + try + { + return accessor.getConnection().createStatement(); + } + catch (SQLException ex) + { + ex.printStackTrace(); + return null; + } } protected List<IClassMapping> getClassMappings() diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/store/verifier/AuditDBStoreIntegrityVerifier.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/store/verifier/AuditDBStoreIntegrityVerifier.java index 06edaf44b4..6b8eb25883 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/store/verifier/AuditDBStoreIntegrityVerifier.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/store/verifier/AuditDBStoreIntegrityVerifier.java @@ -14,11 +14,11 @@ import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; import org.eclipse.emf.cdo.server.IRepository; -import org.eclipse.emf.cdo.server.IStore; import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; -import org.eclipse.emf.cdo.server.db.mapping.IReferenceMapping; +import org.eclipse.emf.cdo.server.db.mapping.IListMapping; import org.eclipse.emf.cdo.server.internal.db.CDODBSchema; -import org.eclipse.emf.cdo.server.internal.db.mapping.HorizontalMappingStrategy; +import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalAuditClassMapping; +import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalAuditMappingStrategy; import org.eclipse.net4j.util.collection.Pair; @@ -38,9 +38,7 @@ public class AuditDBStoreIntegrityVerifier extends AbstractDBStoreVerifier super(repo); // this is a verifier for auditing mode - assertTrue(getStore().getRevisionTemporality() == IStore.RevisionTemporality.AUDITING); - // ... and for horizontal class mapping - assertTrue(getStore().getMappingStrategy() instanceof HorizontalMappingStrategy); + assertTrue(getStore().getMappingStrategy() instanceof HorizontalAuditMappingStrategy); } @Override @@ -48,7 +46,7 @@ public class AuditDBStoreIntegrityVerifier extends AbstractDBStoreVerifier { for (IClassMapping mapping : getClassMappings()) { - if (mapping != null && mapping.getTable() != null) + if (mapping != null && mapping.getDBTables() != null) { verifyClassMapping(mapping); } @@ -64,7 +62,7 @@ public class AuditDBStoreIntegrityVerifier extends AbstractDBStoreVerifier private void verifyAtMostOneUnrevised(IClassMapping mapping) throws Exception { - String tableName = mapping.getTable().getName(); + String tableName = mapping.getDBTables().iterator().next().getName(); TRACER.format("verifyAtMostOneUnrevised: {0} ...", tableName); String sql = "SELECT " + CDODBSchema.ATTRIBUTES_ID + ", count(1) FROM " + tableName + " WHERE " @@ -90,7 +88,7 @@ public class AuditDBStoreIntegrityVerifier extends AbstractDBStoreVerifier */ private void verifyUniqueIdVersion(IClassMapping mapping) throws Exception { - String tableName = mapping.getTable().getName(); + String tableName = mapping.getDBTables().iterator().next().getName(); TRACER.format("verifyUniqueIdVersion: {0} ...", tableName); String sql = "SELECT " + CDODBSchema.ATTRIBUTES_ID + "," + CDODBSchema.ATTRIBUTES_VERSION + ", count(1) FROM " @@ -120,13 +118,14 @@ public class AuditDBStoreIntegrityVerifier extends AbstractDBStoreVerifier private void verifyReferences(IClassMapping mapping) throws Exception { - List<IReferenceMapping> referenceMappings = mapping.getReferenceMappings(); - if (referenceMappings == null) + List<IListMapping> listMappings = ((HorizontalAuditClassMapping)mapping).getListMappings(); + if (listMappings == null) { return; } - String tableName = mapping.getTable().getName(); + String tableName = mapping.getDBTables().iterator().next().getName(); + ; String sql = "SELECT " + CDODBSchema.ATTRIBUTES_ID + ", " + CDODBSchema.ATTRIBUTES_VERSION + " FROM " + tableName; ArrayList<Pair<Long, Integer>> idVersions = new ArrayList<Pair<Long, Integer>>(); @@ -144,24 +143,23 @@ public class AuditDBStoreIntegrityVerifier extends AbstractDBStoreVerifier resultSet.close(); } - for (IReferenceMapping refMapping : referenceMappings) + for (IListMapping listMapping : listMappings) { for (Pair<Long, Integer> idVersion : idVersions) { - verifyCorrectIndices(refMapping, idVersion.getElement1(), idVersion.getElement2()); + verifyCorrectIndices(listMapping, idVersion.getElement1(), idVersion.getElement2()); } } } - private void verifyCorrectIndices(IReferenceMapping refMapping, long id, int version) throws Exception + private void verifyCorrectIndices(IListMapping refMapping, long id, int version) throws Exception { - String tableName = refMapping.getTable().getName(); + String tableName = refMapping.getDBTables().iterator().next().getName(); TRACER.format("verifyUniqueIdVersion: {0} for ID{1}v{2} ...", tableName, id, version); - String sql = "SELECT " + CDODBSchema.REFERENCES_IDX + " FROM " + tableName + " WHERE " - + CDODBSchema.REFERENCES_SOURCE + "=" + id + " AND " + CDODBSchema.REFERENCES_VERSION + "=" + version - + " ORDER BY " + CDODBSchema.REFERENCES_IDX; + String sql = "SELECT " + CDODBSchema.LIST_IDX + " FROM " + tableName + " WHERE " + CDODBSchema.LIST_REVISION_ID + + "=" + id + " AND " + CDODBSchema.LIST_REVISION_VERSION + "=" + version + " ORDER BY " + CDODBSchema.LIST_IDX; TRACER.format(" Executing SQL: {0} ", sql); @@ -178,8 +176,8 @@ public class AuditDBStoreIntegrityVerifier extends AbstractDBStoreVerifier } catch (AssertionFailedError e) { - sqlDump("SELECT * FROM " + tableName + " WHERE " + CDODBSchema.REFERENCES_SOURCE + "=" + id + " AND " - + CDODBSchema.REFERENCES_VERSION + "=" + version + " ORDER BY " + CDODBSchema.REFERENCES_IDX); + sqlDump("SELECT * FROM " + tableName + " WHERE " + CDODBSchema.LIST_REVISION_ID + "=" + id + " AND " + + CDODBSchema.LIST_REVISION_VERSION + "=" + version + " ORDER BY " + CDODBSchema.LIST_IDX); throw e; } finally diff --git a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/store/verifier/NonAuditDBStoreIntegrityVerifier.java b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/store/verifier/NonAuditDBStoreIntegrityVerifier.java index 09e30a5128..261482905a 100644 --- a/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/store/verifier/NonAuditDBStoreIntegrityVerifier.java +++ b/plugins/org.eclipse.emf.cdo.tests/src/org/eclipse/emf/cdo/tests/store/verifier/NonAuditDBStoreIntegrityVerifier.java @@ -4,7 +4,7 @@ * 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: * Stefan Winkler - initial API and implementation */ @@ -16,9 +16,10 @@ import static junit.framework.Assert.assertTrue; import org.eclipse.emf.cdo.server.IRepository; import org.eclipse.emf.cdo.server.IStore; import org.eclipse.emf.cdo.server.db.mapping.IClassMapping; -import org.eclipse.emf.cdo.server.db.mapping.IReferenceMapping; +import org.eclipse.emf.cdo.server.db.mapping.IListMapping; import org.eclipse.emf.cdo.server.internal.db.CDODBSchema; -import org.eclipse.emf.cdo.server.internal.db.mapping.HorizontalMappingStrategy; +import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalNonAuditClassMapping; +import org.eclipse.emf.cdo.server.internal.db.mapping.horizontal.HorizontalNonAuditMappingStrategy; import org.eclipse.net4j.util.collection.Pair; @@ -38,7 +39,7 @@ public class NonAuditDBStoreIntegrityVerifier extends AbstractDBStoreVerifier // this is a verifier for non-auditing mode assertTrue(getStore().getRevisionTemporality() == IStore.RevisionTemporality.NONE); // ... and for horizontal class mapping - assertTrue(getStore().getMappingStrategy() instanceof HorizontalMappingStrategy); + assertTrue(getStore().getMappingStrategy() instanceof HorizontalNonAuditMappingStrategy); } @Override @@ -46,7 +47,7 @@ public class NonAuditDBStoreIntegrityVerifier extends AbstractDBStoreVerifier { for (IClassMapping mapping : getClassMappings()) { - if (mapping != null && mapping.getTable() != null) + if (mapping != null && mapping.getDBTables().size() > 0) { verifyClassMapping(mapping); } @@ -65,7 +66,7 @@ public class NonAuditDBStoreIntegrityVerifier extends AbstractDBStoreVerifier */ private void verifyNoUnrevisedRevisions(IClassMapping mapping) throws Exception { - String tableName = mapping.getTable().getName(); + String tableName = mapping.getDBTables().iterator().next().getName(); String sql = "SELECT count(1) FROM " + tableName + " WHERE " + CDODBSchema.ATTRIBUTES_REVISED + " <> 0"; ResultSet resultSet = getStatement().executeQuery(sql); try @@ -84,7 +85,7 @@ public class NonAuditDBStoreIntegrityVerifier extends AbstractDBStoreVerifier */ private void verifyUniqueId(IClassMapping mapping) throws Exception { - String tableName = mapping.getTable().getName(); + String tableName = mapping.getDBTables().iterator().next().getName(); String sql = "SELECT " + CDODBSchema.ATTRIBUTES_ID + ", count(1) FROM " + tableName + " GROUP BY " + CDODBSchema.ATTRIBUTES_ID; @@ -105,13 +106,13 @@ public class NonAuditDBStoreIntegrityVerifier extends AbstractDBStoreVerifier private void verifyReferences(IClassMapping mapping) throws Exception { - List<IReferenceMapping> referenceMappings = mapping.getReferenceMappings(); + List<IListMapping> referenceMappings = ((HorizontalNonAuditClassMapping)mapping).getListMappings(); if (referenceMappings == null) { return; } - String tableName = mapping.getTable().getName(); + String tableName = mapping.getDBTables().iterator().next().getName(); String sql = "SELECT " + CDODBSchema.ATTRIBUTES_ID + ", " + CDODBSchema.ATTRIBUTES_VERSION + " FROM " + tableName; ArrayList<Pair<Long, Integer>> idVersions = new ArrayList<Pair<Long, Integer>>(); @@ -129,43 +130,20 @@ public class NonAuditDBStoreIntegrityVerifier extends AbstractDBStoreVerifier resultSet.close(); } - for (IReferenceMapping refMapping : referenceMappings) + for (IListMapping refMapping : referenceMappings) { for (Pair<Long, Integer> idVersion : idVersions) { - verifyOnlyLatestReferences(refMapping, idVersion.getElement1(), idVersion.getElement2()); verifyCorrectIndices(refMapping, idVersion.getElement1()); } } } - /** - * Verify that no reference with sourceId == ID exist which have another version - */ - private void verifyOnlyLatestReferences(IReferenceMapping refMapping, long id, int version) throws Exception - { - String tableName = refMapping.getTable().getName(); - String sql = "SELECT count(1) FROM " + tableName + " WHERE " + CDODBSchema.REFERENCES_SOURCE + "=" + id + " AND " - + CDODBSchema.REFERENCES_VERSION + "<>" + version; - - ResultSet resultSet = getStatement().executeQuery(sql); - try - { - assertTrue(resultSet.next()); - assertEquals("Table " + tableName + " contains old references for id " + id + "(version should be " + version - + ")", 0, resultSet.getInt(1)); - } - finally - { - resultSet.close(); - } - } - - private void verifyCorrectIndices(IReferenceMapping refMapping, long id) throws Exception + private void verifyCorrectIndices(IListMapping refMapping, long id) throws Exception { - String tableName = refMapping.getTable().getName(); - String sql = "SELECT " + CDODBSchema.REFERENCES_IDX + " FROM " + tableName + " WHERE " - + CDODBSchema.REFERENCES_SOURCE + "=" + id + " ORDER BY " + CDODBSchema.REFERENCES_IDX; + String tableName = refMapping.getDBTables().iterator().next().getName(); + String sql = "SELECT " + CDODBSchema.LIST_IDX + " FROM " + tableName + " WHERE " + CDODBSchema.LIST_REVISION_ID + + "=" + id + " ORDER BY " + CDODBSchema.LIST_IDX; ResultSet resultSet = getStatement().executeQuery(sql); int indexShouldBe = 0; |