/**
   * Returns a SQL type "wide" enough to represent the result of the expression.<br>
   * A type is "wider" than the other if it can represent all its numeric values.<br>
   * Arithmetic operation terms are promoted to a type that can represent the resulting values and
   * avoid incorrect results.
   *
   * <p>FLOAT/REAL/DOUBLE used in an operation results in the same type, regardless of the type of
   * the other operand. When the result or the expression is converted to the type of the target
   * column for storage, an exception is thrown if the resulting value cannot be stored in the
   * column
   *
   * <p>Types narrower than INTEGER (int) are promoted to INTEGER. The order of promotion is as
   * follows
   *
   * <p>INTEGER, BIGINT, NUMERIC/DECIMAL
   *
   * <p>TINYINT and SMALLINT in any combination return INTEGER<br>
   * TINYINT/SMALLINT/INTEGER and INTEGER return BIGINT<br>
   * TINYINT/SMALLINT/INTEGER and BIGINT return NUMERIC/DECIMAL<br>
   * BIGINT and BIGINT return NUMERIC/DECIMAL<br>
   * REAL/FLOAT/DOUBLE and any type return REAL/FLOAT/DOUBLE<br>
   * NUMERIC/DECIMAL any type other than REAL/FLOAT/DOUBLE returns NUMERIC/DECIMAL<br>
   * In the case of NUMERIC/DECIMAL returned, the result precision is always large enough to express
   * any value result, while the scale depends on the operation:<br>
   * For ADD/SUBTRACT/DIVIDE, the scale is the larger of the two<br>
   * For MULTIPLY, the scale is the sum of the two scales<br>
   */
  public Type getCombinedType(Type other, int operation) throws HsqlException {

    if (other.typeCode == Types.SQL_ALL_TYPES) {
      other = this;
    }

    switch (operation) {
      case OpTypes.ADD:
        break;

      case OpTypes.MULTIPLY:
        if (other.isIntervalType()) {
          return other.getCombinedType(this, OpTypes.MULTIPLY);
        }
        break;

      case OpTypes.DIVIDE:
      case OpTypes.SUBTRACT:
      default:

        // all derivatives of equality ops or comparison ops
        return getAggregateType(other);
    }

    // resolution for ADD and MULTIPLY only
    if (!other.isNumberType()) {
      throw Error.error(ErrorCode.X_42562);
    }

    if (typeWidth == DOUBLE_WIDTH || ((NumberType) other).typeWidth == DOUBLE_WIDTH) {
      return Type.SQL_DOUBLE;
    }

    int sum = typeWidth + ((NumberType) other).typeWidth;

    if (sum <= INTEGER_WIDTH) {
      return Type.SQL_INTEGER;
    }

    if (sum <= BIGINT_WIDTH) {
      return Type.SQL_BIGINT;
    }

    int newScale;
    long newDigits;

    switch (operation) {

        //            case OpCodes.DIVIDE :
        //            case OpCodes.SUBTRACT :
      case OpTypes.ADD:
        newScale = scale > other.scale ? scale : other.scale;
        newDigits =
            precision - scale > other.precision - other.scale
                ? precision - scale
                : other.precision - other.scale;

        newDigits++;
        break;

      case OpTypes.MULTIPLY:
        newDigits = precision - scale + other.precision - other.scale;
        newScale = scale + other.scale;
        break;

      default:
        throw Error.runtimeError(ErrorCode.U_S0500, "NumberType");
    }

    return getNumberType(Types.SQL_DECIMAL, newScale + newDigits, newScale);
  }