Beispiel #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;
 }
Beispiel #2
0
 private static Comparable zeroValue(RelDataType type) {
   switch (type.getSqlTypeName()) {
     case CHAR:
       return new NlsString(Spaces.of(type.getPrecision()), null, null);
     case VARCHAR:
       return new NlsString("", null, null);
     case BINARY:
       return new ByteString(new byte[type.getPrecision()]);
     case VARBINARY:
       return ByteString.EMPTY;
     case TINYINT:
     case SMALLINT:
     case INTEGER:
     case BIGINT:
     case DECIMAL:
     case FLOAT:
     case REAL:
     case DOUBLE:
       return BigDecimal.ZERO;
     case BOOLEAN:
       return false;
     case TIME:
     case DATE:
     case TIMESTAMP:
       return DateTimeUtils.ZERO_CALENDAR;
     default:
       throw Util.unexpected(type.getSqlTypeName());
   }
 }
  /**
   * Returns the type the row which results when two relations are joined.
   *
   * <p>The resulting row type consists of the system fields (if any), followed by the fields of the
   * left type, followed by the fields of the right type. The field name list, if present, overrides
   * the original names of the fields.
   *
   * @param typeFactory Type factory
   * @param leftType Type of left input to join
   * @param rightType Type of right input to join
   * @param fieldNameList If not null, overrides the original names of the fields
   * @param systemFieldList List of system fields that will be prefixed to output row type;
   *     typically empty but must not be null
   * @return type of row which results when two relations are joined
   */
  public static RelDataType createJoinType(
      RelDataTypeFactory typeFactory,
      RelDataType leftType,
      RelDataType rightType,
      List<String> fieldNameList,
      List<RelDataTypeField> systemFieldList) {
    assert (fieldNameList == null)
        || (fieldNameList.size()
            == (systemFieldList.size() + leftType.getFieldCount() + rightType.getFieldCount()));
    List<String> nameList = new ArrayList<>();
    final List<RelDataType> typeList = new ArrayList<>();

    // Use a set to keep track of the field names; this is needed
    // to ensure that the contains() call to check for name uniqueness
    // runs in constant time; otherwise, if the number of fields is large,
    // doing a contains() on a list can be expensive.
    final Set<String> uniqueNameList =
        typeFactory.getTypeSystem().isSchemaCaseSensitive()
            ? new HashSet<String>()
            : new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
    addFields(systemFieldList, typeList, nameList, uniqueNameList);
    addFields(leftType.getFieldList(), typeList, nameList, uniqueNameList);
    if (rightType != null) {
      addFields(rightType.getFieldList(), typeList, nameList, uniqueNameList);
    }
    if (fieldNameList != null) {
      assert fieldNameList.size() == nameList.size();
      nameList = fieldNameList;
    }
    return typeFactory.createStructType(typeList, nameList);
  }
Beispiel #4
0
  /**
   * Creates a relational expression that projects the given fields of the input.
   *
   * <p>Optimizes if the fields are the identity projection.
   *
   * @param relBuilder RelBuilder
   * @param child Input relational expression
   * @param posList Source of each projected field
   * @return Relational expression that projects given fields
   */
  public static RelNode createProject(
      final RelBuilder relBuilder, final RelNode child, final List<Integer> posList) {
    RelDataType rowType = child.getRowType();
    final List<String> fieldNames = rowType.getFieldNames();
    final RexBuilder rexBuilder = child.getCluster().getRexBuilder();
    return createProject(
        child,
        new AbstractList<RexNode>() {
          public int size() {
            return posList.size();
          }

          public RexNode get(int index) {
            final int pos = posList.get(index);
            return rexBuilder.makeInputRef(child, pos);
          }
        },
        new AbstractList<String>() {
          public int size() {
            return posList.size();
          }

          public String get(int index) {
            final int pos = posList.get(index);
            return fieldNames.get(pos);
          }
        },
        true,
        relBuilder);
  }
  protected DrillRel addRenamedProject(DrillRel rel, RelDataType validatedRowType) {
    RelDataType t = rel.getRowType();

    RexBuilder b = rel.getCluster().getRexBuilder();
    List<RexNode> projections = Lists.newArrayList();
    int projectCount = t.getFieldList().size();

    for (int i = 0; i < projectCount; i++) {
      projections.add(b.makeInputRef(rel, i));
    }

    final List<String> fieldNames2 =
        SqlValidatorUtil.uniquify(validatedRowType.getFieldNames(), SqlValidatorUtil.F_SUGGESTER2);

    RelDataType newRowType =
        RexUtil.createStructType(rel.getCluster().getTypeFactory(), projections, fieldNames2);

    DrillProjectRel topProj =
        DrillProjectRel.create(rel.getCluster(), rel.getTraitSet(), rel, projections, newRowType);

    // Add a final non-trivial Project to get the validatedRowType, if child is not project.
    if (rel instanceof Project && DrillRelOptUtil.isTrivialProject(topProj, true)) {
      return rel;
    } else {
      return topProj;
    }
  }
