Пример #1
0
 @Override
 public String visitLiteral(RexLiteral rexLiteral) {
   Object v = rexLiteral.getValue();
   RelDataType ty = rexLiteral.getType();
   switch (rexLiteral.getTypeName()) {
     case BOOLEAN:
       return v.toString();
     case CHAR:
       return CompilerUtil.escapeJavaString(((NlsString) v).getValue(), true);
     case NULL:
       return "((" + ((Class<?>) typeFactory.getJavaClass(ty)).getCanonicalName() + ")null)";
     case DOUBLE:
     case BIGINT:
     case DECIMAL:
       switch (ty.getSqlTypeName()) {
         case TINYINT:
         case SMALLINT:
         case INTEGER:
           return Long.toString(((BigDecimal) v).longValueExact());
         case BIGINT:
           return Long.toString(((BigDecimal) v).longValueExact()) + 'L';
         case DECIMAL:
         case FLOAT:
         case REAL:
         case DOUBLE:
           return Util.toScientificNotation((BigDecimal) v);
       }
       break;
     default:
       throw new UnsupportedOperationException();
   }
   return null;
 }
Пример #2
0
  /** @return true if all tuples match rowType; otherwise, assert on mismatch */
  private boolean assertRowType() {
    for (List<RexLiteral> tuple : tuples) {
      assert tuple.size() == rowType.getFieldCount();
      for (Pair<RexLiteral, RelDataTypeField> pair : Pair.zip(tuple, rowType.getFieldList())) {
        RexLiteral literal = pair.left;
        RelDataType fieldType = pair.right.getType();

        // TODO jvs 19-Feb-2006: strengthen this a bit.  For example,
        // overflow, rounding, and padding/truncation must already have
        // been dealt with.
        if (!RexLiteral.isNullLiteral(literal)) {
          assert (SqlTypeUtil.canAssignFrom(fieldType, literal.getType()));
        }
      }
    }
    return true;
  }
Пример #3
0
 /**
  * Returns whether a node represents the NULL value.
  *
  * <p>Examples:
  *
  * <ul>
  *   <li>For {@link org.eigenbase.rex.RexLiteral} Unknown, returns false.
  *   <li>For <code>CAST(NULL AS <i>type</i>)</code>, returns true if <code>
  * allowCast</code> is true, false otherwise.
  *   <li>For <code>CAST(CAST(NULL AS <i>type</i>) AS <i>type</i>))</code>, returns false.
  * </ul>
  */
 public static boolean isNullLiteral(RexNode node, boolean allowCast) {
   if (node instanceof RexLiteral) {
     RexLiteral literal = (RexLiteral) node;
     if (literal.getTypeName() == SqlTypeName.NULL) {
       assert (null == literal.getValue());
       return true;
     } else {
       // We don't regard UNKNOWN -- SqlLiteral(null,Boolean) -- as
       // NULL.
       return false;
     }
   }
   if (allowCast) {
     if (node.isA(RexKind.Cast)) {
       RexCall call = (RexCall) node;
       if (isNullLiteral(call.operands[0], false)) {
         // node is "CAST(NULL as type)"
         return true;
       }
     }
   }
   return false;
 }
Пример #4
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);
 }
Пример #5
0
 /**
  * Returns whether a node represents the NULL value or a series of nested CAST(NULL as <TYPE>)
  * calls<br>
  * For Example:<br>
  * isNull(CAST(CAST(NULL as INTEGER) AS VARCHAR(1))) returns true
  */
 public static boolean isNull(RexNode node) {
   /* Checks to see if the RexNode is null */
   return RexLiteral.isNullLiteral(node)
       || ((node.getKind() == RexKind.Cast) && isNull(((RexCall) node).operands[0]));
 }
