Java Code Examples for org.apache.calcite.sql.type.SqlTypeUtil#isDecimal()

The following examples show how to use org.apache.calcite.sql.type.SqlTypeUtil#isDecimal() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: ReduceDecimalsRule.java    From Bats with Apache License 2.0 6 votes vote down vote up
@Override
public RexNode expand(RexCall call) {
    RelDataType retType = call.getType();
    int argCount = call.getOperands().size();
    ImmutableList.Builder<RexNode> opBuilder = ImmutableList.builder();

    for (int i = 0; i < argCount; i++) {
        // skip case conditions
        if (((i % 2) == 0) && (i != (argCount - 1))) {
            opBuilder.add(call.getOperands().get(i));
            continue;
        }
        RexNode expr = ensureType(retType, call.getOperands().get(i), false);
        if (SqlTypeUtil.isDecimal(retType)) {
            expr = decodeValue(expr);
        }
        opBuilder.add(expr);
    }

    RexNode newCall = builder.makeCall(retType, call.getOperator(), opBuilder.build());
    if (SqlTypeUtil.isDecimal(retType)) {
        newCall = encodeValue(newCall, retType);
    }
    return newCall;
}
 
Example 2
Source File: ReduceDecimalsRule.java    From Bats with Apache License 2.0 6 votes vote down vote up
@Override
public RexNode expand(RexCall call) {
    ImmutableList.Builder<RexNode> opBuilder = ImmutableList.builder();
    for (RexNode operand : call.getOperands()) {
        if (SqlTypeUtil.isNumeric(operand.getType())) {
            opBuilder.add(accessValue(operand));
        } else {
            opBuilder.add(operand);
        }
    }

    RexNode newCall = builder.makeCall(call.getType(), call.getOperator(), opBuilder.build());
    if (SqlTypeUtil.isDecimal(call.getType())) {
        return encodeValue(newCall, call.getType());
    } else {
        return newCall;
    }
}
 
Example 3
Source File: ReduceDecimalsRule.java    From Bats with Apache License 2.0 6 votes vote down vote up
@Override
public RexNode expand(RexCall call) {
    ImmutableList.Builder<RexNode> opBuilder = ImmutableList.builder();

    for (Ord<RexNode> operand : Ord.zip(call.getOperands())) {
        RelDataType targetType = getArgType(call, operand.i);
        if (SqlTypeUtil.isDecimal(operand.e.getType())) {
            opBuilder.add(ensureType(targetType, operand.e, true));
        } else {
            opBuilder.add(operand.e);
        }
    }

    RexNode ret = builder.makeCall(call.getType(), call.getOperator(), opBuilder.build());
    ret = ensureType(call.getType(), ret, true);
    return ret;
}
 
Example 4
Source File: ReduceDecimalsRule.java    From calcite with Apache License 2.0 6 votes vote down vote up
public RexNode expand(RexCall call) {
  RelDataType retType = call.getType();
  int argCount = call.operands.size();
  ImmutableList.Builder<RexNode> opBuilder = ImmutableList.builder();

  for (int i = 0; i < argCount; i++) {
    // skip case conditions
    if (((i % 2) == 0) && (i != (argCount - 1))) {
      opBuilder.add(call.operands.get(i));
      continue;
    }
    RexNode expr = ensureType(retType, call.operands.get(i), false);
    if (SqlTypeUtil.isDecimal(retType)) {
      expr = decodeValue(expr);
    }
    opBuilder.add(expr);
  }

  RexNode newCall =
      builder.makeCall(retType, call.getOperator(), opBuilder.build());
  if (SqlTypeUtil.isDecimal(retType)) {
    newCall = encodeValue(newCall, retType);
  }
  return newCall;
}
 
Example 5
Source File: ReduceDecimalsRule.java    From calcite with Apache License 2.0 6 votes vote down vote up
public RexNode expand(RexCall call) {
  ImmutableList.Builder<RexNode> opBuilder = ImmutableList.builder();
  for (RexNode operand : call.operands) {
    if (SqlTypeUtil.isNumeric(operand.getType())) {
      opBuilder.add(accessValue(operand));
    } else {
      opBuilder.add(operand);
    }
  }

  RexNode newCall =
      builder.makeCall(call.getType(), call.getOperator(),
          opBuilder.build());
  if (SqlTypeUtil.isDecimal(call.getType())) {
    return encodeValue(
        newCall,
        call.getType());
  } else {
    return newCall;
  }
}
 