Beispiel #6
0
 /**
  * Creates an expression accessing a given named field from a record.
  *
  * <p>NOTE: Be careful choosing the value of {@code caseSensitive}. If the field name was supplied
  * by an end-user (e.g. as a column alias in SQL), use your session's case-sensitivity setting.
  * Only hard-code {@code true} if you are sure that the field name is internally generated.
  * Hard-coding {@code false} is almost certainly wrong.
  *
  * @param expr Expression yielding a record
  * @param fieldName Name of field in record
  * @param caseSensitive Whether match is case-sensitive
  * @return Expression accessing a given named field
  */
 public RexNode makeFieldAccess(RexNode expr, String fieldName, boolean caseSensitive) {
   final RelDataType type = expr.getType();
   final RelDataTypeField field = type.getField(fieldName, caseSensitive, false);
   if (field == null) {
     throw Util.newInternal("Type '" + type + "' has no field '" + fieldName + "'");
   }
   return makeFieldAccessInternal(expr, field);
 }
Beispiel #7
0
 /**
  * Creates an expression accessing a field with a given ordinal from a record.
  *
  * @param expr Expression yielding a record
  * @param i Ordinal of field
  * @return Expression accessing given field
  */
 public RexNode makeFieldAccess(RexNode expr, int i) {
   final RelDataType type = expr.getType();
   final List<RelDataTypeField> fields = type.getFieldList();
   if ((i < 0) || (i >= fields.size())) {
     throw Util.newInternal("Field ordinal " + i + " is invalid for " + " type '" + type + "'");
   }
   return makeFieldAccessInternal(expr, fields.get(i));
 }
Beispiel #8
0
 /**
  * Makes an expression which converts a value of type T to a value of type T NOT NULL, or throws
  * if the value is NULL. If the expression is already NOT NULL, does nothing.
  */
 public RexNode makeNotNullCast(RexNode expr) {
   RelDataType type = expr.getType();
   if (!type.isNullable()) {
     return expr;
   }
   RelDataType typeNotNull = getTypeFactory().createTypeWithNullability(type, false);
   return new RexCall(typeNotNull, SqlStdOperatorTable.CAST, ImmutableList.of(expr));
 }
Beispiel #9
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);
 }
