content: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to you under the Apache License, Version 2.0
   * (the "License"); you may not use this file except in compliance with
   * the License.  You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.apache.calcite.sql2rel;
  
  import org.apache.calcite.avatica.util.ByteString;
  import org.apache.calcite.rel.type.RelDataType;
  import org.apache.calcite.rex.RexBuilder;
  import org.apache.calcite.rex.RexLiteral;
  import org.apache.calcite.rex.RexNode;
  import org.apache.calcite.sql.SqlCall;
  import org.apache.calcite.sql.SqlIntervalQualifier;
  import org.apache.calcite.sql.SqlLiteral;
  import org.apache.calcite.sql.SqlTimeLiteral;
  import org.apache.calcite.sql.SqlTimestampLiteral;
  import org.apache.calcite.sql.type.SqlTypeName;
  import org.apache.calcite.util.BitString;
  import org.apache.calcite.util.DateString;
  import org.apache.calcite.util.NlsString;
  import org.apache.calcite.util.TimeString;
  import org.apache.calcite.util.TimestampString;
  import org.apache.calcite.util.TimestampWithTimeZoneString;
  import org.apache.calcite.util.Util;
  
  import java.math.BigDecimal;
  import java.util.UUID;
  
  import static com.google.common.base.Preconditions.checkArgument;
  
  /**
   * Standard implementation of {@link SqlNodeToRexConverter}.
   */
  public class SqlNodeToRexConverterImpl implements SqlNodeToRexConverter {
    //~ Instance fields --------------------------------------------------------
  
    private final SqlRexConvertletTable convertletTable;
  
    //~ Constructors -----------------------------------------------------------
  
    SqlNodeToRexConverterImpl(SqlRexConvertletTable convertletTable) {
      this.convertletTable = convertletTable;
    }
  
    //~ Methods ----------------------------------------------------------------
  
    @Override public RexNode convertCall(SqlRexContext cx, SqlCall call) {
      final SqlRexConvertlet convertlet = convertletTable.get(call);
      if (convertlet != null) {
        return convertlet.convertCall(cx, call);
      }
  
      // No convertlet was suitable. (Unlikely, because the standard
      // convertlet table has a fall-back for all possible calls.)
      throw Util.needToImplement(call);
    }
  
    @Override public RexLiteral convertInterval(
        SqlRexContext cx,
        SqlIntervalQualifier intervalQualifier) {
      RexBuilder rexBuilder = cx.getRexBuilder();
  
      return rexBuilder.makeIntervalLiteral(intervalQualifier);
    }
  
    @Override public RexNode convertLiteral(
        SqlRexContext cx,
        SqlLiteral literal) {
      final RexBuilder rexBuilder = cx.getRexBuilder();
      if (literal.getValue() == null) {
        if (literal.getTypeName() == SqlTypeName.NULL) {
          RelDataType type = cx.getValidator().getValidatedNodeTypeIfKnown(literal);
          if (type == null) {
            type = rexBuilder.getTypeFactory().createSqlType(SqlTypeName.NULL);
          }
          return rexBuilder.makeNullLiteral(type);
        } else {
          RelDataType type = cx.getValidator().getValidatedNodeType(literal);
          return rexBuilder.makeNullLiteral(type);
        }
      }
  
      switch (literal.getTypeName()) {
      case UUID:
        return rexBuilder.makeUuidLiteral(literal.getValueAs(UUID.class));
      case DECIMAL:
        // exact number
        BigDecimal bd = literal.getValueAs(BigDecimal.class);
        RelDataType type = literal.createSqlType(cx.getTypeFactory());
        return rexBuilder.makeExactLiteral(bd, type);
  
      case DOUBLE:
        // approximate type
        // TODO:  preserve fixed-point precision and large integers
        return rexBuilder.makeApproxLiteral(literal.getValueAs(BigDecimal.class));
  
      case CHAR:
        return rexBuilder.makeCharLiteral(literal.getValueAs(NlsString.class));
      case BOOLEAN:
        return rexBuilder.makeLiteral(literal.getValueAs(Boolean.class));
      case BINARY:
        final BitString bitString = literal.getValueAs(BitString.class);
        checkArgument((bitString.getBitCount() % 8) == 0, "incomplete octet");
  
        // An even number of hexits (e.g. X'ABCD') makes whole number
        // of bytes.
        final ByteString byteString = new ByteString(bitString.getAsByteArray());
        return rexBuilder.makeBinaryLiteral(byteString);
      case SYMBOL:
        return rexBuilder.makeFlag(literal.getValueAs(Enum.class));
      case TIMESTAMP:
        return rexBuilder.makeTimestampLiteral(
            literal.getValueAs(TimestampString.class),
            ((SqlTimestampLiteral) literal).getPrec());
      case TIMESTAMP_WITH_LOCAL_TIME_ZONE:
        return rexBuilder.makeTimestampWithLocalTimeZoneLiteral(
            literal.getValueAs(TimestampString.class),
            ((SqlTimestampLiteral) literal).getPrec());
      case TIMESTAMP_TZ:
        return rexBuilder.makeTimestampTzLiteral(
            literal.getValueAs(TimestampWithTimeZoneString.class),
            ((SqlTimestampLiteral) literal).getPrec());
      case TIME:
        return rexBuilder.makeTimeLiteral(
            literal.getValueAs(TimeString.class),
            ((SqlTimeLiteral) literal).getPrec());
      case DATE:
        return rexBuilder.makeDateLiteral(literal.getValueAs(DateString.class));
  
      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:
        SqlIntervalQualifier sqlIntervalQualifier =
            literal.getValueAs(SqlIntervalQualifier.class);
        return rexBuilder.makeIntervalLiteral(
            literal.getValueAs(BigDecimal.class),
            sqlIntervalQualifier);
  
      case UNKNOWN:
        return convertLiteral(cx, cx.getValidator().resolveLiteral(literal));
  
      default:
        throw Util.unexpected(literal.getTypeName());
      }
    }
  }
  