package net.notdot.bdbdatastore.server;
import java.util.Arrays;
import com.sleepycat.je.Cursor;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.JoinCursor;
import com.sleepycat.je.OperationStatus;
public class JoinedDatastoreResultSet extends AbstractDatastoreResultSet {
protected JoinCursor joinCursor = null;
protected Cursor[] cursors = null;
protected byte[][] startKeys = null;
protected boolean positioned;
public JoinedDatastoreResultSet(AppDatastore ds, QuerySpec query, byte[][] startKeys) throws DatabaseException {
super(ds, query);
this.startKeys = startKeys;
}
@Override
protected void closeCursor() throws DatabaseException {
// joinCursor will not be set, if the first equality filter is not found
if (this.joinCursor == null) return;
this.joinCursor.close();
this.joinCursor = null;
for(Cursor cur : this.cursors)
cur.close();
this.cursors = null;
}
@Override
protected void openCursor() throws DatabaseException {
positioned = false;
}
@Override
protected boolean readInternal() throws DatabaseException {
OperationStatus status;
if(!positioned) {
cursors = new Cursor[startKeys.length];
for(int i = 0; i < startKeys.length; i++) {
cursors[i] = ds.entities_by_property.openCursor(null, ds.getCursorConfig());
// Find the requested entry
DatabaseEntry key = new DatabaseEntry(startKeys[i]);
if(this.currentValue != null) {
// Reopening the cursor
DatabaseEntry value = new DatabaseEntry(currentValue.getData());
status = cursors[i].getSearchBothRange(key, value, null);
if(status == OperationStatus.SUCCESS) {
if(Arrays.equals(startKeys[i], key.getData())) {
// Skip the last record we read last time
status = cursors[i].getNextDup(key, value, null);
} else {
// We reopened a cursor, but couldn't find anything.
status = OperationStatus.NOTFOUND;
}
}
} else {
// First use
DatabaseEntry value = new DatabaseEntry();
status = cursors[i].getSearchKey(key, value, null);
}
// If we can't find it, the whole query returns 0 results
if(status != OperationStatus.SUCCESS) {
// The finally close should catch this
// Close any cursors we already opened
//for(int j = 0; j <= i; j++)
//cursors[i].close();
return false;
}
}
// Construct a join cursor
joinCursor = ds.entities.join(cursors, null);
positioned = true;
}
currentValue = new DatabaseEntry();
status = joinCursor.getNext(currentPKey, currentValue, null);
if(status == OperationStatus.SUCCESS) {
return true;
} else if(status == OperationStatus.NOTFOUND) {
return false;
} else {
throw new DatabaseException(String.format("Failed to advance query cursor: returned %s", status));
}
}
}