Beispiel #10
0
 /**
  * Converts the type of a value to comply with {@link
  * org.apache.calcite.rex.RexLiteral#valueMatchesType}.
  */
 private static Object clean(Object o, RelDataType type) {
   if (o == null) {
     return null;
   }
   final Calendar calendar;
   switch (type.getSqlTypeName()) {
     case TINYINT:
     case SMALLINT:
     case INTEGER:
     case BIGINT:
     case DECIMAL:
     case INTERVAL_YEAR_MONTH:
     case INTERVAL_DAY_TIME:
       if (o instanceof BigDecimal) {
         return o;
       }
       return new BigDecimal(((Number) o).longValue());
     case FLOAT:
     case REAL:
     case DOUBLE:
       if (o instanceof BigDecimal) {
         return o;
       }
       return new BigDecimal(((Number) o).doubleValue());
     case CHAR:
     case VARCHAR:
       if (o instanceof NlsString) {
         return o;
       }
       return new NlsString((String) o, type.getCharset().name(), type.getCollation());
     case TIME:
       if (o instanceof Calendar) {
         return o;
       }
       calendar = Calendar.getInstance(DateTimeUtils.GMT_ZONE);
       calendar.setTimeInMillis((Integer) o);
       return calendar;
     case DATE:
       if (o instanceof Calendar) {
         return o;
       }
       calendar = Calendar.getInstance(DateTimeUtils.GMT_ZONE);
       calendar.setTimeInMillis(0);
       calendar.add(Calendar.DAY_OF_YEAR, (Integer) o);
       return calendar;
     case TIMESTAMP:
       if (o instanceof Calendar) {
         return o;
       }
       calendar = Calendar.getInstance(DateTimeUtils.GMT_ZONE);
       calendar.setTimeInMillis((Long) o);
       return calendar;
     default:
       return o;
   }
 }
Beispiel #11
0
 /**
  * Derives the list of column names suitable for NATURAL JOIN. These are the columns that occur
  * exactly once on each side of the join.
  *
  * @param leftRowType Row type of left input to the join
  * @param rightRowType Row type of right input to the join
  * @return List of columns that occur once on each side
  */
 public static List<String> deriveNaturalJoinColumnList(
     RelDataType leftRowType, RelDataType rightRowType) {
   final List<String> naturalColumnNames = new ArrayList<>();
   final List<String> leftNames = leftRowType.getFieldNames();
   final List<String> rightNames = rightRowType.getFieldNames();
   for (String name : leftNames) {
     if ((Collections.frequency(leftNames, name) == 1)
         && (Collections.frequency(rightNames, name) == 1)) {
       naturalColumnNames.add(name);
     }
   }
   return naturalColumnNames;
 }
Beispiel #12
0
 public static RelDataType createTypeFromProjection(
     RelDataType type,
     List<String> columnNameList,
     RelDataTypeFactory typeFactory,
     boolean caseSensitive) {
   // If the names in columnNameList and type have case-sensitive differences,
   // the resulting type will use those from type. These are presumably more
   // canonical.
   final List<RelDataTypeField> fields = new ArrayList<>(columnNameList.size());
   for (String name : columnNameList) {
     RelDataTypeField field = type.getField(name, caseSensitive, false);
     fields.add(type.getFieldList().get(field.getIndex()));
   }
   return typeFactory.createStructType(fields);
 }
Beispiel #13
0
 /**
  * Estimates the average size (in bytes) of a value of a type.
  *
  * <p>Nulls count as 1 byte.
  */
 public double typeValueSize(RelDataType type, Comparable value) {
   if (value == null) {
     return 1d;
   }
   switch (type.getSqlTypeName()) {
     case BOOLEAN:
     case TINYINT:
       return 1d;
     case SMALLINT:
       return 2d;
     case INTEGER:
     case FLOAT:
     case REAL:
     case DATE:
     case TIME:
       return 4d;
     case BIGINT:
     case DOUBLE:
     case TIMESTAMP:
     case INTERVAL_DAY_TIME:
     case INTERVAL_YEAR_MONTH:
       return 8d;
     case BINARY:
     case VARBINARY:
       return ((ByteString) value).length();
     case CHAR:
     case VARCHAR:
       return ((NlsString) value).getValue().length() * BYTES_PER_CHARACTER;
     default:
       return 32;
   }
 }
 public RelDataType toSql(RelDataType type) {
   if (type instanceof RelRecordType) {
     return createStructType(
         Lists.transform(
             type.getFieldList(),
             new Function<RelDataTypeField, RelDataType>() {
               public RelDataType apply(RelDataTypeField a0) {
                 return toSql(a0.getType());
               }
             }),
         type.getFieldNames());
   }
   if (type instanceof JavaType) {
     return createTypeWithNullability(createSqlType(type.getSqlTypeName()), type.isNullable());
   }
   return type;
 }
