/* * Copyright (c) 2010-2016 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 - 249610: [DB] Support external references (Implementation) * Stefan Winkler - derived branch mapping from audit mapping * Stefan Winkler - Bug 329025: [DB] Support branching for range-based mapping strategy */ package org.eclipse.emf.cdo.server.internal.db.mapping.horizontal; import org.eclipse.emf.cdo.common.branch.CDOBranch; import org.eclipse.emf.cdo.common.branch.CDOBranchManager; import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; import org.eclipse.emf.cdo.common.branch.CDOBranchVersion; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.revision.CDOList; import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.common.revision.CDORevisionHandler; import org.eclipse.emf.cdo.common.revision.CDORevisionManager; 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.CDOSetFeatureDelta; import org.eclipse.emf.cdo.common.revision.delta.CDOUnsetFeatureDelta; import org.eclipse.emf.cdo.eresource.EresourcePackage; import org.eclipse.emf.cdo.server.IRepository; import org.eclipse.emf.cdo.server.IStoreAccessor.QueryXRefsContext; import org.eclipse.emf.cdo.server.db.IDBStoreAccessor; import org.eclipse.emf.cdo.server.db.IIDHandler; 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.IListMapping; 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.bundle.OM; import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch; import org.eclipse.emf.cdo.spi.common.commit.CDOChangeSetSegment; import org.eclipse.emf.cdo.spi.common.revision.DetachedCDORevision; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta; import org.eclipse.emf.cdo.spi.server.InternalRepository; import org.eclipse.net4j.db.DBException; import org.eclipse.net4j.db.DBType; import org.eclipse.net4j.db.DBUtil; import org.eclipse.net4j.db.IDBPreparedStatement; import org.eclipse.net4j.db.IDBPreparedStatement.ReuseProbability; import org.eclipse.net4j.db.ddl.IDBField; import org.eclipse.net4j.db.ddl.IDBTable; import org.eclipse.net4j.util.ImplementationError; 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.ResultSet; import java.sql.SQLException; import java.util.HashSet; import java.util.Map; import java.util.Set; /** * @author Eike Stepper * @author Stefan Winkler * @since 3.0 */ public class HorizontalBranchingClassMapping extends AbstractHorizontalClassMapping implements IClassMappingAuditSupport, IClassMappingDeltaSupport { /** * @author Stefan Winkler */ private class FeatureDeltaWriter implements CDOFeatureDeltaVisitor { private IDBStoreAccessor accessor; private long created; private CDOID id; private CDOBranch targetBranch; private int oldVersion; private int newVersion; private InternalCDORevision newRevision; public void process(IDBStoreAccessor accessor, InternalCDORevisionDelta delta, long created) { this.accessor = accessor; this.created = created; id = delta.getID(); oldVersion = delta.getVersion(); if (TRACER.isEnabled()) { TRACER.format("FeatureDeltaWriter: old version: {0}, new version: {1}", oldVersion, oldVersion + 1); //$NON-NLS-1$ } InternalCDORevision originalRevision = (InternalCDORevision)accessor.getTransaction().getRevision(id); newRevision = originalRevision.copy(); targetBranch = accessor.getTransaction().getBranch(); newRevision.adjustForCommit(targetBranch, created); newVersion = newRevision.getVersion(); // process revision delta tree delta.accept(this); if (newVersion != CDORevision.FIRST_VERSION) { reviseOldRevision(accessor, id, delta.getBranch(), newRevision.getTimeStamp() - 1); } writeValues(accessor, newRevision); } public void visit(CDOMoveFeatureDelta delta) { throw new ImplementationError("Should not be called"); //$NON-NLS-1$ } public void visit(CDOAddFeatureDelta delta) { throw new ImplementationError("Should not be called"); //$NON-NLS-1$ } public void visit(CDORemoveFeatureDelta delta) { throw new ImplementationError("Should not be called"); //$NON-NLS-1$ } public void visit(CDOSetFeatureDelta delta) { delta.applyTo(newRevision); } public void visit(CDOUnsetFeatureDelta delta) { delta.applyTo(newRevision); } public void visit(CDOListFeatureDelta delta) { delta.applyTo(newRevision); IListMappingDeltaSupport listMapping = (IListMappingDeltaSupport)getListMapping(delta.getFeature()); listMapping.processDelta(accessor, id, targetBranch.getID(), oldVersion, newVersion, created, delta); } public void visit(CDOClearFeatureDelta delta) { throw new ImplementationError("Should not be called"); //$NON-NLS-1$ } public void visit(CDOContainerFeatureDelta delta) { delta.applyTo(newRevision); } } private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, HorizontalBranchingClassMapping.class); private String sqlInsertAttributes; private String sqlSelectCurrentAttributes; private String sqlSelectAllObjectIDs; private String sqlSelectAttributesByTime; private String sqlSelectAttributesByVersion; private String sqlReviseAttributes; private String sqlSelectForHandle; private String sqlSelectForChangeSet; private String sqlRawDeleteAttributes; private ThreadLocal<FeatureDeltaWriter> deltaWriter = new ThreadLocal<FeatureDeltaWriter>() { @Override protected FeatureDeltaWriter initialValue() { return new FeatureDeltaWriter(); } }; public HorizontalBranchingClassMapping(AbstractHorizontalMappingStrategy mappingStrategy, EClass eClass) { super(mappingStrategy, eClass); initSQLStrings(); } @Override protected IDBField addBranchField(IDBTable table) { return table.addField(ATTRIBUTES_BRANCH, DBType.INTEGER, true); } private void initSQLStrings() { // ----------- Select Revision --------------------------- StringBuilder builder = new StringBuilder(); builder.append("SELECT "); //$NON-NLS-1$ builder.append(ATTRIBUTES_VERSION); builder.append(", "); //$NON-NLS-1$ builder.append(ATTRIBUTES_CREATED); builder.append(", "); //$NON-NLS-1$ builder.append(ATTRIBUTES_REVISED); builder.append(", "); //$NON-NLS-1$ builder.append(ATTRIBUTES_RESOURCE); builder.append(", "); //$NON-NLS-1$ builder.append(ATTRIBUTES_CONTAINER); builder.append(", "); //$NON-NLS-1$ builder.append(ATTRIBUTES_FEATURE); appendTypeMappingNames(builder, getValueMappings()); appendFieldNames(builder, getUnsettableFields()); appendFieldNames(builder, getListSizeFields()); builder.append(" FROM "); //$NON-NLS-1$ builder.append(getTable()); builder.append(" WHERE "); //$NON-NLS-1$ builder.append(ATTRIBUTES_ID); builder.append("=? AND "); //$NON-NLS-1$ builder.append(ATTRIBUTES_BRANCH); builder.append("=? AND ("); //$NON-NLS-1$ String sqlSelectAttributesPrefix = builder.toString(); builder.append(ATTRIBUTES_REVISED); builder.append("=0)"); //$NON-NLS-1$ sqlSelectCurrentAttributes = builder.toString(); builder = new StringBuilder(sqlSelectAttributesPrefix); builder.append(ATTRIBUTES_CREATED); builder.append("<=? AND ("); //$NON-NLS-1$ builder.append(ATTRIBUTES_REVISED); builder.append("=0 OR "); //$NON-NLS-1$ builder.append(ATTRIBUTES_REVISED); builder.append(">=?))"); //$NON-NLS-1$ sqlSelectAttributesByTime = builder.toString(); builder = new StringBuilder(sqlSelectAttributesPrefix); builder.append("ABS("); //$NON-NLS-1$ builder.append(ATTRIBUTES_VERSION); builder.append(")=?)"); //$NON-NLS-1$ sqlSelectAttributesByVersion = builder.toString(); // ----------- Insert Attributes ------------------------- builder = new StringBuilder(); builder.append("INSERT INTO "); //$NON-NLS-1$ builder.append(getTable()); builder.append("("); //$NON-NLS-1$ builder.append(ATTRIBUTES_ID); builder.append(", "); //$NON-NLS-1$ builder.append(ATTRIBUTES_VERSION); builder.append(", "); //$NON-NLS-1$ builder.append(ATTRIBUTES_BRANCH); builder.append(", "); //$NON-NLS-1$ builder.append(ATTRIBUTES_CREATED); builder.append(", "); //$NON-NLS-1$ builder.append(ATTRIBUTES_REVISED); builder.append(", "); //$NON-NLS-1$ builder.append(ATTRIBUTES_RESOURCE); builder.append(", "); //$NON-NLS-1$ builder.append(ATTRIBUTES_CONTAINER); builder.append(", "); //$NON-NLS-1$ builder.append(ATTRIBUTES_FEATURE); appendTypeMappingNames(builder, getValueMappings()); appendFieldNames(builder, getUnsettableFields()); appendFieldNames(builder, getListSizeFields()); builder.append(") VALUES (?, ?, ?, ?, ?, ?, ?, ?"); //$NON-NLS-1$ appendTypeMappingParameters(builder, getValueMappings()); appendFieldParameters(builder, getUnsettableFields()); appendFieldParameters(builder, getListSizeFields()); builder.append(")"); //$NON-NLS-1$ sqlInsertAttributes = builder.toString(); // ----------- Update to set revised ---------------- builder = new StringBuilder("UPDATE "); //$NON-NLS-1$ builder.append(getTable()); builder.append(" SET "); //$NON-NLS-1$ builder.append(ATTRIBUTES_REVISED); builder.append("=? WHERE "); //$NON-NLS-1$ builder.append(ATTRIBUTES_ID); builder.append("=? AND "); //$NON-NLS-1$ builder.append(ATTRIBUTES_BRANCH); builder.append("=? AND "); //$NON-NLS-1$ builder.append(ATTRIBUTES_REVISED); builder.append("=0"); //$NON-NLS-1$ sqlReviseAttributes = builder.toString(); // ----------- Select all unrevised Object IDs ------ builder = new StringBuilder("SELECT "); //$NON-NLS-1$ builder.append(ATTRIBUTES_ID); builder.append(" FROM "); //$NON-NLS-1$ builder.append(getTable()); builder.append(" WHERE "); //$NON-NLS-1$ builder.append(ATTRIBUTES_REVISED); builder.append("=0"); //$NON-NLS-1$ sqlSelectAllObjectIDs = builder.toString(); // ----------- Select all revisions (for handleRevision) --- builder = new StringBuilder("SELECT "); //$NON-NLS-1$ builder.append(ATTRIBUTES_ID); builder.append(", "); //$NON-NLS-1$ builder.append(ATTRIBUTES_VERSION); builder.append(", "); //$NON-NLS-1$ builder.append(ATTRIBUTES_BRANCH); builder.append(" FROM "); //$NON-NLS-1$ builder.append(getTable()); sqlSelectForHandle = builder.toString(); // ----------- Select all revisions (for handleRevision) --- builder = new StringBuilder("SELECT DISTINCT "); //$NON-NLS-1$ builder.append(ATTRIBUTES_ID); builder.append(" FROM "); //$NON-NLS-1$ builder.append(getTable()); builder.append(" WHERE "); //$NON-NLS-1$ sqlSelectForChangeSet = builder.toString(); // ----------- Raw delete one specific revision ------ builder = new StringBuilder("DELETE FROM "); //$NON-NLS-1$ builder.append(getTable()); builder.append(" WHERE "); //$NON-NLS-1$ builder.append(ATTRIBUTES_ID); builder.append("=? AND "); //$NON-NLS-1$ builder.append(ATTRIBUTES_BRANCH); builder.append("=? AND "); //$NON-NLS-1$ builder.append(ATTRIBUTES_VERSION); builder.append("=?"); //$NON-NLS-1$ sqlRawDeleteAttributes = builder.toString(); } public boolean readRevision(IDBStoreAccessor accessor, InternalCDORevision revision, int listChunk) { long timeStamp = revision.getTimeStamp(); int branchID = revision.getBranch().getID(); IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); IDBPreparedStatement stmt = null; boolean success = false; try { if (timeStamp != CDOBranchPoint.UNSPECIFIED_DATE) { stmt = accessor.getDBConnection().prepareStatement(sqlSelectAttributesByTime, ReuseProbability.MEDIUM); idHandler.setCDOID(stmt, 1, revision.getID()); stmt.setInt(2, branchID); stmt.setLong(3, timeStamp); stmt.setLong(4, timeStamp); } else { stmt = accessor.getDBConnection().prepareStatement(sqlSelectCurrentAttributes, ReuseProbability.HIGH); idHandler.setCDOID(stmt, 1, revision.getID()); stmt.setInt(2, branchID); } // Read singleval-attribute table always (even without modeled attributes!) success = readValuesFromStatement(stmt, revision, accessor); } catch (SQLException ex) { throw new DBException(ex); } finally { DBUtil.close(stmt); } // Read multival tables only if revision exists if (success && revision.getVersion() >= CDOBranchVersion.FIRST_VERSION) { readLists(accessor, revision, listChunk); } return success; } public boolean readRevisionByVersion(IDBStoreAccessor accessor, InternalCDORevision revision, int listChunk) { IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlSelectAttributesByVersion, ReuseProbability.HIGH); boolean success = false; try { idHandler.setCDOID(stmt, 1, revision.getID()); stmt.setInt(2, revision.getBranch().getID()); stmt.setInt(3, revision.getVersion()); // Read singleval-attribute table always (even without modeled attributes!) success = readValuesFromStatement(stmt, revision, accessor); } catch (SQLException ex) { throw new DBException(ex); } finally { DBUtil.close(stmt); } // Read multival tables only if revision exists if (success) { readLists(accessor, revision, listChunk); } return success; } public IDBPreparedStatement createResourceQueryStatement(IDBStoreAccessor accessor, CDOID folderId, String name, boolean exactMatch, CDOBranchPoint branchPoint) { EStructuralFeature nameFeature = EresourcePackage.eINSTANCE.getCDOResourceNode_Name(); ITypeMapping nameValueMapping = getValueMapping(nameFeature); if (nameValueMapping == null) { throw new ImplementationError(nameFeature + " not found in ClassMapping " + this); //$NON-NLS-1$ } int branchID = branchPoint.getBranch().getID(); long timeStamp = branchPoint.getTimeStamp(); StringBuilder builder = new StringBuilder(); builder.append("SELECT "); //$NON-NLS-1$ builder.append(ATTRIBUTES_ID); builder.append(" FROM "); //$NON-NLS-1$ builder.append(getTable()); builder.append(" WHERE "); //$NON-NLS-1$ builder.append(ATTRIBUTES_VERSION); builder.append(">0 AND "); //$NON-NLS-1$ builder.append(ATTRIBUTES_BRANCH); builder.append("=? AND "); //$NON-NLS-1$ builder.append(ATTRIBUTES_CONTAINER); builder.append("=? AND "); //$NON-NLS-1$ builder.append(nameValueMapping.getField()); if (name == null) { builder.append(" IS NULL"); //$NON-NLS-1$ } else { builder.append(exactMatch ? " =?" : " LIKE ?"); //$NON-NLS-1$ //$NON-NLS-2$ } builder.append(" AND ("); //$NON-NLS-1$ if (timeStamp == CDORevision.UNSPECIFIED_DATE) { builder.append(ATTRIBUTES_REVISED); builder.append("=0)"); //$NON-NLS-1$ } else { builder.append(ATTRIBUTES_CREATED); builder.append("<=? AND ("); //$NON-NLS-1$ builder.append(ATTRIBUTES_REVISED); builder.append("=0 OR "); //$NON-NLS-1$ builder.append(ATTRIBUTES_REVISED); builder.append(">=?))"); //$NON-NLS-1$ } IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(builder.toString(), ReuseProbability.MEDIUM); try { int column = 1; stmt.setInt(column++, branchID); idHandler.setCDOID(stmt, column++, folderId); if (name != null) { String queryName = exactMatch ? name : name + "%"; //$NON-NLS-1$ nameValueMapping.setValue(stmt, column++, queryName); } if (timeStamp != CDORevision.UNSPECIFIED_DATE) { stmt.setLong(column++, timeStamp); stmt.setLong(column++, timeStamp); } if (TRACER.isEnabled()) { TRACER.format("Created Resource Query: {0}", stmt.toString()); //$NON-NLS-1$ } return stmt; } catch (Throwable ex) { DBUtil.close(stmt); // only release on error throw new DBException(ex); } } public IDBPreparedStatement createObjectIDStatement(IDBStoreAccessor accessor) { if (TRACER.isEnabled()) { TRACER.format("Created ObjectID Statement : {0}", sqlSelectAllObjectIDs); //$NON-NLS-1$ } return accessor.getDBConnection().prepareStatement(sqlSelectAllObjectIDs, ReuseProbability.HIGH); } @Override protected final void writeValues(IDBStoreAccessor accessor, InternalCDORevision revision) { IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlInsertAttributes, ReuseProbability.HIGH); try { int column = 1; idHandler.setCDOID(stmt, column++, revision.getID()); stmt.setInt(column++, revision.getVersion()); stmt.setInt(column++, revision.getBranch().getID()); stmt.setLong(column++, revision.getTimeStamp()); stmt.setLong(column++, revision.getRevised()); idHandler.setCDOID(stmt, column++, revision.getResourceID()); idHandler.setCDOID(stmt, column++, (CDOID)revision.getContainerID()); stmt.setInt(column++, revision.getContainingFeatureID()); int isSetCol = column + getValueMappings().size(); for (ITypeMapping mapping : getValueMappings()) { EStructuralFeature feature = mapping.getFeature(); if (feature.isUnsettable()) { if (revision.getValue(feature) == null) { stmt.setBoolean(isSetCol++, false); // also set value column to default value mapping.setDefaultValue(stmt, column++); continue; } stmt.setBoolean(isSetCol++, true); } mapping.setValueFromRevision(stmt, column++, revision); } Map<EStructuralFeature, IDBField> listSizeFields = getListSizeFields(); if (listSizeFields != null) { // isSetCol now points to the first listTableSize-column column = isSetCol; for (EStructuralFeature feature : listSizeFields.keySet()) { CDOList list = revision.getList(feature); stmt.setInt(column++, list.size()); } } DBUtil.update(stmt, true); } catch (SQLException e) { throw new DBException(e); } finally { DBUtil.close(stmt); } } @Override protected void detachAttributes(IDBStoreAccessor accessor, CDOID id, int version, CDOBranch branch, long timeStamp, OMMonitor mon) { IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlInsertAttributes, ReuseProbability.HIGH); try { int column = 1; idHandler.setCDOID(stmt, column++, id); stmt.setInt(column++, -version); // cdo_version stmt.setInt(column++, branch.getID()); stmt.setLong(column++, timeStamp); // cdo_created stmt.setLong(column++, CDOBranchPoint.UNSPECIFIED_DATE); // cdo_revised idHandler.setCDOID(stmt, column++, CDOID.NULL); // resource idHandler.setCDOID(stmt, column++, CDOID.NULL); // container stmt.setInt(column++, 0); // containing feature ID int isSetCol = column + getValueMappings().size(); for (ITypeMapping mapping : getValueMappings()) { EStructuralFeature feature = mapping.getFeature(); if (feature.isUnsettable()) { stmt.setBoolean(isSetCol++, false); } mapping.setDefaultValue(stmt, column++); } Map<EStructuralFeature, IDBField> listSizeFields = getListSizeFields(); if (listSizeFields != null) { // list size columns begin after isSet-columns column = isSetCol; for (int i = 0; i < listSizeFields.size(); i++) { stmt.setInt(column++, 0); } } DBUtil.update(stmt, true); } catch (SQLException e) { throw new DBException(e); } finally { DBUtil.close(stmt); } } @Override protected void rawDeleteAttributes(IDBStoreAccessor accessor, CDOID id, CDOBranch branch, int version, OMMonitor fork) { IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlRawDeleteAttributes, ReuseProbability.HIGH); try { idHandler.setCDOID(stmt, 1, id); stmt.setInt(2, branch.getID()); stmt.setInt(3, version); DBUtil.update(stmt, false); } catch (SQLException e) { throw new DBException(e); } finally { DBUtil.close(stmt); } } @Override protected void reviseOldRevision(IDBStoreAccessor accessor, CDOID id, CDOBranch branch, long revised) { IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sqlReviseAttributes, ReuseProbability.HIGH); try { stmt.setLong(1, revised); idHandler.setCDOID(stmt, 2, id); stmt.setInt(3, branch.getID()); DBUtil.update(stmt, false); // No row affected if old revision from other branch! } catch (SQLException e) { throw new DBException(e); } finally { DBUtil.close(stmt); } } @Override public void writeRevision(IDBStoreAccessor accessor, InternalCDORevision revision, boolean mapType, boolean revise, OMMonitor monitor) { Async async = null; monitor.begin(10); try { try { async = monitor.forkAsync(); CDOID id = revision.getID(); if (mapType) { // Put new objects into objectTypeMapper long timeStamp = revision.getTimeStamp(); EClass eClass = getEClass(); AbstractHorizontalMappingStrategy mappingStrategy = (AbstractHorizontalMappingStrategy)getMappingStrategy(); if (!mappingStrategy.putObjectType(accessor, timeStamp, id, eClass)) { mapType = false; } } if (!mapType && revise && revision.getVersion() > CDOBranchVersion.FIRST_VERSION) { // If revision is not the first one, revise the old revision long revised = revision.getTimeStamp() - 1; InternalCDOBranch branch = revision.getBranch(); reviseOldRevision(accessor, id, branch, revised); for (IListMapping mapping : getListMappings()) { mapping.objectDetached(accessor, id, revised); } } } finally { if (async != null) { async.stop(); } } try { async = monitor.forkAsync(); if (revision.isResourceNode()) { checkDuplicateResources(accessor, revision); } } finally { if (async != null) { async.stop(); } } try { // Write attribute table always (even without modeled attributes!) async = monitor.forkAsync(); writeValues(accessor, revision); } finally { if (async != null) { async.stop(); } } try { // Write list tables only if they exist async = monitor.forkAsync(7); if (getListMappings() != null) { writeLists(accessor, revision); } } finally { if (async != null) { async.stop(); } } } finally { monitor.done(); } } @Override public void handleRevisions(IDBStoreAccessor accessor, CDOBranch branch, long timeStamp, boolean exactTime, CDORevisionHandler handler) { StringBuilder builder = new StringBuilder(sqlSelectForHandle); boolean whereAppend = false; if (branch != null) { // TODO: Prepare this string literal builder.append(" WHERE "); //$NON-NLS-1$ builder.append(ATTRIBUTES_BRANCH); builder.append("=?"); //$NON-NLS-1$ whereAppend = true; } int timeParameters = 0; if (timeStamp != CDOBranchPoint.INVALID_DATE) { if (exactTime) { if (timeStamp != CDOBranchPoint.UNSPECIFIED_DATE) { builder.append(whereAppend ? " AND " : " WHERE "); //$NON-NLS-1$ //$NON-NLS-2$ builder.append(ATTRIBUTES_CREATED); builder.append("=?"); //$NON-NLS-1$ timeParameters = 1; } } else { builder.append(whereAppend ? " AND " : " WHERE "); //$NON-NLS-1$ //$NON-NLS-2$ if (timeStamp != CDOBranchPoint.UNSPECIFIED_DATE) { builder.append(ATTRIBUTES_CREATED); builder.append("<=? AND ("); //$NON-NLS-1$ builder.append(ATTRIBUTES_REVISED); builder.append("=0 OR "); //$NON-NLS-1$ builder.append(ATTRIBUTES_REVISED); builder.append(">=?)"); //$NON-NLS-1$ timeParameters = 2; } else { builder.append(ATTRIBUTES_REVISED); builder.append("=0"); //$NON-NLS-1$ } } } IRepository repository = accessor.getStore().getRepository(); CDORevisionManager revisionManager = repository.getRevisionManager(); CDOBranchManager branchManager = repository.getBranchManager(); IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(builder.toString(), ReuseProbability.LOW); ResultSet resultSet = null; try { int column = 1; if (branch != null) { stmt.setInt(column++, branch.getID()); } for (int i = 0; i < timeParameters; i++) { stmt.setLong(column++, timeStamp); } resultSet = stmt.executeQuery(); while (resultSet.next()) { CDOID id = idHandler.getCDOID(resultSet, 1); int version = resultSet.getInt(2); if (version >= CDOBranchVersion.FIRST_VERSION) { int branchID = resultSet.getInt(3); CDOBranchVersion branchVersion = branchManager.getBranch(branchID).getVersion(Math.abs(version)); InternalCDORevision revision = (InternalCDORevision)revisionManager.getRevisionByVersion(id, branchVersion, CDORevision.UNCHUNKED, true); if (!handler.handleRevision(revision)) { break; } } else { // Tell handler about detached IDs InternalCDORevision revision = new DetachedCDORevision(null, id, null, version, 0); if (!handler.handleRevision(revision)) { break; } } } } catch (SQLException e) { throw new DBException(e); } finally { DBUtil.close(resultSet); DBUtil.close(stmt); } } @Override public Set<CDOID> readChangeSet(IDBStoreAccessor accessor, CDOChangeSetSegment[] segments) { StringBuilder builder = new StringBuilder(sqlSelectForChangeSet); boolean isFirst = true; for (int i = 0; i < segments.length; i++) { if (isFirst) { isFirst = false; } else { builder.append(" OR "); //$NON-NLS-1$ } builder.append(ATTRIBUTES_BRANCH); builder.append("=? AND "); //$NON-NLS-1$ builder.append(ATTRIBUTES_CREATED); builder.append(">=?"); //$NON-NLS-1$ builder.append(" AND ("); //$NON-NLS-1$ builder.append(ATTRIBUTES_REVISED); builder.append("<=? OR "); //$NON-NLS-1$ builder.append(ATTRIBUTES_REVISED); builder.append("=0)"); //$NON-NLS-1$ } String sql = builder.toString(); IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler(); IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(sql, ReuseProbability.LOW); ResultSet resultSet = null; Set<CDOID> result = new HashSet<CDOID>(); try { int column = 1; for (CDOChangeSetSegment segment : segments) { stmt.setInt(column++, segment.getBranch().getID()); stmt.setLong(column++, segment.getTimeStamp()); stmt.setLong(column++, segment.getEndTime()); } resultSet = stmt.executeQuery(); while (resultSet.next()) { CDOID id = idHandler.getCDOID(resultSet, 1); result.add(id); } return result; } catch (SQLException e) { throw new DBException(e); } finally { DBUtil.close(resultSet); DBUtil.close(stmt); } } @Override protected String getListXRefsWhere(QueryXRefsContext context) { StringBuilder builder = new StringBuilder(); builder.append(ATTRIBUTES_BRANCH); builder.append("="); builder.append(context.getBranch().getID()); builder.append(" AND ("); long timeStamp = context.getTimeStamp(); if (timeStamp == CDORevision.UNSPECIFIED_DATE) { builder.append(ATTRIBUTES_REVISED); builder.append("=0)"); //$NON-NLS-1$ } else { builder.append(ATTRIBUTES_CREATED); builder.append("<="); builder.append(timeStamp); builder.append(" AND ("); //$NON-NLS-1$ builder.append(ATTRIBUTES_REVISED); builder.append("=0 OR "); //$NON-NLS-1$ builder.append(ATTRIBUTES_REVISED); builder.append(">="); builder.append(timeStamp); builder.append("))"); //$NON-NLS-1$ } return builder.toString(); } public void writeRevisionDelta(IDBStoreAccessor accessor, InternalCDORevisionDelta delta, long created, OMMonitor monitor) { monitor.begin(); try { if (accessor.getTransaction().getBranch() != delta.getBranch()) { // new branch -> decide, if branch should be copied if (((HorizontalBranchingMappingStrategyWithRanges)getMappingStrategy()).shallCopyOnBranch()) { doCopyOnBranch(accessor, delta, created, monitor.fork()); return; } } Async async = null; try { async = monitor.forkAsync(); FeatureDeltaWriter writer = deltaWriter.get(); writer.process(accessor, delta, created); } finally { if (async != null) { async.stop(); } } } finally { monitor.done(); } } private void doCopyOnBranch(IDBStoreAccessor accessor, InternalCDORevisionDelta delta, long created, OMMonitor monitor) { monitor.begin(2); try { InternalRepository repository = (InternalRepository)accessor.getStore().getRepository(); InternalCDORevision oldRevision = (InternalCDORevision)accessor.getTransaction().getRevision(delta.getID()); if (oldRevision == null) { throw new IllegalStateException("Origin revision not found for " + delta); } // Make sure all chunks are loaded repository.ensureChunks(oldRevision, CDORevision.UNCHUNKED); InternalCDORevision newRevision = oldRevision.copy(); newRevision.adjustForCommit(accessor.getTransaction().getBranch(), created); delta.applyTo(newRevision); monitor.worked(); writeRevision(accessor, newRevision, false, true, monitor.fork()); } finally { monitor.done(); } } }