Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/NonAuditFeatureMapTableMapping.java')
-rw-r--r--org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/NonAuditFeatureMapTableMapping.java590
1 files changed, 590 insertions, 0 deletions
diff --git a/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/NonAuditFeatureMapTableMapping.java b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/NonAuditFeatureMapTableMapping.java
new file mode 100644
index 0000000000..0f8c57ea80
--- /dev/null
+++ b/org.eclipse.emf.cdo.server.db/src/org/eclipse/emf/cdo/server/internal/db/mapping/horizontal/NonAuditFeatureMapTableMapping.java
@@ -0,0 +1,590 @@
+/**
+ * Copyright (c) 2004 - 2011 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 bug 271444
+ * Christopher Albert - 254455: [DB] Support FeatureMaps bug 254455
+ * 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.id.CDOID;
+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.IDBStoreAccessor;
+import org.eclipse.emf.cdo.server.db.IIDHandler;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache;
+import org.eclipse.emf.cdo.server.db.IPreparedStatementCache.ReuseProbability;
+import org.eclipse.emf.cdo.server.db.mapping.IListMappingDeltaSupport;
+import org.eclipse.emf.cdo.server.db.mapping.IMappingStrategy;
+import org.eclipse.emf.cdo.server.db.mapping.ITypeMapping;
+import org.eclipse.emf.cdo.server.internal.db.CDODBSchema;
+
+import org.eclipse.net4j.db.DBException;
+import org.eclipse.net4j.db.DBType;
+import org.eclipse.net4j.db.DBUtil;
+import org.eclipse.net4j.util.ImplementationError;
+
+import org.eclipse.emf.ecore.EClass;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.ecore.util.FeatureMap;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Iterator;
+
+/**
+ * This is a featuremap-to-table mapping optimized for non-audit-mode. It doesn't care about version and has delta
+ * support.
+ *
+ * @author Eike Stepper
+ * @since 3.0
+ */
+public class NonAuditFeatureMapTableMapping extends AbstractFeatureMapTableMapping implements IListMappingDeltaSupport
+{
+ private FieldInfo[] keyFields;
+
+ private static final int TEMP_INDEX = -1;
+
+ private static final int UNBOUNDED_MOVE = -1;
+
+ private String sqlClear;
+
+ private String sqlUpdateIndex;
+
+ private String sqlUpdateValue;
+
+ private String sqlDeleteItem;
+
+ private String sqlMoveDownWithLimit;
+
+ private String sqlMoveDown;
+
+ private String sqlMoveUpWithLimit;
+
+ private String sqlMoveUp;
+
+ public NonAuditFeatureMapTableMapping(IMappingStrategy mappingStrategy, EClass eClass, EStructuralFeature feature)
+ {
+ super(mappingStrategy, eClass, feature);
+ initSQLStrings();
+ }
+
+ private void initSQLStrings()
+ {
+ // TODO: add key fields length support
+
+ StringBuilder builder = new StringBuilder();
+
+ // ----------- clear list -------------------------
+
+ builder.append("DELETE FROM "); //$NON-NLS-1$
+ builder.append(getTable());
+ builder.append(" WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+ builder.append("=? "); //$NON-NLS-1$
+
+ sqlClear = builder.toString();
+
+ builder.append(" AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append("=? "); //$NON-NLS-1$
+
+ sqlDeleteItem = builder.toString();
+
+ // ----------- update one item index --------------
+ builder = new StringBuilder();
+ builder.append("UPDATE "); //$NON-NLS-1$
+ builder.append(getTable());
+ builder.append(" SET "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append("=? "); //$NON-NLS-1$
+ builder.append(" WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append("=? "); //$NON-NLS-1$
+ sqlUpdateIndex = builder.toString();
+
+ // ----------- update one item value --------------
+ builder = new StringBuilder();
+ builder.append("UPDATE "); //$NON-NLS-1$
+ builder.append(getTable());
+ builder.append(" SET "); //$NON-NLS-1$
+
+ builder.append(CDODBSchema.FEATUREMAP_TAG);
+ builder.append("=?,"); //$NON-NLS-1$
+
+ Iterator<String> iter = getColumnNames().iterator();
+ while (iter.hasNext())
+ {
+ String column = iter.next();
+ builder.append(column);
+ builder.append("=?"); //$NON-NLS-1$
+
+ if (iter.hasNext())
+ {
+ builder.append(", "); //$NON-NLS-1$
+ }
+ }
+
+ builder.append(" WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append("=? "); //$NON-NLS-1$
+ sqlUpdateValue = builder.toString();
+
+ // ----------- move down --------------
+ builder = new StringBuilder();
+ builder.append("UPDATE "); //$NON-NLS-1$
+ builder.append(getTable());
+ builder.append(" SET "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append("="); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append("-1 WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append(">? "); //$NON-NLS-1$
+ sqlMoveDown = builder.toString();
+
+ builder.append(" AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append("<=?"); //$NON-NLS-1$
+ sqlMoveDownWithLimit = builder.toString();
+
+ // ----------- move up --------------
+ builder = new StringBuilder();
+ builder.append("UPDATE "); //$NON-NLS-1$
+ builder.append(getTable());
+ builder.append(" SET "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append("="); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append("+1 WHERE "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_REVISION_ID);
+ builder.append("=? AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append(">=? "); //$NON-NLS-1$
+ sqlMoveUp = builder.toString();
+
+ builder.append(" AND "); //$NON-NLS-1$
+ builder.append(CDODBSchema.FEATUREMAP_IDX);
+ builder.append("<?"); //$NON-NLS-1$
+ sqlMoveUpWithLimit = builder.toString();
+ }
+
+ @Override
+ protected FieldInfo[] getKeyFields()
+ {
+ if (keyFields == null)
+ {
+ DBType dbType = getMappingStrategy().getStore().getIDHandler().getDBType();
+ keyFields = new FieldInfo[] { new FieldInfo(CDODBSchema.FEATUREMAP_REVISION_ID, dbType) };
+ }
+
+ return keyFields;
+ }
+
+ @Override
+ protected void setKeyFields(PreparedStatement stmt, CDORevision revision) throws SQLException
+ {
+ getMappingStrategy().getStore().getIDHandler().setCDOID(stmt, 1, revision.getID());
+ }
+
+ public void objectDetached(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)
+ {
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+
+ try
+ {
+ stmt = statementCache.getPreparedStatement(sqlClear, ReuseProbability.HIGH);
+ getMappingStrategy().getStore().getIDHandler().setCDOID(stmt, 1, id);
+ DBUtil.update(stmt, false);
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e);
+ }
+ finally
+ {
+ statementCache.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, long timestamp)
+ {
+ move1up(accessor, id, index, UNBOUNDED_MOVE);
+ insertValue(accessor, id, index, value, timestamp);
+ }
+
+ private void insertValue(IDBStoreAccessor accessor, CDOID id, int index, Object value, long timestamp)
+ {
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+
+ try
+ {
+ FeatureMap.Entry entry = (FeatureMap.Entry)value;
+ EStructuralFeature entryFeature = entry.getEStructuralFeature();
+ CDOID tag = getTagByFeature(entryFeature, timestamp);
+ String columnName = getColumnName(tag);
+
+ String sql = sqlInsert;
+
+ stmt = statementCache.getPreparedStatement(sql, ReuseProbability.HIGH);
+
+ idHandler.setCDOID(stmt, 1, id);
+ int column = getKeyFields().length + 1;
+
+ for (int i = 0; i < getColumnNames().size(); i++)
+ {
+ if (getColumnNames().get(i).equals(columnName))
+ {
+ getTypeMapping(tag).setValue(stmt, column++, entry.getValue());
+ }
+ else
+ {
+ stmt.setNull(column++, getDBTypes().get(i).getCode());
+ }
+ }
+
+ stmt.setInt(column++, index);
+ idHandler.setCDOID(stmt, column++, tag);
+
+ DBUtil.update(stmt, true);
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e);
+ }
+ finally
+ {
+ statementCache.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)
+ {
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+
+ try
+ {
+ stmt = statementCache.getPreparedStatement(sqlUpdateIndex, ReuseProbability.HIGH);
+ stmt.setInt(1, newIndex);
+ idHandler.setCDOID(stmt, 2, id);
+ stmt.setInt(3, oldIndex);
+ DBUtil.update(stmt, true);
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e);
+ }
+ finally
+ {
+ statementCache.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 remove
+ */
+ 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)
+ {
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+
+ try
+ {
+ stmt = statementCache.getPreparedStatement(upperIndex == UNBOUNDED_MOVE ? sqlMoveDown : sqlMoveDownWithLimit,
+ ReuseProbability.HIGH);
+
+ idHandler.setCDOID(stmt, 1, id);
+ stmt.setInt(2, index);
+ if (upperIndex != UNBOUNDED_MOVE)
+ {
+ stmt.setInt(3, upperIndex);
+ }
+
+ DBUtil.update(stmt, false);
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e);
+ }
+ finally
+ {
+ statementCache.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)
+ {
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+
+ try
+ {
+ stmt = statementCache.getPreparedStatement(upperIndex == UNBOUNDED_MOVE ? sqlMoveUp : sqlMoveUpWithLimit,
+ ReuseProbability.HIGH);
+ idHandler.setCDOID(stmt, 1, id);
+ stmt.setInt(2, index);
+ if (upperIndex != UNBOUNDED_MOVE)
+ {
+ stmt.setInt(3, upperIndex);
+ }
+
+ DBUtil.update(stmt, false);
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e);
+ }
+ finally
+ {
+ statementCache.releasePreparedStatement(stmt);
+ }
+ }
+
+ private void deleteItem(IDBStoreAccessor accessor, CDOID id, int index)
+ {
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+
+ try
+ {
+ stmt = statementCache.getPreparedStatement(sqlDeleteItem, ReuseProbability.HIGH);
+ idHandler.setCDOID(stmt, 1, id);
+ stmt.setInt(2, index);
+ DBUtil.update(stmt, true);
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e);
+ }
+ finally
+ {
+ statementCache.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, long timestamp)
+ {
+ IIDHandler idHandler = getMappingStrategy().getStore().getIDHandler();
+ IPreparedStatementCache statementCache = accessor.getStatementCache();
+ PreparedStatement stmt = null;
+
+ FeatureMap.Entry entry = (FeatureMap.Entry)value;
+ EStructuralFeature entryFeature = entry.getEStructuralFeature();
+ CDOID tag = getTagByFeature(entryFeature, timestamp);
+ String columnName = getColumnName(tag);
+ ITypeMapping mapping = getTypeMapping(tag);
+
+ try
+ {
+ stmt = statementCache.getPreparedStatement(sqlUpdateValue, ReuseProbability.HIGH);
+ idHandler.setCDOID(stmt, 1, tag);
+ int column = 2;
+
+ for (int i = 0; i < getColumnNames().size(); i++)
+ {
+ if (getColumnNames().get(i).equals(columnName))
+ {
+ mapping.setValue(stmt, column++, entry.getValue());
+ }
+ else
+ {
+ stmt.setNull(column++, getDBTypes().get(i).getCode());
+ }
+ }
+
+ idHandler.setCDOID(stmt, column++, id);
+ stmt.setInt(column++, index);
+ DBUtil.update(stmt, true);
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e);
+ }
+ finally
+ {
+ statementCache.releasePreparedStatement(stmt);
+ }
+ }
+
+ public void processDelta(final IDBStoreAccessor accessor, final CDOID id, final int branchId, int oldVersion,
+ final int newVersion, final 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(), created);
+ }
+
+ public void visit(CDORemoveFeatureDelta delta)
+ {
+ removeListItem(accessor, id, delta.getIndex());
+ }
+
+ public void visit(CDOSetFeatureDelta delta)
+ {
+ setListItem(accessor, id, delta.getIndex(), delta.getValue(), created);
+ }
+
+ public void visit(CDOUnsetFeatureDelta delta)
+ {
+ if (delta.getFeature().isUnsettable())
+ {
+ throw new ImplementationError("Should not be called"); //$NON-NLS-1$
+ }
+
+ clearList(accessor, id);
+ }
+
+ public void visit(CDOListFeatureDelta delta)
+ {
+ throw new ImplementationError("Should not be called"); //$NON-NLS-1$
+ }
+
+ public void visit(CDOClearFeatureDelta delta)
+ {
+ clearList(accessor, id);
+ }
+
+ public void visit(CDOContainerFeatureDelta delta)
+ {
+ throw new ImplementationError("Should not be called"); //$NON-NLS-1$
+ }
+ };
+
+ for (CDOFeatureDelta delta : listDelta.getListChanges())
+ {
+ delta.accept(visitor);
+ }
+ }
+}

Back to the top