Beispiel #15
0
 /**
  * Internal method to create a call to a literal. Code outside this package should call one of the
  * type-specific methods such as {@link #makeDateLiteral(Calendar)}, {@link
  * #makeLiteral(boolean)}, {@link #makeLiteral(String)}.
  *
  * @param o Value of literal, must be appropriate for the type
  * @param type Type of literal
  * @param typeName SQL type of literal
  * @return Literal
  */
 protected RexLiteral makeLiteral(Comparable o, RelDataType type, SqlTypeName typeName) {
   // All literals except NULL have NOT NULL types.
   type = typeFactory.createTypeWithNullability(type, o == null);
   if (typeName == SqlTypeName.CHAR) {
     // Character literals must have a charset and collation. Populate
     // from the type if necessary.
     assert o instanceof NlsString;
     NlsString nlsString = (NlsString) o;
     if ((nlsString.getCollation() == null) || (nlsString.getCharset() == null)) {
       assert type.getSqlTypeName() == SqlTypeName.CHAR;
       assert type.getCharset().name() != null;
       assert type.getCollation() != null;
       o = new NlsString(nlsString.getValue(), type.getCharset().name(), type.getCollation());
     }
   }
   return new RexLiteral(o, type, typeName);
 }
Beispiel #16
0
 /** Ensures that a type's nullability matches a value's nullability. */
 public RelDataType matchNullability(RelDataType type, RexNode value) {
   boolean typeNullability = type.isNullable();
   boolean valueNullability = value.getType().isNullable();
   if (typeNullability != valueNullability) {
     return getTypeFactory().createTypeWithNullability(type, valueNullability);
   }
   return type;
 }
Beispiel #17
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()
                 + "'");
       }
     }
   }
 }
Beispiel #18
0
 private RexNode makeCastBooleanToExact(RelDataType toType, RexNode exp) {
   final RexNode casted =
       makeCall(
           SqlStdOperatorTable.CASE,
           exp,
           makeExactLiteral(BigDecimal.ONE, toType),
           makeZeroLiteral(toType));
   if (!exp.getType().isNullable()) {
     return casted;
   }
   return makeCall(
       toType,
       SqlStdOperatorTable.CASE,
       ImmutableList.<RexNode>of(
           makeCall(SqlStdOperatorTable.IS_NOT_NULL, exp),
           casted,
           makeNullLiteral(toType.getSqlTypeName())));
 }
 public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
   RelDataType type = opBinding.getOperandType(0);
   if (type.isStruct()) {
     type = type.getFieldList().get(0).getType();
   }
   assert type instanceof ArraySqlType || type instanceof MultisetSqlType;
   if (withOrdinality) {
     final RelDataTypeFactory.FieldInfoBuilder builder = opBinding.getTypeFactory().builder();
     if (type.getComponentType().isStruct()) {
       builder.addAll(type.getComponentType().getFieldList());
     } else {
       builder.add(SqlUtil.deriveAliasFromOrdinal(0), type.getComponentType());
     }
     return builder.add(ORDINALITY_COLUMN_NAME, SqlTypeName.INTEGER).build();
   } else {
     return type.getComponentType();
   }
 }