Example 6
Source File: ReduceDecimalsRule.java    From calcite with Apache License 2.0 6 votes vote down vote up
public RexNode expand(RexCall call) {
  ImmutableList.Builder<RexNode> opBuilder = ImmutableList.builder();

  for (Ord<RexNode> operand : Ord.zip(call.operands)) {
    RelDataType targetType = getArgType(call, operand.i);
    if (SqlTypeUtil.isDecimal(operand.e.getType())) {
      opBuilder.add(ensureType(targetType, operand.e, true));
    } else {
      opBuilder.add(operand.e);
    }
  }

  RexNode ret =
      builder.makeCall(
          call.getType(),
          call.getOperator(),
          opBuilder.build());
  ret =
      ensureType(
          call.getType(),
          ret,
          true);
  return ret;
}
 
Example 7
Source File: RelDataTypeFactoryImpl.java    From Bats with Apache License 2.0 5 votes vote down vote up
/**
 * {@inheritDoc}
 *
 * <p>Implement RelDataTypeFactory with SQL 2003 compliant behavior. Let p1,
 * s1 be the precision and scale of the first operand Let p2, s2 be the
 * precision and scale of the second operand Let p, s be the precision and
 * scale of the result, Then the result type is a decimal with:
 *
 * <ul>
 * <li>p = p1 + p2</li>
 * <li>s = s1 + s2</li>
 * </ul>
 *
 * <p>p and s are capped at their maximum values
 *
 * @see Glossary#SQL2003 SQL:2003 Part 2 Section 6.26
 */
public RelDataType createDecimalProduct(
    RelDataType type1,
    RelDataType type2) {
  if (SqlTypeUtil.isExactNumeric(type1)
      && SqlTypeUtil.isExactNumeric(type2)) {
    if (SqlTypeUtil.isDecimal(type1)
        || SqlTypeUtil.isDecimal(type2)) {
      int p1 = type1.getPrecision();
      int p2 = type2.getPrecision();
      int s1 = type1.getScale();
      int s2 = type2.getScale();

      int scale = s1 + s2;
      scale = Math.min(scale, typeSystem.getMaxNumericScale());
      int precision = p1 + p2;
      precision =
          Math.min(
              precision,
              typeSystem.getMaxNumericPrecision());

      RelDataType ret;
      ret =
          createSqlType(
              SqlTypeName.DECIMAL,
              precision,
              scale);

      return ret;
    }
  }

  return null;
}
 
Example 8
Source File: RelDataTypeSystemImpl.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
@Override
public RelDataType deriveDecimalTruncateType(RelDataTypeFactory typeFactory, RelDataType type1,
  Integer scale2) {
  if (!SqlTypeUtil.isExactNumeric(type1) || !SqlTypeUtil.isDecimal(type1)) {
    return null;
  }

  ArrowType.Decimal finalPrecisionScale = OutputDerivation.getDecimalOutputTypeForTruncate(type1.getPrecision(),
    type1.getScale(), scale2);

  return typeFactory.createSqlType(SqlTypeName.DECIMAL, finalPrecisionScale.getPrecision(),
    finalPrecisionScale.getScale());
}
 
Example 9
Source File: RelDataTypeSystemImpl.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
@Override
public RelDataType deriveDecimalRoundType(RelDataTypeFactory typeFactory, RelDataType type1,
  Integer scale2) {
  if (!SqlTypeUtil.isExactNumeric(type1) || !SqlTypeUtil.isDecimal(type1)) {
    return null;
  }

  ArrowType.Decimal finalPrecisionScale = OutputDerivation.getDecimalOutputTypeForRound(type1.getPrecision(),
    type1.getScale(), scale2);

  return typeFactory.createSqlType(SqlTypeName.DECIMAL, finalPrecisionScale.getPrecision(),
    finalPrecisionScale.getScale());
}
 
Example 10
Source File: RelDataTypeSystemImpl.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
private RelDataType getDecimalReturnType(RelDataTypeFactory typeFactory, RelDataType type1, RelDataType type2, DecimalTypeUtil
  .OperationType operationType) {
  if (!SqlTypeUtil.isExactNumeric(type1) || !SqlTypeUtil.isExactNumeric(type2) || (!SqlTypeUtil
    .isDecimal(type1) && !SqlTypeUtil.isDecimal(type2))) {
    return null;
  } else {
    ArrowType.Decimal operand1 = new ArrowType.Decimal(type1.getPrecision(), type1.getScale());
    ArrowType.Decimal operand2 = new ArrowType.Decimal(type2.getPrecision(), type2.getScale());
    ArrowType.Decimal output = DecimalTypeUtil.getResultTypeForOperation(operationType, operand1,
      operand2);
    return typeFactory.createSqlType(SqlTypeName.DECIMAL, output.getPrecision(), output.getScale());
  }
}
 
