public DataTypeDescriptor resolveArithmeticOperation(DataTypeDescriptor leftType,
DataTypeDescriptor rightType,
String operator)
throws StandardException {
NumericTypeCompiler higherTC;
DataTypeDescriptor higherType;
boolean nullable;
int precision, scale, maximumWidth;
/*
** Check the right type to be sure it's a number. By convention,
** we call this method off the TypeId of the left operand, so if
** we get here, we know the left operand is a number.
*/
assert leftType.getTypeId().isNumericTypeId() : "The left type is supposed to be a number because we're resolving an arithmetic operator";
TypeId leftTypeId = leftType.getTypeId();
TypeId rightTypeId = rightType.getTypeId();
boolean supported = true;
if (!(rightTypeId.isNumericTypeId())) {
if (rightTypeId.isIntervalTypeId() &&
operator.equals(TypeCompiler.TIMES_OP)) {
// Let interval type resolve it.
return getTypeCompiler(rightTypeId).resolveArithmeticOperation(rightType, leftType, operator);
}
supported = false;
}
if (TypeCompiler.MOD_OP.equals(operator)) {
switch (leftTypeId.getJDBCTypeId()) {
case java.sql.Types.TINYINT:
case java.sql.Types.SMALLINT:
case java.sql.Types.INTEGER:
case java.sql.Types.BIGINT:
break;
default:
supported = false;
break;
}
switch (rightTypeId.getJDBCTypeId()) {
case java.sql.Types.TINYINT:
case java.sql.Types.SMALLINT:
case java.sql.Types.INTEGER:
case java.sql.Types.BIGINT:
break;
default:
supported = false;
break;
}
}
if (!supported) {
return super.resolveArithmeticOperation(leftType, rightType, operator);
}
/*
** Take left as the higher precedence if equal
*/
if (rightTypeId.typePrecedence() > leftTypeId.typePrecedence()) {
higherType = rightType;
higherTC = (NumericTypeCompiler)getTypeCompiler(rightTypeId);
}
else {
higherType = leftType;
higherTC = (NumericTypeCompiler)getTypeCompiler(leftTypeId);
}
/* The calculation of precision and scale should be based upon
* the type with higher precedence, which is going to be the result
* type, this is also to be consistent with maximumWidth. Beetle 3906.
*/
precision = higherTC.getPrecision(operator, leftType, rightType);
scale = higherTC.getScale(operator, leftType, rightType);
if (higherType.getTypeId().isDecimalTypeId()) {
maximumWidth = (scale > 0) ? precision + 3 : precision + 1;
/*
** Be careful not to overflow
*/
if (maximumWidth < precision) {
maximumWidth = Integer.MAX_VALUE;
}
}
else {
maximumWidth = higherType.getMaximumWidth();
}
/* The result is nullable if either side is nullable */
nullable = leftType.isNullable() || rightType.isNullable();
/*
** The higher type does not have the right nullability. Create a
** new DataTypeDescriptor that has the correct type and nullability.
**
** It's OK to call the implementation of the DataTypeDescriptorFactory
** here, because we're in the same package.
*/
return new DataTypeDescriptor(higherType.getTypeId(),
precision,
scale,
nullable,
maximumWidth);
}