* This method only looks at a single node and will not recursively walk through the tree
*
* @param exp
*/
public static Pair<VoltType,Integer> calculateOutputValueTypes(AbstractExpression exp) {
VoltType retType = VoltType.INVALID;
int retSize = 0;
//
// First get the value types for the left and right children
//
ExpressionType exp_type = exp.getExpressionType();
AbstractExpression left_exp = exp.getLeft();
AbstractExpression right_exp = exp.getRight();
// -------------------------------
// CONSTANT/NULL/PARAMETER/TUPLE VALUES
// If our current expression is a Value node, then the QueryPlanner should have
// already figured out our types and there is nothing we need to do here
// -------------------------------
if (exp instanceof ConstantValueExpression ||
exp instanceof NullValueExpression ||
exp instanceof ParameterValueExpression ||
exp instanceof TupleValueExpression) {
//
// Nothing to do...
// We have to return what we already have to keep the QueryPlanner happy
//
retType = exp.getValueType();
retSize = exp.getValueSize();
// -------------------------------
// CONJUNCTION & COMPARISON
// If it is an Comparison or Conjunction node, then the output is always
// going to be either true or false
// -------------------------------
} else if (exp instanceof ComparisonExpression ||
exp instanceof ConjunctionExpression) {
//
// Make sure that they have the same number of output values
// NOTE: We do not need to do this check for COMPARE_IN
//
if (exp_type != ExpressionType.COMPARE_IN) {
//
// IMPORTANT:
// We are not handling the case where one of types is NULL. That is because we
// are only dealing with what the *output* type should be, not what the actual
// value is at execution time. There will need to be special handling code
// over on the ExecutionEngine to handle special cases for conjunctions with NULLs
// Therefore, it is safe to assume that the output is always going to be an
// integer (for booleans)
//
retType = VoltType.BIGINT;
retSize = retType.getLengthInBytesForFixedTypes();
//
// Everything else...
//
} else {
//
// TODO: Need to figure out how COMPARE_IN is going to work
//
throw new NotImplementedException("The '" + exp_type + "' Expression is not yet supported");
}
// -------------------------------
// AGGREGATES
// -------------------------------
} else if (exp instanceof AggregateExpression) {
switch (exp_type) {
case AGGREGATE_COUNT:
case AGGREGATE_COUNT_STAR:
//
// Always an integer
//
retType = VoltType.BIGINT;
retSize = retType.getLengthInBytesForFixedTypes();
break;
case AGGREGATE_AVG:
case AGGREGATE_MAX:
case AGGREGATE_MIN:
//
// It's always whatever the base type is
//
retType = left_exp.getValueType();
retSize = left_exp.getValueSize();
break;
case AGGREGATE_SUM:
if (left_exp.getValueType() == VoltType.TINYINT ||
left_exp.getValueType() == VoltType.SMALLINT ||
left_exp.getValueType() == VoltType.INTEGER) {
retType = VoltType.BIGINT;
retSize = retType.getLengthInBytesForFixedTypes();
} else {
retType = left_exp.getValueType();
retSize = left_exp.getValueSize();
}
break;
default:
throw new RuntimeException("ERROR: Invalid Expression type '" + exp_type + "' for Expression '" + exp + "'");
} // SWITCH
// -------------------------------
// EVERYTHING ELSE
// We need to look at our children and iterate through their
// output value types. We will match up the left and right output types
// at each position and call the method to figure out the cast type
// -------------------------------
} else {
VoltType left_type = left_exp.getValueType();
VoltType right_type = right_exp.getValueType();
VoltType cast_type = VoltType.INVALID;
//
// If there doesn't need to be a a right expression, then the type will always be a integer (for booleans)
//
if (!ExpressionUtil.needsRightExpression(exp)) {
//
// Make sure that they can cast the left-side expression with integer
// This is just a simple check to make sure that it is a numeric value
//
try {
// NOTE: in some brave new Decimal world, this check will be
// unnecessary. This code path is currently extremely unlikely
// anyway since we don't support any of the ways to get here
cast_type = VoltType.DECIMAL;
if (left_type != VoltType.DECIMAL)
{
VoltTypeUtil.determineImplicitCasting(left_type, VoltType.BIGINT);
cast_type = VoltType.BIGINT;
}
} catch (Exception ex) {
throw new RuntimeException("ERROR: Invalid type '" + left_type + "' used in a '" + exp_type + "' Expression");
}
//
// Otherwise, use VoltTypeUtil to figure out what to case the value to
//
} else {
cast_type = VoltTypeUtil.determineImplicitCasting(left_type, right_type);
}
if (cast_type == VoltType.INVALID) {
throw new RuntimeException("ERROR: Invalid output value type for Expression '" + exp + "'");
}
retType = cast_type;
// this may not always be safe
retSize = cast_type.getLengthInBytesForFixedTypes();
}
return new Pair<VoltType, Integer>(retType, retSize);
}