Example 11
Source File: RelDataTypeSystem.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * Infers the return type of a decimal multiplication. Decimal
 * multiplication involves at least one decimal operand and requires both
 * operands to have exact numeric types.
 *
 * <p>The default implementation is SQL:2003 compliant.
 *
 * <p>Rules:
 *
 * <ul>
 * <li>Let p1, s1 be the precision and scale of the first operand</li>
 * <li>Let p2, s2 be the precision and scale of the second operand</li>
 * <li>Let p, s be the precision and scale of the result</li>
 * <li>Let d be the number of whole digits in the result</li>
 * <li>Then the result type is a decimal with:
 *   <ul>
 *   <li>p = p1 + p2)</li>
 *   <li>s = s1 + s2</li>
 *   </ul>
 * </li>
 * <li>p and s are capped at their maximum values</li>
 * </ul>
 *
 * <p>p and s are capped at their maximum values
 *
 * @see Glossary#SQL2003 SQL:2003 Part 2 Section 6.26
 *
 * @param typeFactory TypeFactory used to create output type
 * @param type1       Type of the first operand
 * @param type2       Type of the second operand
 * @return Result type for a decimal multiplication, or null if decimal
 * multiplication should not be applied to the operands
 */
default RelDataType deriveDecimalMultiplyType(RelDataTypeFactory typeFactory,
    RelDataType type1, RelDataType type2) {
  if (SqlTypeUtil.isExactNumeric(type1)
          && SqlTypeUtil.isExactNumeric(type2)) {
    if (SqlTypeUtil.isDecimal(type1)
            || SqlTypeUtil.isDecimal(type2)) {
      // Java numeric will always have invalid precision/scale,
      // use its default decimal precision/scale instead.
      type1 = RelDataTypeFactoryImpl.isJavaType(type1)
          ? typeFactory.decimalOf(type1)
          : type1;
      type2 = RelDataTypeFactoryImpl.isJavaType(type2)
          ? typeFactory.decimalOf(type2)
          : type2;
      int p1 = type1.getPrecision();
      int p2 = type2.getPrecision();
      int s1 = type1.getScale();
      int s2 = type2.getScale();

      int scale = s1 + s2;
      scale = Math.min(scale, getMaxNumericScale());
      int precision = p1 + p2;
      precision =
              Math.min(
                      precision,
                      getMaxNumericPrecision());

      RelDataType ret;
      ret = typeFactory.createSqlType(
                      SqlTypeName.DECIMAL,
                      precision,
                      scale);

      return ret;
    }
  }

  return null;
}
 
Example 12
Source File: AbstractTypeCoercion.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * Finds a wider type when one or both types are decimal type.
 * If the wider decimal type's precision/scale exceeds system limitation,
 * this rule will truncate the decimal type to the max precision/scale.
 * For decimal and fractional types, returns a decimal type
 * which has the higher precision of the two.
 *
 * <p>The default implementation depends on the max precision/scale of the type system,
 * you can override it based on the specific system requirement in
 * {@link org.apache.calcite.rel.type.RelDataTypeSystem}.
 */
public RelDataType getWiderTypeForDecimal(RelDataType type1, RelDataType type2) {
  if (!SqlTypeUtil.isDecimal(type1) && !SqlTypeUtil.isDecimal(type2)) {
    return null;
  }
  // For Calcite `DECIMAL` default to have max allowed precision,
  // so just return decimal type.
  // This is based on the RelDataTypeSystem implementation,
  // subclass should override it correctly.
  if (SqlTypeUtil.isNumeric(type1) && SqlTypeUtil.isNumeric(type2)) {
    return factory.leastRestrictive(ImmutableList.of(type1, type2));
  }
  return null;
}
 
Example 13
Source File: TypeCoercionImpl.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * For NUMERIC and STRING operands, cast STRING to data type of the other operand.
 **/