Beispiel #20
0
 /**
  * Estimates the average size (in bytes) of a value of a type.
  *
  * <p>We assume that the proportion of nulls is negligible, even if the type is nullable.
  */
 public Double averageTypeValueSize(RelDataType type) {
   switch (type.getSqlTypeName()) {
     case BOOLEAN:
     case TINYINT:
       return 1d;
     case SMALLINT:
       return 2d;
     case INTEGER:
     case REAL:
     case DECIMAL:
     case DATE:
     case TIME:
       return 4d;
     case BIGINT:
     case DOUBLE:
     case FLOAT: // sic
     case TIMESTAMP:
     case INTERVAL_DAY_TIME:
     case INTERVAL_YEAR_MONTH:
       return 8d;
     case BINARY:
       return (double) type.getPrecision();
     case VARBINARY:
       return Math.min((double) type.getPrecision(), 100d);
     case CHAR:
       return (double) type.getPrecision() * BYTES_PER_CHARACTER;
     case VARCHAR:
       // Even in large (say VARCHAR(2000)) columns most strings are small
       return Math.min((double) type.getPrecision() * BYTES_PER_CHARACTER, 100d);
     case ROW:
       Double average = 0.0;
       for (RelDataTypeField field : type.getFieldList()) {
         average += averageTypeValueSize(field.getType());
       }
       return average;
     default:
       return null;
   }
 }
 public Type getJavaClass(RelDataType type) {
   if (type instanceof JavaType) {
     JavaType javaType = (JavaType) type;
     return javaType.getJavaClass();
   }
   if (type.isStruct() && type.getFieldCount() == 1) {
     return getJavaClass(type.getFieldList().get(0).getType());
   }
   if (type instanceof BasicSqlType || type instanceof IntervalSqlType) {
     switch (type.getSqlTypeName()) {
       case VARCHAR:
       case CHAR:
         return String.class;
       case DATE:
       case TIME:
       case INTEGER:
       case INTERVAL_YEAR_MONTH:
         return type.isNullable() ? Integer.class : int.class;
       case TIMESTAMP:
       case BIGINT:
       case INTERVAL_DAY_TIME:
         return type.isNullable() ? Long.class : long.class;
       case SMALLINT:
         return type.isNullable() ? Short.class : short.class;
       case TINYINT:
         return type.isNullable() ? Byte.class : byte.class;
       case DECIMAL:
         return BigDecimal.class;
       case BOOLEAN:
         return type.isNullable() ? Boolean.class : boolean.class;
       case DOUBLE:
       case FLOAT: // sic
         return type.isNullable() ? Double.class : double.class;
       case REAL:
         return type.isNullable() ? Float.class : float.class;
       case BINARY:
       case VARBINARY:
         return ByteString.class;
       case ARRAY:
         return Array.class;
       case ANY:
         return Object.class;
     }
   }
   switch (type.getSqlTypeName()) {
     case ROW:
       assert type instanceof RelRecordType;
       if (type instanceof JavaRecordType) {
         return ((JavaRecordType) type).clazz;
       } else {
         return createSyntheticType((RelRecordType) type);
       }
     case MAP:
       return Map.class;
     case ARRAY:
     case MULTISET:
       return List.class;
   }
   return null;
 }
 private SyntheticRecordType(RelDataType relType, String name) {
   this.relType = relType;
   this.name = name;
   assert relType == null || Util.isDistinct(relType.getFieldNames())
       : "field names not distinct: " + relType;
 }
  /**
   * Variant of {@link #trimFields(RelNode, ImmutableBitSet, Set)} for {@link
   * org.apache.hadoop.hive.ql.optimizer.calcite.reloperators.HiveMultiJoin}.
   */
  public TrimResult trimFields(
      HiveMultiJoin join, ImmutableBitSet fieldsUsed, Set<RelDataTypeField> extraFields) {
    final int fieldCount = join.getRowType().getFieldCount();
    final RexNode conditionExpr = join.getCondition();

    // Add in fields used in the condition.
    final Set<RelDataTypeField> combinedInputExtraFields =
        new LinkedHashSet<RelDataTypeField>(extraFields);
    RelOptUtil.InputFinder inputFinder = new RelOptUtil.InputFinder(combinedInputExtraFields);
    inputFinder.inputBitSet.addAll(fieldsUsed);
    conditionExpr.accept(inputFinder);
    final ImmutableBitSet fieldsUsedPlus = inputFinder.inputBitSet.build();

    int inputStartPos = 0;
    int changeCount = 0;
    int newFieldCount = 0;
    List<RelNode> newInputs = new ArrayList<RelNode>();
    List<Mapping> inputMappings = new ArrayList<Mapping>();
    for (RelNode input : join.getInputs()) {
      final RelDataType inputRowType = input.getRowType();
      final int inputFieldCount = inputRowType.getFieldCount();

      // Compute required mapping.
      ImmutableBitSet.Builder inputFieldsUsed = ImmutableBitSet.builder();
      for (int bit : fieldsUsedPlus) {
        if (bit >= inputStartPos && bit < inputStartPos + inputFieldCount) {
          inputFieldsUsed.set(bit - inputStartPos);
        }
      }

      Set<RelDataTypeField> inputExtraFields = Collections.<RelDataTypeField>emptySet();
      TrimResult trimResult = trimChild(join, input, inputFieldsUsed.build(), inputExtraFields);
      newInputs.add(trimResult.left);
      if (trimResult.left != input) {
        ++changeCount;
      }

      final Mapping inputMapping = trimResult.right;
      inputMappings.add(inputMapping);

      // Move offset to point to start of next input.
      inputStartPos += inputFieldCount;
      newFieldCount += inputMapping.getTargetCount();
    }

    Mapping mapping = Mappings.create(MappingType.INVERSE_SURJECTION, fieldCount, newFieldCount);
    int offset = 0;
    int newOffset = 0;
    for (int i = 0; i < inputMappings.size(); i++) {
      Mapping inputMapping = inputMappings.get(i);
      for (IntPair pair : inputMapping) {
        mapping.set(pair.source + offset, pair.target + newOffset);
      }
      offset += inputMapping.getSourceCount();
      newOffset += inputMapping.getTargetCount();
    }

    if (changeCount == 0 && mapping.isIdentity()) {
      return new TrimResult(join, Mappings.createIdentity(fieldCount));
    }

    // Build new join.
    final RexVisitor<RexNode> shuttle =
        new RexPermuteInputsShuttle(mapping, newInputs.toArray(new RelNode[newInputs.size()]));
    RexNode newConditionExpr = conditionExpr.accept(shuttle);

    final RelDataType newRowType =
        RelOptUtil.permute(join.getCluster().getTypeFactory(), join.getRowType(), mapping);
    final RelNode newJoin =
        new HiveMultiJoin(
            join.getCluster(),
            newInputs,
            newConditionExpr,
            newRowType,
            join.getJoinInputs(),
            join.getJoinTypes(),
            join.getJoinFilters());

    return new TrimResult(newJoin, mapping);
  }
