示例#1
0
 /**
  * Extracts the string value from a string literal, a chain of string literals, or a CAST of a
  * string literal.
  *
  * @deprecated Use {@link #value(SqlNode)}
  */
 @Deprecated // to be removed before 2.0
 public static String stringValue(SqlNode node) {
   if (node instanceof SqlLiteral) {
     SqlLiteral literal = (SqlLiteral) node;
     assert SqlTypeUtil.inCharFamily(literal.getTypeName());
     return literal.toValue();
   } else if (SqlUtil.isLiteralChain(node)) {
     final SqlLiteral literal = SqlLiteralChainOperator.concatenateOperands((SqlCall) node);
     assert SqlTypeUtil.inCharFamily(literal.getTypeName());
     return literal.toValue();
   } else if (node instanceof SqlCall
       && ((SqlCall) node).getOperator() == SqlStdOperatorTable.CAST) {
     return stringValue(((SqlCall) node).operand(0));
   } else {
     throw Util.newInternal("invalid string literal: " + node);
   }
 }
示例#2
0
 /**
  * Creates a call to the CAST operator, expanding if possible.
  *
  * @param type Type to cast to
  * @param exp Expression being cast
  * @return Call to CAST operator
  */
 public RexNode makeCast(RelDataType type, RexNode exp) {
   final SqlTypeName sqlType = type.getSqlTypeName();
   if (exp instanceof RexLiteral) {
     RexLiteral literal = (RexLiteral) exp;
     Comparable value = literal.getValue();
     if (RexLiteral.valueMatchesType(value, sqlType, false)
         && (!(value instanceof NlsString)
             || (type.getPrecision() >= ((NlsString) value).getValue().length()))
         && (!(value instanceof ByteString)
             || (type.getPrecision() >= ((ByteString) value).length()))) {
       switch (literal.getTypeName()) {
         case CHAR:
           if (value instanceof NlsString) {
             value = ((NlsString) value).rtrim();
           }
           break;
         case TIMESTAMP:
         case TIME:
           final Calendar calendar = (Calendar) value;
           int scale = type.getScale();
           if (scale == RelDataType.SCALE_NOT_SPECIFIED) {
             scale = 0;
           }
           calendar.setTimeInMillis(
               SqlFunctions.round(
                   calendar.getTimeInMillis(), DateTimeUtils.powerX(10, 3 - scale)));
           break;
         case INTERVAL_DAY_TIME:
           BigDecimal value2 = (BigDecimal) value;
           final long multiplier =
               literal.getType().getIntervalQualifier().getStartUnit().multiplier;
           SqlTypeName typeName = type.getSqlTypeName();
           // Not all types are allowed for literals
           switch (typeName) {
             case INTEGER:
               typeName = SqlTypeName.BIGINT;
           }
           return makeLiteral(
               value2.divide(BigDecimal.valueOf(multiplier), 0, BigDecimal.ROUND_HALF_DOWN),
               type,
               typeName);
       }
       return makeLiteral(value, type, literal.getTypeName());
     }
   } else if (SqlTypeUtil.isInterval(type) && SqlTypeUtil.isExactNumeric(exp.getType())) {
     return makeCastExactToInterval(type, exp);
   } else if (SqlTypeUtil.isExactNumeric(type) && SqlTypeUtil.isInterval(exp.getType())) {
     return makeCastIntervalToExact(type, exp);
   } else if (sqlType == SqlTypeName.BOOLEAN && SqlTypeUtil.isExactNumeric(exp.getType())) {
     return makeCastExactToBoolean(type, exp);
   } else if (exp.getType().getSqlTypeName() == SqlTypeName.BOOLEAN
       && SqlTypeUtil.isExactNumeric(type)) {
     return makeCastBooleanToExact(type, exp);
   }
   return makeAbstractCast(type, exp);
 }
