/* * This file is part of the HyperGraphDB source distribution. This is copyrighted software. For permitted * uses, licensing options and redistribution, please see the LicensingInformation file at the root level of * the distribution. * * Copyright (c) 2005-2010 Kobrix Software, Inc. All rights reserved. */ package org.hypergraphdb.storage.bje; import org.hypergraphdb.HGException; import org.hypergraphdb.storage.ByteArrayConverter; import org.hypergraphdb.util.HGUtils; import com.sleepycat.je.DatabaseEntry; import com.sleepycat.je.LockMode; import com.sleepycat.je.OperationStatus; import com.sleepycat.je.SecondaryCursor; /** * <p> * A result set based on a BerkeleyDB secondary cursor. That is, when a BerkeleyDB has a secondary DB, it is * possible to use the keys of the secondary DB to get primary key and data of the primary DB. This result set * returns primary keys based on secondary keys and it ignores the data (which usually will simply be the same * thing as the secondary key). * </p> * * @author Borislav Iordanov */ public class SingleValueResultSet<T> extends IndexResultSet<T> { private DatabaseEntry pkey = new DatabaseEntry(); public SingleValueResultSet(BJETxCursor cursor, DatabaseEntry keyIn, ByteArrayConverter<T> converter) { // // The following is bit hacky because we want to avoid some of the default behavior // of the super constructor, which is incorrect when the "values" we are interested in // are the DB's primary keys. So we duplicate its bebavior and override instantiation // of the current value. this.converter = converter; this.cursor = cursor; this.key = new DatabaseEntry(); if (keyIn != null) { assignData(key, keyIn.getData()); } try { ((SecondaryCursor)cursor.cursor()).getCurrent(key, pkey, data, LockMode.DEFAULT); next = converter.fromByteArray(pkey.getData(), pkey.getOffset(), pkey.getSize()); lookahead = 1; } catch (Throwable t) { throw new HGException(t); } } protected T advance() { try { OperationStatus status = ((SecondaryCursor)cursor.cursor()).getNextDup(key, pkey, data, LockMode.DEFAULT); if (status == OperationStatus.SUCCESS) return converter.fromByteArray(pkey.getData(), pkey.getOffset(), pkey.getSize()); else return null; } catch (Throwable t) { closeNoException(); throw new HGException(t); } } protected T back() { try { OperationStatus status = ((SecondaryCursor)cursor.cursor()).getPrevDup(key, pkey, data, LockMode.DEFAULT); if (status == OperationStatus.SUCCESS) return converter.fromByteArray(pkey.getData(), pkey.getOffset(), pkey.getSize()); else return null; } catch (Throwable t) { closeNoException(); throw new HGException(t); } } public GotoResult goTo(T value, boolean exactMatch) { byte[] B = converter.toByteArray(value); assignData(pkey, B); try { if (exactMatch) { if (((SecondaryCursor)cursor.cursor()).getSearchBoth(key, pkey, data, LockMode.DEFAULT) == OperationStatus.SUCCESS) { positionToCurrent(pkey.getData(), pkey.getOffset(), pkey.getSize()); return GotoResult.found; } else return GotoResult.nothing; } else { if (((SecondaryCursor)cursor.cursor()).getSearchBothRange(key, pkey, data, LockMode.DEFAULT) == OperationStatus.SUCCESS) { positionToCurrent(pkey.getData(), pkey.getOffset(), pkey.getSize()); return HGUtils.eq(B, pkey.getData()) ? GotoResult.found : GotoResult.close; } else return GotoResult.nothing; } } catch (Throwable t) { closeNoException(); throw new HGException(t); } } public boolean isOrdered() { return false; } }