Beispiel #24
0
 /**
  * Creates a literal of a given type. The value is assumed to be compatible with the type.
  *
  * @param value Value
  * @param type Type
  * @param allowCast Whether to allow a cast. If false, value is always a {@link RexLiteral} but
  *     may not be the exact type
  * @return Simple literal, or cast simple literal
  */
 public RexNode makeLiteral(Object value, RelDataType type, boolean allowCast) {
   if (value == null) {
     return makeCast(type, constantNull);
   }
   if (type.isNullable()) {
     final RelDataType typeNotNull = typeFactory.createTypeWithNullability(type, false);
     RexNode literalNotNull = makeLiteral(value, typeNotNull, allowCast);
     return makeAbstractCast(type, literalNotNull);
   }
   value = clean(value, type);
   RexLiteral literal;
   final List<RexNode> operands;
   switch (type.getSqlTypeName()) {
     case CHAR:
       return makeCharLiteral(padRight((NlsString) value, type.getPrecision()));
     case VARCHAR:
       literal = makeCharLiteral((NlsString) value);
       if (allowCast) {
         return makeCast(type, literal);
       } else {
         return literal;
       }
     case BINARY:
       return makeBinaryLiteral(padRight((ByteString) value, type.getPrecision()));
     case VARBINARY:
       literal = makeBinaryLiteral((ByteString) value);
       if (allowCast) {
         return makeCast(type, literal);
       } else {
         return literal;
       }
     case TINYINT:
     case SMALLINT:
     case INTEGER:
     case BIGINT:
     case DECIMAL:
       return makeExactLiteral((BigDecimal) value, type);
     case FLOAT:
     case REAL:
     case DOUBLE:
       return makeApproxLiteral((BigDecimal) value, type);
     case BOOLEAN:
       return (Boolean) value ? booleanTrue : booleanFalse;
     case TIME:
       return makeTimeLiteral((Calendar) value, type.getPrecision());
     case DATE:
       return makeDateLiteral((Calendar) value);
     case TIMESTAMP:
       return makeTimestampLiteral((Calendar) value, type.getPrecision());
     case INTERVAL_YEAR_MONTH:
     case INTERVAL_DAY_TIME:
       return makeIntervalLiteral((BigDecimal) value, type.getIntervalQualifier());
     case MAP:
       final MapSqlType mapType = (MapSqlType) type;
       @SuppressWarnings("unchecked")
       final Map<Object, Object> map = (Map) value;
       operands = new ArrayList<RexNode>();
       for (Map.Entry<Object, Object> entry : map.entrySet()) {
         operands.add(makeLiteral(entry.getKey(), mapType.getKeyType(), allowCast));
         operands.add(makeLiteral(entry.getValue(), mapType.getValueType(), allowCast));
       }
       return makeCall(SqlStdOperatorTable.MAP_VALUE_CONSTRUCTOR, operands);
     case ARRAY:
       final ArraySqlType arrayType = (ArraySqlType) type;
       @SuppressWarnings("unchecked")
       final List<Object> listValue = (List) value;
       operands = new ArrayList<RexNode>();
       for (Object entry : listValue) {
         operands.add(makeLiteral(entry, arrayType.getComponentType(), allowCast));
       }
       return makeCall(SqlStdOperatorTable.ARRAY_VALUE_CONSTRUCTOR, operands);
     case ANY:
       return makeLiteral(value, guessType(value), allowCast);
     default:
       throw Util.unexpected(type.getSqlTypeName());
   }
 }