示例#3
0
 /**
  * Extracts the value from a literal.
  *
  * <p>Cases:
  *
  * <ul>
  *   <li>If the node is a character literal, a chain of string literals, or a CAST of a character
  *       literal, returns the value as a {@link NlsString}.
  *   <li>If the node is a numeric literal, or a negated numeric literal, returns the value as a
  *       {@link BigDecimal}.
  *   <li>If the node is a {@link SqlIntervalQualifier}, returns its {@link TimeUnitRange}.
  *   <li>If the node is INTERVAL_DAY_TIME in {@link SqlTypeFamily}, returns its sign multiplied by
  *       its millisecond equivalent value
  *   <li>If the node is INTERVAL_YEAR_MONTH in {@link SqlTypeFamily}, returns its sign multiplied
  *       by its months equivalent value
  *   <li>Otherwise the behavior is not specified.
  * </ul>
  */
 public static Comparable value(SqlNode node) {
   if (node instanceof SqlLiteral) {
     SqlLiteral literal = (SqlLiteral) node;
     switch (literal.getTypeName().getFamily()) {
       case CHARACTER:
         return (NlsString) literal.value;
       case NUMERIC:
         return (BigDecimal) literal.value;
       case INTERVAL_YEAR_MONTH:
         final SqlIntervalLiteral.IntervalValue valMonth =
             (SqlIntervalLiteral.IntervalValue) literal.value;
         return valMonth.getSign() * SqlParserUtil.intervalToMonths(valMonth);
       case INTERVAL_DAY_TIME:
         final SqlIntervalLiteral.IntervalValue valTime =
             (SqlIntervalLiteral.IntervalValue) literal.value;
         return valTime.getSign() * SqlParserUtil.intervalToMillis(valTime);
     }
   }
   if (SqlUtil.isLiteralChain(node)) {
     assert node instanceof SqlCall;
     final SqlLiteral literal = SqlLiteralChainOperator.concatenateOperands((SqlCall) node);
     assert SqlTypeUtil.inCharFamily(literal.getTypeName());
     return (NlsString) literal.value;
   }
   if (node instanceof SqlIntervalQualifier) {
     SqlIntervalQualifier qualifier = (SqlIntervalQualifier) node;
     return qualifier.timeUnitRange;
   }
   switch (node.getKind()) {
     case CAST:
       assert node instanceof SqlCall;
       return value(((SqlCall) node).operand(0));
     case MINUS_PREFIX:
       assert node instanceof SqlCall;
       Comparable o = value(((SqlCall) node).operand(0));
       if (o instanceof BigDecimal) {
         BigDecimal bigDecimal = (BigDecimal) o;
         return bigDecimal.negate();
       }
       // fall through
     default:
       throw Util.newInternal("invalid literal: " + node);
   }
 }
示例#4
0
  /**
   * Transforms this literal (which must be of type character) into a new one in which 4-digit
   * Unicode escape sequences have been replaced with the corresponding Unicode characters.
   *
   * @param unicodeEscapeChar escape character (e.g. backslash) for Unicode numeric sequences; 0
   *     implies no transformation
   * @return transformed literal
   */
  public SqlLiteral unescapeUnicode(char unicodeEscapeChar) {
    if (unicodeEscapeChar == 0) {
      return this;
    }
    assert SqlTypeUtil.inCharFamily(getTypeName());
    NlsString ns = (NlsString) value;
    String s = ns.getValue();
    StringBuilder sb = new StringBuilder();
    int n = s.length();
    for (int i = 0; i < n; ++i) {
      char c = s.charAt(i);
      if (c == unicodeEscapeChar) {
        if (n > (i + 1)) {
          if (s.charAt(i + 1) == unicodeEscapeChar) {
            sb.append(unicodeEscapeChar);
            ++i;
            continue;
          }
        }
        if ((i + 5) > n) {
          throw SqlUtil.newContextException(
              getParserPosition(), RESOURCE.unicodeEscapeMalformed(i));
        }
        final String u = s.substring(i + 1, i + 5);
        final int v;
        try {
          v = Integer.parseInt(u, 16);
        } catch (NumberFormatException ex) {
          throw SqlUtil.newContextException(
              getParserPosition(), RESOURCE.unicodeEscapeMalformed(i));
        }
        sb.append((char) (v & 0xFFFF));

        // skip hexits
        i += 4;
      } else {
        sb.append(c);
      }
    }
    ns = new NlsString(sb.toString(), ns.getCharsetName(), ns.getCollation());
    return new SqlCharStringLiteral(ns, getParserPosition());
  }
示例#5
0
 public static void checkCharsetAndCollateConsistentIfCharType(RelDataType type) {
   // (every charset must have a default collation)
   if (SqlTypeUtil.inCharFamily(type)) {
     Charset strCharset = type.getCharset();
     Charset colCharset = type.getCollation().getCharset();
     assert null != strCharset;
     assert null != colCharset;
     if (!strCharset.equals(colCharset)) {
       if (false) {
         // todo: enable this checking when we have a charset to
         //   collation mapping
         throw new Error(
             type.toString()
                 + " was found to have charset '"
                 + strCharset.name()
                 + "' and a mismatched collation charset '"
                 + colCharset.name()
                 + "'");
       }
     }
   }
 }
示例#6
0
 /**
  * Creates a reference to a given field of the input record.
  *
  * @param type Type of field
  * @param i Ordinal of field
  * @return Reference to field
  */
 public RexInputRef makeInputRef(RelDataType type, int i) {
   type = SqlTypeUtil.addCharsetAndCollation(type, typeFactory);
   return new RexInputRef(i, type);
 }
示例#7
0
 /**
  * Retrieves an interval or decimal node's integer representation
  *
  * @param node the interval or decimal value as an opaque type
  * @return an integer representation of the decimal value
  */
 public RexNode decodeIntervalOrDecimal(RexNode node) {
   assert SqlTypeUtil.isDecimal(node.getType()) || SqlTypeUtil.isInterval(node.getType());
   RelDataType bigintType = typeFactory.createSqlType(SqlTypeName.BIGINT);
   return makeReinterpretCast(matchNullability(bigintType, node), node, makeLiteral(false));
 }