]> source.dussan.org Git - jackcess.git/commitdiff
add ids to savepoints in order to verify legitimacy of restore attempts
authorJames Ahlborn <jtahlborn@yahoo.com>
Tue, 4 Dec 2007 04:17:40 +0000 (04:17 +0000)
committerJames Ahlborn <jtahlborn@yahoo.com>
Tue, 4 Dec 2007 04:17:40 +0000 (04:17 +0000)
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@198 f203690c-595d-4dc9-a70b-905162fa7fd2

src/java/com/healthmarketscience/jackcess/Cursor.java
test/src/java/com/healthmarketscience/jackcess/CursorTest.java

index 5cc45cf20d25b25d012a77d7ce3a7e61d308a9e7..4578a413b2d0942f02ab515db0c06022117df45d 100644 (file)
@@ -67,6 +67,8 @@ public abstract class Cursor implements Iterable<Map<String, Object>>
   private static final ScanPosition LAST_SCAN_POSITION =
     new ScanPosition(RowId.LAST_ROW_ID);
 
+  /** identifier for this cursor */
+  private final Id _id;
   /** owning table */
   private final Table _table;
   /** State used for reading the table rows */
@@ -81,7 +83,8 @@ public abstract class Cursor implements Iterable<Map<String, Object>>
   private Position _curPos;
   
 
-  protected Cursor(Table table, Position firstPos, Position lastPos) {
+  protected Cursor(Id id, Table table, Position firstPos, Position lastPos) {
+    _id = id;
     _table = table;
     _rowState = _table.createRowState();
     _firstPos = firstPos;
@@ -255,6 +258,10 @@ public abstract class Cursor implements Iterable<Map<String, Object>>
     return null;
   }
   
+  public Id getId() {
+    return _id;
+  }
+
   public Table getTable() {
     return _table;
   }
@@ -272,20 +279,26 @@ public abstract class Cursor implements Iterable<Map<String, Object>>
    * point in time by a call to {@link #restoreSavepoint}.
    * <p>
    * Savepoints may be used across different cursor instances for the same
-   * table, but they must be of the same type (index based vs. non-index
-   * based).
+   * table, but they must have the same {@link Id}.
    */
   public Savepoint getSavepoint() {
-    return new Savepoint(_curPos, _prevPos);
+    return new Savepoint(_id, _curPos, _prevPos);
   }
 
   /**
    * Moves the cursor to a savepoint previously returned from
    * {@link #getSavepoint}.
+   * @throws IllegalArgumentException if the given savepoint does not have a
+   *         cursorId equal to this cursor's id
    */
   public void restoreSavepoint(Savepoint savepoint)
     throws IOException
   {
+    if(!_id.equals(savepoint.getCursorId())) {
+      throw new IllegalArgumentException(
+          "Savepoint " + savepoint + " is not valid for this cursor with id "
+          + _id);
+    }
     restorePosition(savepoint.getCurrentPosition(),
                     savepoint.getPreviousPosition());
   }
@@ -884,7 +897,8 @@ public abstract class Cursor implements Iterable<Map<String, Object>>
     private final UsageMap.PageCursor _ownedPagesCursor;
     
     private TableScanCursor(Table table) {
-      super(table, FIRST_SCAN_POSITION, LAST_SCAN_POSITION);
+      super(new Id(table, null), table,
+            FIRST_SCAN_POSITION, LAST_SCAN_POSITION);
       _ownedPagesCursor = table.getOwnedPagesCursor();
     }
 
@@ -1045,7 +1059,7 @@ public abstract class Cursor implements Iterable<Map<String, Object>>
                         Index.EntryCursor entryCursor)
       throws IOException
     {
-      super(table,
+      super(new Id(table, index), table,
             new IndexPosition(entryCursor.getFirstEntry()),
             new IndexPosition(entryCursor.getLastEntry()));
       _entryCursor = entryCursor;
@@ -1217,19 +1231,59 @@ public abstract class Cursor implements Iterable<Map<String, Object>>
     
   }
 
+  /**
+   * Identifier for a cursor.  Will be equal to any other cursor of the same
+   * type for the same table.  Primarily used to check the validity of a
+   * Savepoint.
+   */
+  public static final class Id
+  {
+    private final String _tableName;
+    private final String _indexName;
+
+    private Id(Table table, Index index) {
+      _tableName = table.getName();
+      _indexName = ((index != null) ? index.getName() : null);
+    }
+
+    @Override
+    public int hashCode() {
+      return _tableName.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      return((this == o) ||
+             ((o != null) && (getClass() == o.getClass()) &&
+              ObjectUtils.equals(_tableName, ((Id)o)._tableName) &&
+              ObjectUtils.equals(_indexName, ((Id)o)._indexName)));
+    }
+
+    @Override
+    public String toString() {
+      return getClass().getSimpleName() + " " + _tableName + ":" + _indexName;
+    }
+  }
+
   /**
    * Value object which represents a complete save state of the cursor.
    */
   public static final class Savepoint
   {
+    private final Id _cursorId;
     private final Position _curPos;
     private final Position _prevPos;
 
-    private Savepoint(Position curPos, Position prevPos) {
+    private Savepoint(Id cursorId, Position curPos, Position prevPos) {
+      _cursorId = cursorId;
       _curPos = curPos;
       _prevPos = prevPos;
     }
 
+    public Id getCursorId() {
+      return _cursorId;
+    }
+
     public Position getCurrentPosition() {
       return _curPos;
     }
@@ -1240,8 +1294,8 @@ public abstract class Cursor implements Iterable<Map<String, Object>>
 
     @Override
     public String toString() {
-      return getClass().getSimpleName() + " CurPosition " + _curPos +
-        ", PrevPosition " + _prevPos;
+      return getClass().getSimpleName() + " " + _cursorId + " CurPosition " + 
+        _curPos + ", PrevPosition " + _prevPos;
     }
   }
   
index 590b9aa214e13b5b5197c8a45a4dedd8cb38fa80..87210ff5109c37a8638751630823583709193c1c 100644 (file)
@@ -649,5 +649,43 @@ public class CursorTest extends TestCase {
     }    
   }
 
+  public void testId() throws Exception
+  {
+    Database db = createTestIndexTable();
+
+    Table table = db.getTable("test");
+    Index idx = table.getIndexes().get(0);
+
+    Cursor tCursor = Cursor.createCursor(table);
+    Cursor iCursor = Cursor.createIndexCursor(table, idx);
+
+    Cursor.Savepoint tSave = tCursor.getSavepoint();
+    Cursor.Savepoint iSave = iCursor.getSavepoint();
+
+    tCursor.restoreSavepoint(tSave);
+    iCursor.restoreSavepoint(iSave);
+
+    try {
+      tCursor.restoreSavepoint(iSave);
+      fail("IllegalArgumentException should have been thrown");
+    } catch(IllegalArgumentException e) {
+      // success
+    }
+
+    try {
+      iCursor.restoreSavepoint(tSave);
+      fail("IllegalArgumentException should have been thrown");
+    } catch(IllegalArgumentException e) {
+      // success
+    }
+
+    Cursor tCursor2 = Cursor.createCursor(table);
+    Cursor iCursor2 = Cursor.createIndexCursor(table, idx);
+
+    tCursor2.restoreSavepoint(tSave);
+    iCursor2.restoreSavepoint(iSave);
+
+    db.close();
+  }
   
 }