protected boolean binaryArithmeticWithStrings(
    SqlCallBinding binding,
    RelDataType left,
    RelDataType right) {
  // For expression "NUMERIC <OP> CHARACTER",
  // PostgreSQL and MS-SQL coerce the CHARACTER operand to NUMERIC,
  // i.e. for '9':VARCHAR(1) / 2: INT, '9' would be coerced to INTEGER,
  // while for '9':VARCHAR(1) / 3.3: DOUBLE, '9' would be coerced to DOUBLE.
  // They do not allow both CHARACTER operands for binary arithmetic operators.

  // MySQL and Oracle would coerce all the string operands to DOUBLE.

  // Keep sync with PostgreSQL and MS-SQL because their behaviors are more in
  // line with the SQL standard.
  if (SqlTypeUtil.isString(left) && SqlTypeUtil.isNumeric(right)) {
    // If the numeric operand is DECIMAL type, coerce the STRING operand to
    // max precision/scale DECIMAL.
    if (SqlTypeUtil.isDecimal(right)) {
      right = SqlTypeUtil.getMaxPrecisionScaleDecimal(factory);
    }
    return coerceOperandType(binding.getScope(), binding.getCall(), 0, right);
  } else if (SqlTypeUtil.isNumeric(left) && SqlTypeUtil.isString(right)) {
    if (SqlTypeUtil.isDecimal(left)) {
      left = SqlTypeUtil.getMaxPrecisionScaleDecimal(factory);
    }
    return coerceOperandType(binding.getScope(), binding.getCall(), 1, left);
  }
  return false;
}
 
Example 14
Source File: RexUtil.java    From Bats with Apache License 2.0 4 votes vote down vote up
/**
 * Determines whether a {@link RexCall} requires decimal expansion. It
 * usually requires expansion if it has decimal operands.
 *
 * <p>Exceptions to this rule are:
 *
 * <ul>
 * <li>isNull doesn't require expansion
 * <li>It's okay to cast decimals to and from char types
 * <li>It's okay to cast nulls as decimals
 * <li>Casts require expansion if their return type is decimal
 * <li>Reinterpret casts can handle a decimal operand
 * </ul>
 *
 * @param expr    expression possibly in need of expansion
 * @param recurse whether to check nested calls
 * @return whether the expression requires expansion
 */
public static boolean requiresDecimalExpansion(RexNode expr, boolean recurse) {
    if (!(expr instanceof RexCall)) {
        return false;
    }
    RexCall call = (RexCall) expr;

    boolean localCheck = true;
    switch (call.getKind()) {
    case REINTERPRET:
    case IS_NULL:
        localCheck = false;
        break;
    case CAST:
        RelDataType lhsType = call.getType();
        RelDataType rhsType = call.getOperands().get(0).getType();
        if (rhsType.getSqlTypeName() == SqlTypeName.NULL) {
            return false;
        }
        if (SqlTypeUtil.inCharFamily(lhsType) || SqlTypeUtil.inCharFamily(rhsType)) {
            localCheck = false;
        } else if (SqlTypeUtil.isDecimal(lhsType) && (lhsType != rhsType)) {
            return true;
        }
        break;
    default:
        localCheck = call.getOperator().requiresDecimalExpansion();
    }

    if (localCheck) {
        if (SqlTypeUtil.isDecimal(call.getType())) {
            // NOTE jvs 27-Mar-2007: Depending on the type factory, the
            // result of a division may be decimal, even though both inputs
            // are integer.
            return true;
        }
        for (int i = 0; i < call.getOperands().size(); i++) {
            if (SqlTypeUtil.isDecimal(call.getOperands().get(i).getType())) {
                return true;
            }
        }
    }
    return recurse && requiresDecimalExpansion(call.getOperands(), true);
}
 
Example 15
Source File: AbstractTypeCoercion.java    From calcite with Apache License 2.0 4 votes vote down vote up
/**
 * Determines common type for a comparison operator when one operand is String type and the
 * other is not. For date + timestamp operands, use timestamp as common type,
 * i.e. Timestamp(2017-01-01 00:00 ...) &gt; Date(2018) evaluates to be false.
 */
