/**
   * @see TypeCompiler#resolveArithmeticOperation
   * @exception StandardException Thrown on error
   */
  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.
     */
    if (SanityManager.DEBUG)
      SanityManager.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())) {
      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) {
      throw StandardException.newException(
          SQLState.LANG_BINARY_OPERATOR_NOT_SUPPORTED,
          operator,
          leftType.getTypeId().getSQLTypeName(),
          rightType.getTypeId().getSQLTypeName());
    }

    /*
     ** 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);
  }