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 */
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;
return null;
}
+ public Id getId() {
+ return _id;
+ }
+
public Table getTable() {
return _table;
}
* 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());
}
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();
}
Index.EntryCursor entryCursor)
throws IOException
{
- super(table,
+ super(new Id(table, index), table,
new IndexPosition(entryCursor.getFirstEntry()),
new IndexPosition(entryCursor.getLastEntry()));
_entryCursor = entryCursor;
}
+ /**
+ * 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;
}
@Override
public String toString() {
- return getClass().getSimpleName() + " CurPosition " + _curPos +
- ", PrevPosition " + _prevPos;
+ return getClass().getSimpleName() + " " + _cursorId + " CurPosition " +
+ _curPos + ", PrevPosition " + _prevPos;
}
}
}
}
+ 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();
+ }
}