public RelDataType commonTypeForBinaryComparison(RelDataType type1, RelDataType type2) {
  SqlTypeName typeName1 = type1.getSqlTypeName();
  SqlTypeName typeName2 = type2.getSqlTypeName();

  if (typeName1 == null || typeName2 == null) {
    return null;
  }

  // DATETIME + CHARACTER -> DATETIME
  // REVIEW Danny 2019-09-23: There is some legacy redundant code in SqlToRelConverter
  // that coerce Datetime and CHARACTER comparison.
  if (SqlTypeUtil.isCharacter(type1) && SqlTypeUtil.isDatetime(type2)) {
    return type2;
  }

  if (SqlTypeUtil.isDatetime(type1) && SqlTypeUtil.isCharacter(type2)) {
    return type1;
  }

  // DATE + TIMESTAMP -> TIMESTAMP
  if (SqlTypeUtil.isDate(type1) && SqlTypeUtil.isTimestamp(type2)) {
    return type2;
  }

  if (SqlTypeUtil.isDate(type2) && SqlTypeUtil.isTimestamp(type1)) {
    return type1;
  }

  if (SqlTypeUtil.isString(type1) && typeName2 == SqlTypeName.NULL) {
    return type1;
  }

  if (typeName1 == SqlTypeName.NULL && SqlTypeUtil.isString(type2)) {
    return type2;
  }

  if (SqlTypeUtil.isDecimal(type1) && SqlTypeUtil.isCharacter(type2)
      || SqlTypeUtil.isCharacter(type1) && SqlTypeUtil.isDecimal(type2)) {
    // There is no proper DECIMAL type for VARCHAR, using max precision/scale DECIMAL
    // as the best we can do.
    return SqlTypeUtil.getMaxPrecisionScaleDecimal(factory);
  }

  // Keep sync with MS-SQL:
  // 1. BINARY/VARBINARY can not cast to FLOAT/REAL/DOUBLE
  // because of precision loss,
  // 2. CHARACTER to TIMESTAMP need explicit cast because of TimeZone.
  // Hive:
  // 1. BINARY can not cast to any other types,
  // 2. CHARACTER can only be coerced to DOUBLE/DECIMAL.
  if (SqlTypeUtil.isBinary(type2) && SqlTypeUtil.isApproximateNumeric(type1)
      || SqlTypeUtil.isBinary(type1) && SqlTypeUtil.isApproximateNumeric(type2)) {
    return null;
  }

  // 1 > '1' will be coerced to 1 > 1.
  if (SqlTypeUtil.isAtomic(type1) && SqlTypeUtil.isCharacter(type2)) {
    if (SqlTypeUtil.isTimestamp(type1)) {
      return null;
    }
    return type1;
  }

  if (SqlTypeUtil.isCharacter(type1) && SqlTypeUtil.isAtomic(type2)) {
    if (SqlTypeUtil.isTimestamp(type2)) {
      return null;
    }
    return type2;
  }

  return null;
}
 
Example 16
Source File: RexUtil.java    From calcite with Apache License 2.0 4 votes vote down vote up
/**
 * Determines whether a {@link RexCall} requires decimal expansion. It
 * usually requires expansion if it has decimal operands.
 *
 * <p>Exceptions to this rule are:
 *
 * <ul>
 * <li>isNull doesn't require expansion
 * <li>It's okay to cast decimals to and from char types
 * <li>It's okay to cast nulls as decimals
 * <li>Casts require expansion if their return type is decimal
 * <li>Reinterpret casts can handle a decimal operand
 * </ul>
 *
 * @param expr    expression possibly in need of expansion
 * @param recurse whether to check nested calls
 * @return whether the expression requires expansion
 */
public static boolean requiresDecimalExpansion(
    RexNode expr,
    boolean recurse) {
  if (!(expr instanceof RexCall)) {
    return false;
  }
  RexCall call = (RexCall) expr;

  boolean localCheck = true;
  switch (call.getKind()) {
  case REINTERPRET:
  case IS_NULL:
    localCheck = false;
    break;
  case CAST:
    RelDataType lhsType = call.getType();
    RelDataType rhsType = call.operands.get(0).getType();
    if (rhsType.getSqlTypeName() == SqlTypeName.NULL) {
      return false;
    }
    if (SqlTypeUtil.inCharFamily(lhsType)
        || SqlTypeUtil.inCharFamily(rhsType)) {
      localCheck = false;
    } else if (SqlTypeUtil.isDecimal(lhsType)
        && (lhsType != rhsType)) {
      return true;
    }
    break;
  default:
    localCheck = call.getOperator().requiresDecimalExpansion();
  }

  if (localCheck) {
    if (SqlTypeUtil.isDecimal(call.getType())) {
      // NOTE jvs 27-Mar-2007: Depending on the type factory, the
      // result of a division may be decimal, even though both inputs
      // are integer.
      return true;
    }
    for (int i = 0; i < call.operands.size(); i++) {
      if (SqlTypeUtil.isDecimal(call.operands.get(i).getType())) {
        return true;
      }
    }
  }
  return recurse && requiresDecimalExpansion(call.operands, true);
}