blob: 6c9c84fa3473a6227c9e1eae1843cf324c8e18f5 [file] [log] [blame]
/*
* Copyright (c) 2010-2015 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 (SQLException 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("="); //$NON-NLS-1$
builder.append(CDOBranchPoint.UNSPECIFIED_DATE);
}
}
}
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);
handler.handleRevision(revision);
}
}
}
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("="); //$NON-NLS-1$
builder.append(CDOBranchPoint.UNSPECIFIED_DATE);
builder.append(")"); //$NON-NLS-1$
}
IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
IDBPreparedStatement stmt = accessor.getDBConnection().prepareStatement(builder.toString(), 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();
}
}
}