Пример #6
0
  /** Variant of {@link #trimFields(RelNode, BitSet, Set)} for {@link ProjectRel}. */
  public TrimResult trimFields(
      ProjectRel project, BitSet fieldsUsed, Set<RelDataTypeField> extraFields) {
    final RelDataType rowType = project.getRowType();
    final int fieldCount = rowType.getFieldCount();
    final RelNode input = project.getChild();
    final RelDataType inputRowType = input.getRowType();

    // Which fields are required from the input?
    BitSet inputFieldsUsed = new BitSet(inputRowType.getFieldCount());
    final Set<RelDataTypeField> inputExtraFields = new LinkedHashSet<RelDataTypeField>(extraFields);
    RelOptUtil.InputFinder inputFinder =
        new RelOptUtil.InputFinder(inputFieldsUsed, inputExtraFields);
    for (Ord<RexNode> ord : Ord.zip(project.getProjects())) {
      if (fieldsUsed.get(ord.i)) {
        ord.e.accept(inputFinder);
      }
    }

    // Create input with trimmed columns.
    TrimResult trimResult = trimChild(project, input, inputFieldsUsed, inputExtraFields);
    RelNode newInput = trimResult.left;
    final Mapping inputMapping = trimResult.right;

    // If the input is unchanged, and we need to project all columns,
    // there's nothing we can do.
    if (newInput == input && fieldsUsed.cardinality() == fieldCount) {
      return new TrimResult(project, Mappings.createIdentity(fieldCount));
    }

    // Some parts of the system can't handle rows with zero fields, so
    // pretend that one field is used.
    if (fieldsUsed.cardinality() == 0) {
      final Mapping mapping = Mappings.create(MappingType.InverseSurjection, fieldCount, 1);
      final RexLiteral expr =
          project.getCluster().getRexBuilder().makeExactLiteral(BigDecimal.ZERO);
      RelDataType newRowType =
          project
              .getCluster()
              .getTypeFactory()
              .createStructType(
                  Collections.singletonList(expr.getType()), Collections.singletonList("DUMMY"));
      ProjectRel newProject =
          new ProjectRel(
              project.getCluster(),
              project.getCluster().traitSetOf(RelCollationImpl.EMPTY),
              newInput,
              Collections.<RexNode>singletonList(expr),
              newRowType,
              project.getFlags());
      return new TrimResult(newProject, mapping);
    }

    // Build new project expressions, and populate the mapping.
    List<RexNode> newProjectExprList = new ArrayList<RexNode>();
    final RexVisitor<RexNode> shuttle = new RexPermuteInputsShuttle(inputMapping, newInput);
    final Mapping mapping =
        Mappings.create(MappingType.InverseSurjection, fieldCount, fieldsUsed.cardinality());
    for (Ord<RexNode> ord : Ord.zip(project.getProjects())) {
      if (fieldsUsed.get(ord.i)) {
        mapping.set(ord.i, newProjectExprList.size());
        RexNode newProjectExpr = ord.e.accept(shuttle);
        newProjectExprList.add(newProjectExpr);
      }
    }

    final RelDataType newRowType =
        project
            .getCluster()
            .getTypeFactory()
            .createStructType(Mappings.apply3(mapping, rowType.getFieldList()));

    final List<RelCollation> newCollations =
        RexUtil.apply(inputMapping, project.getCollationList());

    final RelNode newProject;
    if (RemoveTrivialProjectRule.isIdentity(
        newProjectExprList, newRowType, newInput.getRowType())) {
      // The new project would be the identity. It is equivalent to return
      // its child.
      newProject = newInput;
    } else {
      newProject =
          new ProjectRel(
              project.getCluster(),
              project
                  .getCluster()
                  .traitSetOf(
                      newCollations.isEmpty() ? RelCollationImpl.EMPTY : newCollations.get(0)),
              newInput,
              newProjectExprList,
              newRowType,
              project.getFlags());
      assert newProject.getClass() == project.getClass();
    }
    return new TrimResult(newProject, mapping);
  }
