private static Expression checkExpressionPadTruncate()

in modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/exp/RexToLixTranslator.java [493:601]


  private static Expression checkExpressionPadTruncate(
      Expression operand,
      RelDataType sourceType,
      RelDataType targetType,
      Expression sourceOperand) {
    // Going from anything to CHAR(n) or VARCHAR(n), make sure value is no
    // longer than n.
    boolean pad = false;
    boolean truncate = true;
    switch (targetType.getSqlTypeName()) {
    case CHAR:
    case BINARY:
    case VARCHAR:
    case VARBINARY:
      final int targetPrecision = targetType.getPrecision();
      if (targetPrecision < 0) {
        return operand;
      }
      switch (sourceType.getSqlTypeName()) {
      case CHAR:
      case VARCHAR:
      case BINARY:
      case VARBINARY:
        // If this is a widening cast, no need to truncate.
        final int sourcePrecision = sourceType.getPrecision();
        if (SqlTypeUtil.comparePrecision(sourcePrecision, targetPrecision)
            <= 0) {
          truncate = false;
        }
        // If this is a widening cast, no need to pad.
        if (SqlTypeUtil.comparePrecision(sourcePrecision, targetPrecision)
            >= 0) {
          pad = false;
        }
        // fall through
      default:
        if (truncate || pad) {
          final Method method =
              pad ? BuiltInMethod.TRUNCATE_OR_PAD.method
                  : BuiltInMethod.TRUNCATE.method;
          return Expressions.call(method, operand,
              Expressions.constant(targetPrecision));
        }
        return operand;
      }

      // Checkstyle thinks that the previous branch should have a break, but it
      // is mistaken.
      // CHECKSTYLE: IGNORE 1
    case TIMESTAMP:
      int targetScale = targetType.getScale();
      if (targetScale == RelDataType.SCALE_NOT_SPECIFIED) {
        targetScale = 0;
      }
      if (targetScale < sourceType.getScale()) {
        return Expressions.call(BuiltInMethod.ROUND_LONG.method, operand,
            Expressions.constant((long) Math.pow(10, 3 - targetScale)));
      }
      return operand;

    case INTERVAL_YEAR:
    case INTERVAL_YEAR_MONTH:
    case INTERVAL_MONTH:
    case INTERVAL_DAY:
    case INTERVAL_DAY_HOUR:
    case INTERVAL_DAY_MINUTE:
    case INTERVAL_DAY_SECOND:
    case INTERVAL_HOUR:
    case INTERVAL_HOUR_MINUTE:
    case INTERVAL_HOUR_SECOND:
    case INTERVAL_MINUTE:
    case INTERVAL_MINUTE_SECOND:
    case INTERVAL_SECOND:
      final SqlTypeFamily family =
          requireNonNull(sourceType.getSqlTypeName().getFamily(),
              () -> "null SqlTypeFamily for " + sourceType + ", SqlTypeName "
                  + sourceType.getSqlTypeName());
      switch (family) {
      case NUMERIC:
        final BigDecimal multiplier =
            targetType.getSqlTypeName().getEndUnit().multiplier;
        final BigDecimal divider = BigDecimal.ONE;
        return RexImpTable.multiplyDivide(operand, multiplier, divider);
      case CHARACTER:
          SqlIntervalQualifier intervalQualifier = targetType.getIntervalQualifier();

          Method method = intervalQualifier.isYearMonth()
                ? IgniteMethod.PARSE_INTERVAL_YEAR_MONTH.method()
                : IgniteMethod.PARSE_INTERVAL_DAY_TIME.method();

        return Expressions.call(
                method,
                sourceOperand,
                Expressions.new_(SqlIntervalQualifier.class,
                        Expressions.constant(intervalQualifier.getStartUnit()),
                        Expressions.constant(intervalQualifier.getStartPrecisionPreservingDefault()),
                        Expressions.constant(intervalQualifier.getEndUnit()),
                        Expressions.constant(intervalQualifier.getFractionalSecondPrecisionPreservingDefault()),
                        Expressions.field(null, SqlParserPos.class, "ZERO")
                )
        );
      default:
        return operand;
      }

    default:
      return operand;
    }
  }