Example #1
0
  protected RexNode convert(ExprNodeConstantDesc literal) throws CalciteSemanticException {
    RexBuilder rexBuilder = cluster.getRexBuilder();
    RelDataTypeFactory dtFactory = rexBuilder.getTypeFactory();
    PrimitiveTypeInfo hiveType = (PrimitiveTypeInfo) literal.getTypeInfo();
    RelDataType calciteDataType = TypeConverter.convert(hiveType, dtFactory);

    PrimitiveCategory hiveTypeCategory = hiveType.getPrimitiveCategory();

    ConstantObjectInspector coi = literal.getWritableObjectInspector();
    Object value =
        ObjectInspectorUtils.copyToStandardJavaObject(coi.getWritableConstantValue(), coi);

    RexNode calciteLiteral = null;
    // TODO: Verify if we need to use ConstantObjectInspector to unwrap data
    switch (hiveTypeCategory) {
      case BOOLEAN:
        calciteLiteral = rexBuilder.makeLiteral(((Boolean) value).booleanValue());
        break;
      case BYTE:
        calciteLiteral = rexBuilder.makeExactLiteral(new BigDecimal((Byte) value), calciteDataType);
        break;
      case SHORT:
        calciteLiteral =
            rexBuilder.makeExactLiteral(new BigDecimal((Short) value), calciteDataType);
        break;
      case INT:
        calciteLiteral = rexBuilder.makeExactLiteral(new BigDecimal((Integer) value));
        break;
      case LONG:
        calciteLiteral = rexBuilder.makeBigintLiteral(new BigDecimal((Long) value));
        break;
        // TODO: is Decimal an exact numeric or approximate numeric?
      case DECIMAL:
        if (value instanceof HiveDecimal) {
          value = ((HiveDecimal) value).bigDecimalValue();
        } else if (value instanceof Decimal128) {
          value = ((Decimal128) value).toBigDecimal();
        }
        if (value == null) {
          // We have found an invalid decimal value while enforcing precision and
          // scale. Ideally,
          // we would replace it with null here, which is what Hive does. However,
          // we need to plumb
          // this thru up somehow, because otherwise having different expression
          // type in AST causes
          // the plan generation to fail after CBO, probably due to some residual
          // state in SA/QB.
          // For now, we will not run CBO in the presence of invalid decimal
          // literals.
          throw new CalciteSemanticException(
              "Expression " + literal.getExprString() + " is not a valid decimal",
              UnsupportedFeature.Invalid_decimal);
          // TODO: return createNullLiteral(literal);
        }
        BigDecimal bd = (BigDecimal) value;
        BigInteger unscaled = bd.unscaledValue();
        if (unscaled.compareTo(MIN_LONG_BI) >= 0 && unscaled.compareTo(MAX_LONG_BI) <= 0) {
          calciteLiteral = rexBuilder.makeExactLiteral(bd);
        } else {
          // CBO doesn't support unlimited precision decimals. In practice, this
          // will work...
          // An alternative would be to throw CboSemanticException and fall back
          // to no CBO.
          RelDataType relType =
              cluster
                  .getTypeFactory()
                  .createSqlType(SqlTypeName.DECIMAL, bd.scale(), unscaled.toString().length());
          calciteLiteral = rexBuilder.makeExactLiteral(bd, relType);
        }
        break;
      case FLOAT:
        calciteLiteral =
            rexBuilder.makeApproxLiteral(new BigDecimal((Float) value), calciteDataType);
        break;
      case DOUBLE:
        calciteLiteral =
            rexBuilder.makeApproxLiteral(new BigDecimal((Double) value), calciteDataType);
        break;
      case CHAR:
        if (value instanceof HiveChar) {
          value = ((HiveChar) value).getValue();
        }
        calciteLiteral = rexBuilder.makeCharLiteral(asUnicodeString((String) value));
        break;
      case VARCHAR:
        if (value instanceof HiveVarchar) {
          value = ((HiveVarchar) value).getValue();
        }
        calciteLiteral = rexBuilder.makeCharLiteral(asUnicodeString((String) value));
        break;
      case STRING:
        calciteLiteral = rexBuilder.makeCharLiteral(asUnicodeString((String) value));
        break;
      case DATE:
        Calendar cal = new GregorianCalendar();
        cal.setTime((Date) value);
        calciteLiteral = rexBuilder.makeDateLiteral(cal);
        break;
      case TIMESTAMP:
        Calendar c = null;
        if (value instanceof Calendar) {
          c = (Calendar) value;
        } else {
          c = Calendar.getInstance();
          c.setTimeInMillis(((Timestamp) value).getTime());
        }
        calciteLiteral = rexBuilder.makeTimestampLiteral(c, RelDataType.PRECISION_NOT_SPECIFIED);
        break;
      case INTERVAL_YEAR_MONTH:
        // Calcite year-month literal value is months as BigDecimal
        BigDecimal totalMonths =
            BigDecimal.valueOf(((HiveIntervalYearMonth) value).getTotalMonths());
        calciteLiteral =
            rexBuilder.makeIntervalLiteral(
                totalMonths,
                new SqlIntervalQualifier(TimeUnit.YEAR, TimeUnit.MONTH, new SqlParserPos(1, 1)));
        break;
      case INTERVAL_DAY_TIME:
        // Calcite day-time interval is millis value as BigDecimal
        // Seconds converted to millis
        BigDecimal secsValueBd =
            BigDecimal.valueOf(((HiveIntervalDayTime) value).getTotalSeconds() * 1000);
        // Nanos converted to millis
        BigDecimal nanosValueBd = BigDecimal.valueOf(((HiveIntervalDayTime) value).getNanos(), 6);
        calciteLiteral =
            rexBuilder.makeIntervalLiteral(
                secsValueBd.add(nanosValueBd),
                new SqlIntervalQualifier(TimeUnit.DAY, TimeUnit.SECOND, new SqlParserPos(1, 1)));
        break;
      case VOID:
        calciteLiteral =
            cluster
                .getRexBuilder()
                .makeLiteral(null, cluster.getTypeFactory().createSqlType(SqlTypeName.NULL), true);
        break;
      case BINARY:
      case UNKNOWN:
      default:
        throw new RuntimeException("UnSupported Literal");
    }

    return calciteLiteral;
  }