Пример #7
0
 /** Converts an expression from {@link RexNode} to {@link SqlNode} format. */
 SqlNode toSql(RexProgram program, RexNode rex) {
   if (rex instanceof RexLocalRef) {
     final int index = ((RexLocalRef) rex).getIndex();
     return toSql(program, program.getExprList().get(index));
   } else if (rex instanceof RexInputRef) {
     return field(((RexInputRef) rex).getIndex());
   } else if (rex instanceof RexLiteral) {
     final RexLiteral literal = (RexLiteral) rex;
     switch (literal.getTypeName().getFamily()) {
       case CHARACTER:
         return SqlLiteral.createCharString((String) literal.getValue2(), POS);
       case NUMERIC:
       case EXACT_NUMERIC:
         return SqlLiteral.createExactNumeric(literal.getValue().toString(), POS);
       case APPROXIMATE_NUMERIC:
         return SqlLiteral.createApproxNumeric(literal.getValue().toString(), POS);
       case BOOLEAN:
         return SqlLiteral.createBoolean((Boolean) literal.getValue(), POS);
       case DATE:
         return SqlLiteral.createDate((Calendar) literal.getValue(), POS);
       case TIME:
         return SqlLiteral.createTime(
             (Calendar) literal.getValue(), literal.getType().getPrecision(), POS);
       case TIMESTAMP:
         return SqlLiteral.createTimestamp(
             (Calendar) literal.getValue(), literal.getType().getPrecision(), POS);
       case ANY:
         switch (literal.getTypeName()) {
           case NULL:
             return SqlLiteral.createNull(POS);
             // fall through
         }
       default:
         throw new AssertionError(literal + ": " + literal.getTypeName());
     }
   } else if (rex instanceof RexCall) {
     final RexCall call = (RexCall) rex;
     final SqlOperator op = call.getOperator();
     final List<SqlNode> nodeList = toSql(program, call.getOperands());
     if (op == SqlStdOperatorTable.CAST) {
       RelDataType type = call.getType();
       if (type.getSqlTypeName() == SqlTypeName.VARCHAR
           && dialect.getDatabaseProduct() == SqlDialect.DatabaseProduct.MYSQL) {
         // MySQL doesn't have a VARCHAR type, only CHAR.
         nodeList.add(
             new SqlDataTypeSpec(
                 new SqlIdentifier("CHAR", POS), type.getPrecision(), -1, null, null, POS));
       } else {
         nodeList.add(toSql(type));
       }
     }
     if (op == SqlStdOperatorTable.CASE) {
       final SqlNode valueNode;
       final List<SqlNode> whenList = Expressions.list();
       final List<SqlNode> thenList = Expressions.list();
       final SqlNode elseNode;
       if (nodeList.size() % 2 == 0) {
         // switched:
         //   "case x when v1 then t1 when v2 then t2 ... else e end"
         valueNode = nodeList.get(0);
         for (int i = 1; i < nodeList.size() - 1; i += 2) {
           whenList.add(nodeList.get(i));
           thenList.add(nodeList.get(i + 1));
         }
       } else {
         // other: "case when w1 then t1 when w2 then t2 ... else e end"
         valueNode = null;
         for (int i = 0; i < nodeList.size() - 1; i += 2) {
           whenList.add(nodeList.get(i));
           thenList.add(nodeList.get(i + 1));
         }
       }
       elseNode = nodeList.get(nodeList.size() - 1);
       return op.createCall(
           POS,
           valueNode,
           new SqlNodeList(whenList, POS),
           new SqlNodeList(thenList, POS),
           elseNode);
     }
     if (op instanceof SqlBinaryOperator && nodeList.size() > 2) {
       // In RexNode trees, OR and AND have any number of children;
       // SqlCall requires exactly 2. So, convert to a left-deep binary tree.
       return createLeftCall(op, nodeList);
     }
     return op.createCall(new SqlNodeList(nodeList, POS));
   } else {
     throw new AssertionError(rex);
   }
 }