package org.reldb.rel.v0.values;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import org.reldb.rel.exceptions.ExceptionSemantic;
import org.reldb.rel.v0.generator.Generator;
import org.reldb.rel.v0.storage.relvars.Relvar;
import org.reldb.rel.v0.vm.Context;
import org.reldb.rel.v0.vm.Operator;
/** Lightweight literal relation. Implements Relvar semantics so that relation-valued attributes can be updated. */
public class ValueRelationLiteral extends ValueRelation implements Relvar {
private static final long serialVersionUID = 0;
private int hashCode;
private HashSet<ValueTuple> lookupTuples;
private LinkedList<ValueTuple> iterationTuples;
// TODO - MEM - modify ValueRelationLiteral to avoid out-of-memory on high-cardinality relations.
public ValueRelationLiteral(Generator generator) {
super(generator);
purge();
}
/** Duplicates are rejected and return false. */
public boolean insert(ValueTuple tuple) {
if (lookupTuples.add(tuple)) {
iterationTuples.add(tuple);
hashCode += tuple.hashCode();
return true;
}
return false;
}
public void remove(ValueTuple tuple) {
if (lookupTuples.remove(tuple)) {
iterationTuples.remove(tuple);
hashCode -= tuple.hashCode();
}
}
@Override
public int hashCode() {
return hashCode;
}
@Override
public TupleIterator newIterator() {
return new TupleIterator() {
ValueTuple currentTuple;
Iterator<ValueTuple> i = iterationTuples.iterator();
public boolean hasNext() {
return i.hasNext();
}
public ValueTuple next() {
currentTuple = i.next();
currentTuple.loaded(getGenerator());
return currentTuple;
}
public void remove() {
i.remove();
iterationTuples.remove(currentTuple);
}
public void close() {
}
};
}
@Override
public long getCardinality() {
return lookupTuples.size();
}
@Override
public boolean contains(ValueTuple tuple) {
return lookupTuples.contains(tuple);
}
@Override
public TupleIterator iterator(Generator generator) {
return iterator();
}
@Override
public long getCardinality(Generator generator) {
return getCardinality();
}
@Override
public boolean contains(Generator generator, ValueTuple tuple) {
return contains(tuple);
}
@Override
public void setValue(ValueRelation relation) {
purge();
insert(getGenerator(), relation);
}
@Override
public long insert(Generator generator, ValueTuple tuple) {
if (insert(tuple))
return 1;
return 0;
}
@Override
public long insert(Generator generator, ValueRelation relation) {
long insertCount = 0;
TupleIterator tuples = relation.iterator();
try {
while (tuples.hasNext())
insertCount += insert(generator, tuples.next());
} finally {
tuples.close();
}
return insertCount;
}
@Override
public long insertNoDuplicates(Generator generator, ValueRelation relation) {
long insertCount = 0;
TupleIterator tuples = relation.iterator();
try {
while (tuples.hasNext()) {
if (insert(generator, tuples.next()) == 0)
throw new ExceptionSemantic("RS0394: inserting tuple would attempt to insert a duplicate.");
insertCount++;
}
} finally {
tuples.close();
}
return insertCount;
}
@Override
public void purge() {
lookupTuples = new HashSet<ValueTuple>();
iterationTuples = new LinkedList<ValueTuple>();
hashCode = 0;
}
@Override
// TODO - note that this is essentially identical to a function in Table
public long delete(Context context, Operator whereTupleOperator) {
return delete(context.getGenerator(), new RelTupleFilter(context, whereTupleOperator));
}
// Update all tuples using a given TupleMap
// TODO - note that this is essentially identical to a function in Table
public long update(final Generator generator, final TupleMap map) {
return update(generator, new TupleFilter() {
public boolean filter(ValueTuple tuple) {
return true;
}
}, map);
}
@Override
// TODO - note that this is essentially identical to a function in Table
public long update(Context context, Operator updateTupleOperator) {
return update(context.getGenerator(), new RelTupleMap(context, updateTupleOperator));
}
@Override
// TODO - note that this is essentially identical to a function in Table
public long update(Context context, Operator whereTupleOperator, Operator updateTupleOperator) {
return update(context.getGenerator(), new RelTupleFilter(context, whereTupleOperator), new RelTupleMap(context, updateTupleOperator));
}
public long update(Generator generator, TupleFilter whereFilter, TupleMap updateMap) {
ValueRelationLiteral temp = new ValueRelationLiteral(generator);
long updateCount = 0;
TupleIterator iterator = iterator();
try {
while (iterator.hasNext()) {
ValueTuple tuple = iterator.next();
if (whereFilter.filter(tuple)) {
ValueTuple newTuple = updateMap.map(tuple);
iterator.remove();
ValueTuple data = (ValueTuple)newTuple.getSerializableClone();
temp.insert(data);
updateCount++;
}
}
} finally {
iterator.close();
}
iterator = temp.iterator();
try {
while (iterator.hasNext())
insert(iterator.next());
} finally {
iterator.close();
}
return updateCount;
}
@Override
public long delete(Generator generator, TupleFilter filter) {
long deleteCount = 0;
TupleIterator iterator = iterator();
try {
while (iterator.hasNext()) {
ValueTuple tuple = iterator.next();
if (filter.filter(tuple)) {
iterator.remove();
deleteCount++;
}
}
} finally {
iterator.close();
}
return deleteCount;
}
@Override
// TODO - note that this is identical to a function in Table
public long delete(Context context, ValueRelation tuplesToDelete, boolean errorIfNotIncluded) {
final HashMap<ValueTuple, Boolean> toDelete = new HashMap<ValueTuple, Boolean>();
Generator generator = context.getGenerator();
// index the tuplesToDelete into the toDelete index, which uses each tupleToDelete as a key and a Boolean as the value.
TupleIterator iterator = tuplesToDelete.iterator();
try {
while (iterator.hasNext())
toDelete.put(iterator.next(), Boolean.FALSE);
} finally {
iterator.close();
}
if (errorIfNotIncluded) {
// make sure every tuple in toDelete is found in this relvar (table) at least once.
TupleIterator relvarTupleIterator = iterator(generator);
try {
while (relvarTupleIterator.hasNext()) {
ValueTuple keyTuple = relvarTupleIterator.next();
if (toDelete.containsKey(keyTuple))
toDelete.put(keyTuple, Boolean.TRUE);
}
} finally {
relvarTupleIterator.close();
}
// make sure every entry in index is TRUE, i.e., has been found at least once
Collection<Boolean>values = toDelete.values();
Iterator<Boolean> valueIterator = values.iterator();
while (valueIterator.hasNext())
if (!valueIterator.next().booleanValue())
throw new ExceptionSemantic("RS0395: In I_DELETE, one or more specified tuples are not included in the relation-valued attribute.");
}
return delete(generator, new TupleFilter() {
public boolean filter(ValueTuple tuple) {
return toDelete.containsKey(tuple);
}
});
}
}