Beispiel #25
0
 /**
  * Looks up a field with a given name, returning null if not found.
  *
  * @param caseSensitive Whether match is case-sensitive
  * @param rowType Row type
  * @param columnName Field name
  * @return Field, or null if not found
  */
 public static RelDataTypeField lookupField(
     boolean caseSensitive, final RelDataType rowType, String columnName) {
   return rowType.getField(columnName, caseSensitive, false);
 }
Beispiel #26
0
 /**
  * Creates an approximate numeric literal (double or float).
  *
  * @param bd literal value
  * @param type approximate numeric type
  * @return new literal
  */
 public RexLiteral makeApproxLiteral(BigDecimal bd, RelDataType type) {
   assert SqlTypeFamily.APPROXIMATE_NUMERIC.getTypeNames().contains(type.getSqlTypeName());
   return makeLiteral(bd, type, SqlTypeName.DOUBLE);
 }
Beispiel #27
0
 /**
  * Creates a list of {@link org.apache.calcite.rex.RexInputRef} expressions, projecting the fields
  * of a given record type.
  */
 public List<RexInputRef> identityProjects(final RelDataType rowType) {
   return Lists.transform(rowType.getFieldList(), TO_INPUT_REF);
 }
Beispiel #28
0
 /**
  * Creates a reference to all the fields in the row.
  *
  * <p>For example, if the input row has type <code>T{f0,f1,f2,f3,f4}</code> then <code>
  * makeRangeReference(T{f0,f1,f2,f3,f4}, S{f3,f4}, 3)</code> is an expression which yields the
  * last 2 fields.
  *
  * @param type Type of the resulting range record.
  * @param offset Index of first field.
  * @param nullable Whether the record is nullable.
  */
 public RexRangeRef makeRangeReference(RelDataType type, int offset, boolean nullable) {
   if (nullable && !type.isNullable()) {
     type = typeFactory.createTypeWithNullability(type, nullable);
   }
   return new RexRangeRef(type, offset);
 }