/* This file is part of VoltDB.
* Copyright (C) 2008-2010 VoltDB L.L.C.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package org.voltdb.benchmark;
import org.voltdb.VoltTable;
import org.voltdb.VoltType;
import org.voltdb.types.ExpressionType;
/**
* Utility class for result set verification. Use the methods to create
* constraints and add the constraints to ClientMain by calling addConstraint().
*/
public class Verification {
/**
* The generic interface of constraint expression.
*/
public interface Expression {
public <T> Object evaluate(T tuple);
public <T> String toString(T tuple);
}
/**
* Class representing a constant.
*
* @param <T>
* Type of the constant
*/
public static class Constant<T> implements Expression {
private final T m_value;
public Constant(T value) {
m_value = value;
}
@Override
public <T1> T evaluate(T1 tuple) {
return m_value;
}
@Override
public String toString() {
return m_value.toString();
}
@Override
public <T1> String toString(T1 tuple) {
return toString();
}
}
/**
* Class representing a single value in a tuple.
*/
public static class Value implements Expression {
private final String m_name;
public Value(String name) {
m_name = name;
}
@Override
public <T> Object evaluate(T tuple) {
VoltTable row = (VoltTable) tuple;
VoltType type = row.getColumnType(row.getColumnIndex(m_name));
return row.get(m_name, type);
}
public <T> String toString(T tuple) {
return (m_name + "(" + evaluate(tuple) + ")");
}
}
protected abstract static class AbstractOperator implements Expression {
protected final Expression m_left;
protected final Expression m_right;
public AbstractOperator(Expression left, Expression right) {
m_left = left;
m_right = right;
}
}
/**
* Class representing the OR conjunction.
*/
public static class ConjunctionOr extends AbstractOperator {
public ConjunctionOr(Expression left, Expression right) {
super(left, right);
}
@Override
public <T> Object evaluate(T tuple) {
if ((Boolean) m_left.evaluate(tuple))
return true;
else
return m_right.evaluate(tuple);
}
@Override
public <T> String toString(T tuple) {
return ("(" + m_left.toString(tuple) + ") || ("
+ m_right.toString(tuple) + ")");
}
}
/**
* Class representing the AND conjunction.
*/
public static class ConjunctionAnd extends AbstractOperator {
public ConjunctionAnd(Expression left, Expression right) {
super(left, right);
}
@Override
public <T> Object evaluate(T tuple) {
return (Boolean) m_left.evaluate(tuple) && (Boolean) m_right.evaluate(tuple);
}
@Override
public <T> String toString(T tuple) {
return ("(" + m_left.toString(tuple) + ") && ("
+ m_right.toString(tuple) + ")");
}
}
protected abstract static class AbstractCompare extends AbstractOperator {
public AbstractCompare(Expression left, Expression right) {
super(left, right);
}
@SuppressWarnings("unchecked")
protected <T> int compare(T tuple) {
return ((Comparable<T>) m_left.evaluate(tuple)).compareTo((T) (m_right.evaluate(tuple)));
}
}
/**
* Class representing the equality comparison.
*/
public static class CompareEqual extends AbstractCompare {
public CompareEqual(Expression left, Expression right) {
super(left, right);
}
@Override
public <T> Object evaluate(T tuple) {
return compare(tuple) == 0;
}
@Override
public <T> String toString(T tuple) {
return ("(" + m_left.toString(tuple) + ") == ("
+ m_right.toString(tuple) + ")");
}
}
/**
* Class representing the inequality comparison.
*/
public static class CompareNotEqual extends AbstractCompare {
public CompareNotEqual(Expression left, Expression right) {
super(left, right);
}
@Override
public <T> Object evaluate(T tuple) {
return compare(tuple) != 0;
}
@Override
public <T> String toString(T tuple) {
return ("(" + m_left.toString(tuple) + ") != ("
+ m_right.toString(tuple) + ")");
}
}
/**
* Class representing the greater than comparison.
*/
public static class CompareGreaterThan extends AbstractCompare {
public CompareGreaterThan(Expression left, Expression right) {
super(left, right);
}
@Override
public <T> Object evaluate(T tuple) {
return compare(tuple) > 0;
}
@Override
public <T> String toString(T tuple) {
return ("(" + m_left.toString(tuple) + ") > ("
+ m_right.toString(tuple) + ")");
}
}
/**
* Class representing the greater than or equal to comparison.
*/
public static class CompareGreaterThanOrEqualTo extends AbstractCompare {
public CompareGreaterThanOrEqualTo(Expression left, Expression right) {
super(left, right);
}
@Override
public <T> Object evaluate(T tuple) {
return compare(tuple) >= 0;
}
@Override
public <T> String toString(T tuple) {
return ("(" + m_left.toString(tuple) + ") >= ("
+ m_right.toString(tuple) + ")");
}
}
/**
* Class representing the less than comparison.
*/
public static class CompareLessThan extends AbstractCompare {
public CompareLessThan(Expression left, Expression right) {
super(left, right);
}
@Override
public <T> Object evaluate(T tuple) {
return compare(tuple) < 0;
}
@Override
public <T> String toString(T tuple) {
return ("(" + m_left.toString(tuple) + ") < ("
+ m_right.toString(tuple) + ")");
}
}
/**
* Class representing the less than or equal to comparison.
*/
public static class CompareLessThanOrEqualTo extends AbstractCompare {
public CompareLessThanOrEqualTo(Expression left, Expression right) {
super(left, right);
}
@Override
public <T> Object evaluate(T tuple) {
return compare(tuple) <= 0;
}
@Override
public <T> String toString(T tuple) {
return ("(" + m_left.toString(tuple) + ") <= ("
+ m_right.toString(tuple) + ")");
}
}
/**
* Checks a single row against the constraint exp.
*
* @param exp
* The constraint to check against.
* @param row
* The row to check.
* @return true if the constraint is satisfied, false otherwise.
*/
public static boolean checkRow(Expression exp, VoltTable row) {
Object result = exp.evaluate(row);
if (!(result instanceof Boolean))
return false;
if (!((Boolean) result))
System.err.println("Failed check on: " + exp.toString(row));
return (Boolean) result;
}
/**
* Handy method for creating tuple value expression. The name of the column
* must exist in the target table so that the value can be read.
*
* @param name
* The name of the column.
* @return The expression representing the tuple value.
*/
public static Expression value(String name) {
return new Value(name);
}
/**
* Handy method for creating constant value expression.
*
* @param <T>
* The type of the constant.
* @param c
* The constant.
* @return The expression representing the constant value.
*/
public static <T> Expression constant(T c) {
return new Constant<T>(c);
}
/**
* Handy method for creating a comparison expression between two tuple
* values.
*
* @param type
* The type of comparison.
* @param left
* The name of the column of the left operand.
* @param right
* The name of the column of the right operand.
* @return The expression representing the comparison operation.
*/
public static Expression compareTupleValues(ExpressionType type,
String left,
String right) {
switch (type) {
case COMPARE_EQUAL:
return new CompareEqual(value(left), value(right));
case COMPARE_NOTEQUAL:
return new CompareNotEqual(value(left), value(right));
case COMPARE_GREATERTHAN:
return new CompareGreaterThan(value(left), value(right));
case COMPARE_GREATERTHANOREQUALTO:
return new CompareGreaterThanOrEqualTo(value(left), value(right));
case COMPARE_LESSTHAN:
return new CompareLessThan(value(left), value(right));
case COMPARE_LESSTHANOREQUALTO:
return new CompareLessThanOrEqualTo(value(left), value(right));
default:
throw new IllegalArgumentException("Type must be a comparison type");
}
}
/**
* Handy method for creating a comparison expression between a tuple value
* and a constant.
*
* @param <T>
* The type of the constant.
* @param type
* The type of comparison.
* @param left
* The name of the column of the left operand.
* @param right
* The constant.
* @return The expression representing the comparison operation.
*/
public static <T> Expression compareWithConstant(ExpressionType type,
String left,
T right) {
switch (type) {
case COMPARE_EQUAL:
return new CompareEqual(value(left), constant(right));
case COMPARE_NOTEQUAL:
return new CompareNotEqual(value(left), constant(right));
case COMPARE_GREATERTHAN:
return new CompareGreaterThan(value(left), constant(right));
case COMPARE_GREATERTHANOREQUALTO:
return new CompareGreaterThanOrEqualTo(value(left), constant(right));
case COMPARE_LESSTHAN:
return new CompareLessThan(value(left), constant(right));
case COMPARE_LESSTHANOREQUALTO:
return new CompareLessThanOrEqualTo(value(left), constant(right));
default:
throw new IllegalArgumentException("Type must be a comparison type");
}
}
/**
* Handy method for creating a conjunction expression. Multiple expressions
* can be given and they will all be joined with the same type.
*
* @param type
* The type of conjunction.
* @param exps
* The expressions to conjunct.
* @return The expression representing the conjunction.
*/
public static Expression conjunction(ExpressionType type, Expression... exps) {
Expression prev = null;
for (Expression exp : exps) {
if (prev != null) {
if (type == ExpressionType.CONJUNCTION_AND)
prev = new ConjunctionAnd(prev, exp);
else if (type == ExpressionType.CONJUNCTION_OR)
prev = new ConjunctionOr(prev, exp);
else
throw new IllegalArgumentException("Type must be a conjunction type");
} else {
prev = exp;
}
}
return prev;
}
/**
* Handy method for creating a expression testing if a tuple value is in
* the range [low, high].
*
* @param <T> The type of the constants.
* @param columnName The name of the column.
* @param low The lower bound constant.
* @param high The upper bound constant.
* @return The expression representing the range check.
*/
public static <T> Expression inRange(String columnName, T low, T high) {
return conjunction(ExpressionType.CONJUNCTION_AND,
compareWithConstant(ExpressionType.COMPARE_GREATERTHANOREQUALTO,
columnName, low),
compareWithConstant(ExpressionType.COMPARE_LESSTHANOREQUALTO,
columnName, high));
}
}