Example #1
0
 /**
  * Computes the rollup of bit sets.
  *
  * <p>For example, <code>rollup({0}, {1})</code> returns <code>({0, 1}, {0}, {})</code>.
  *
  * <p>Bit sets are not necessarily singletons: <code>rollup({0, 2}, {3, 5})</code> returns <code>
  * ({0, 2, 3, 5}, {0, 2}, {})</code>.
  */
 @VisibleForTesting
 public static ImmutableList<ImmutableBitSet> rollup(List<ImmutableBitSet> bitSets) {
   Set<ImmutableBitSet> builder = Sets.newLinkedHashSet();
   for (; ; ) {
     final ImmutableBitSet union = ImmutableBitSet.union(bitSets);
     builder.add(union);
     if (union.isEmpty()) {
       break;
     }
     bitSets = bitSets.subList(0, bitSets.size() - 1);
   }
   return ImmutableList.copyOf(builder);
 }
Example #2
0
 /**
  * Computes the cube of bit sets.
  *
  * <p>For example, <code>rollup({0}, {1})</code> returns <code>({0, 1}, {0}, {})</code>.
  *
  * <p>Bit sets are not necessarily singletons: <code>rollup({0, 2}, {3, 5})</code> returns <code>
  * ({0, 2, 3, 5}, {0, 2}, {})</code>.
  */
 @VisibleForTesting
 public static ImmutableList<ImmutableBitSet> cube(List<ImmutableBitSet> bitSets) {
   // Given the bit sets [{1}, {2, 3}, {5}],
   // form the lists [[{1}, {}], [{2, 3}, {}], [{5}, {}]].
   final Set<List<ImmutableBitSet>> builder = Sets.newLinkedHashSet();
   for (ImmutableBitSet bitSet : bitSets) {
     builder.add(Arrays.asList(bitSet, ImmutableBitSet.of()));
   }
   Set<ImmutableBitSet> flattenedBitSets = Sets.newLinkedHashSet();
   for (List<ImmutableBitSet> o : Linq4j.product(builder)) {
     flattenedBitSets.add(ImmutableBitSet.union(o));
   }
   return ImmutableList.copyOf(flattenedBitSets);
 }
Example #3
0
 /** Analyzes a GROUPING SETS item in a GROUP BY clause. */
 private static void convertGroupSet(
     SqlValidatorScope scope,
     List<SqlNode> groupExprs,
     Map<Integer, Integer> groupExprProjection,
     ImmutableList.Builder<ImmutableBitSet> builder,
     SqlNode groupExpr) {
   switch (groupExpr.getKind()) {
     case GROUPING_SETS:
       final SqlCall call = (SqlCall) groupExpr;
       for (SqlNode node : call.getOperandList()) {
         convertGroupSet(scope, groupExprs, groupExprProjection, builder, node);
       }
       return;
     case ROW:
       final List<ImmutableBitSet> bitSets =
           analyzeGroupTuple(
               scope, groupExprs, groupExprProjection, ((SqlCall) groupExpr).getOperandList());
       builder.add(ImmutableBitSet.union(bitSets));
       return;
     default:
       builder.add(analyzeGroupExpr(scope, groupExprs, groupExprProjection, groupExpr));
       return;
   }
 }
Example #4
0
  private static void splitJoinCondition(
      List<RelDataTypeField> sysFieldList,
      List<RelNode> inputs,
      RexNode condition,
      List<List<RexNode>> joinKeys,
      List<Integer> filterNulls,
      List<SqlOperator> rangeOp,
      List<RexNode> nonEquiList)
      throws CalciteSemanticException {
    final int sysFieldCount = sysFieldList.size();
    final RelOptCluster cluster = inputs.get(0).getCluster();
    final RexBuilder rexBuilder = cluster.getRexBuilder();

    if (condition instanceof RexCall) {
      RexCall call = (RexCall) condition;
      if (call.getOperator() == SqlStdOperatorTable.AND) {
        for (RexNode operand : call.getOperands()) {
          splitJoinCondition(
              sysFieldList, inputs, operand, joinKeys, filterNulls, rangeOp, nonEquiList);
        }
        return;
      }

      RexNode leftKey = null;
      RexNode rightKey = null;
      int leftInput = 0;
      int rightInput = 0;
      List<RelDataTypeField> leftFields = null;
      List<RelDataTypeField> rightFields = null;
      boolean reverse = false;

      SqlKind kind = call.getKind();

      // Only consider range operators if we haven't already seen one
      if ((kind == SqlKind.EQUALS)
          || (filterNulls != null && kind == SqlKind.IS_NOT_DISTINCT_FROM)
          || (rangeOp != null
              && rangeOp.isEmpty()
              && (kind == SqlKind.GREATER_THAN
                  || kind == SqlKind.GREATER_THAN_OR_EQUAL
                  || kind == SqlKind.LESS_THAN
                  || kind == SqlKind.LESS_THAN_OR_EQUAL))) {
        final List<RexNode> operands = call.getOperands();
        RexNode op0 = operands.get(0);
        RexNode op1 = operands.get(1);

        final ImmutableBitSet projRefs0 = InputFinder.bits(op0);
        final ImmutableBitSet projRefs1 = InputFinder.bits(op1);

        final ImmutableBitSet[] inputsRange = new ImmutableBitSet[inputs.size()];
        int totalFieldCount = 0;
        for (int i = 0; i < inputs.size(); i++) {
          final int firstField = totalFieldCount + sysFieldCount;
          totalFieldCount = firstField + inputs.get(i).getRowType().getFieldCount();
          inputsRange[i] = ImmutableBitSet.range(firstField, totalFieldCount);
        }

        boolean foundBothInputs = false;
        for (int i = 0; i < inputs.size() && !foundBothInputs; i++) {
          if (projRefs0.intersects(inputsRange[i])
              && projRefs0.union(inputsRange[i]).equals(inputsRange[i])) {
            if (leftKey == null) {
              leftKey = op0;
              leftInput = i;
              leftFields = inputs.get(leftInput).getRowType().getFieldList();
            } else {
              rightKey = op0;
              rightInput = i;
              rightFields = inputs.get(rightInput).getRowType().getFieldList();
              reverse = true;
              foundBothInputs = true;
            }
          } else if (projRefs1.intersects(inputsRange[i])
              && projRefs1.union(inputsRange[i]).equals(inputsRange[i])) {
            if (leftKey == null) {
              leftKey = op1;
              leftInput = i;
              leftFields = inputs.get(leftInput).getRowType().getFieldList();
            } else {
              rightKey = op1;
              rightInput = i;
              rightFields = inputs.get(rightInput).getRowType().getFieldList();
              foundBothInputs = true;
            }
          }
        }

        if ((leftKey != null) && (rightKey != null)) {
          // adjustment array
          int[] adjustments = new int[totalFieldCount];
          for (int i = 0; i < inputs.size(); i++) {
            final int adjustment = inputsRange[i].nextSetBit(0);
            for (int j = adjustment; j < inputsRange[i].length(); j++) {
              adjustments[j] = -adjustment;
            }
          }

          // replace right Key input ref
          rightKey =
              rightKey.accept(
                  new RelOptUtil.RexInputConverter(
                      rexBuilder, rightFields, rightFields, adjustments));

          // left key only needs to be adjusted if there are system
          // fields, but do it for uniformity
          leftKey =
              leftKey.accept(
                  new RelOptUtil.RexInputConverter(
                      rexBuilder, leftFields, leftFields, adjustments));

          RelDataType leftKeyType = leftKey.getType();
          RelDataType rightKeyType = rightKey.getType();

          if (leftKeyType != rightKeyType) {
            // perform casting using Hive rules
            TypeInfo rType = TypeConverter.convert(rightKeyType);
            TypeInfo lType = TypeConverter.convert(leftKeyType);
            TypeInfo tgtType = FunctionRegistry.getCommonClassForComparison(lType, rType);

            if (tgtType == null) {
              throw new CalciteSemanticException(
                  "Cannot find common type for join keys "
                      + leftKey
                      + " (type "
                      + leftKeyType
                      + ") and "
                      + rightKey
                      + " (type "
                      + rightKeyType
                      + ")");
            }
            RelDataType targetKeyType = TypeConverter.convert(tgtType, rexBuilder.getTypeFactory());

            if (leftKeyType != targetKeyType
                && TypeInfoUtils.isConversionRequiredForComparison(tgtType, lType)) {
              leftKey = rexBuilder.makeCast(targetKeyType, leftKey);
            }

            if (rightKeyType != targetKeyType
                && TypeInfoUtils.isConversionRequiredForComparison(tgtType, rType)) {
              rightKey = rexBuilder.makeCast(targetKeyType, rightKey);
            }
          }
        }
      }

      if ((leftKey != null) && (rightKey != null)) {
        // found suitable join keys
        // add them to key list, ensuring that if there is a
        // non-equi join predicate, it appears at the end of the
        // key list; also mark the null filtering property
        addJoinKey(joinKeys.get(leftInput), leftKey, (rangeOp != null) && !rangeOp.isEmpty());
        addJoinKey(joinKeys.get(rightInput), rightKey, (rangeOp != null) && !rangeOp.isEmpty());
        if (filterNulls != null && kind == SqlKind.EQUALS) {
          // nulls are considered not matching for equality comparison
          // add the position of the most recently inserted key
          filterNulls.add(joinKeys.get(leftInput).size() - 1);
        }
        if (rangeOp != null && kind != SqlKind.EQUALS && kind != SqlKind.IS_DISTINCT_FROM) {
          if (reverse) {
            kind = reverse(kind);
          }
          rangeOp.add(op(kind, call.getOperator()));
        }
        return;
      } // else fall through and add this condition as nonEqui condition
    }

    // The operator is not of RexCall type
    // So we fail. Fall through.
    // Add this condition to the list of non-equi-join conditions.
    nonEquiList.add(condition);
  }
Example #5
0
  /** Analyzes a component of a tuple in a GROUPING SETS clause. */
  private static ImmutableBitSet analyzeGroupExpr(
      SqlValidatorScope scope,
      List<SqlNode> groupExprs,
      Map<Integer, Integer> groupExprProjection,
      SqlNode groupExpr) {
    final SqlNode expandedGroupExpr = scope.getValidator().expand(groupExpr, scope);

    switch (expandedGroupExpr.getKind()) {
      case ROW:
        return ImmutableBitSet.union(
            analyzeGroupTuple(
                scope,
                groupExprs,
                groupExprProjection,
                ((SqlCall) expandedGroupExpr).getOperandList()));
      case OTHER:
        if (expandedGroupExpr instanceof SqlNodeList
            && ((SqlNodeList) expandedGroupExpr).size() == 0) {
          return ImmutableBitSet.of();
        }
    }

    final int ref = lookupGroupExpr(groupExprs, groupExpr);
    if (expandedGroupExpr instanceof SqlIdentifier) {
      // SQL 2003 does not allow expressions of column references
      SqlIdentifier expr = (SqlIdentifier) expandedGroupExpr;

      // column references should be fully qualified.
      assert expr.names.size() == 2;
      String originalRelName = expr.names.get(0);
      String originalFieldName = expr.names.get(1);

      final SqlValidatorScope.ResolvedImpl resolved = new SqlValidatorScope.ResolvedImpl();
      scope.resolve(ImmutableList.of(originalRelName), false, resolved);

      assert resolved.count() == 1;
      final SqlValidatorScope.Resolve resolve = resolved.only();
      final SqlValidatorNamespace foundNs = resolve.namespace;
      final int childNamespaceIndex = resolve.path.steps().get(0).i;

      int namespaceOffset = 0;

      if (childNamespaceIndex > 0) {
        // If not the first child, need to figure out the width of
        // output types from all the preceding namespaces
        final SqlValidatorScope ancestorScope = resolve.scope;
        assert ancestorScope instanceof ListScope;
        List<SqlValidatorNamespace> children = ((ListScope) ancestorScope).getChildren();

        for (int j = 0; j < childNamespaceIndex; j++) {
          namespaceOffset += children.get(j).getRowType().getFieldCount();
        }
      }

      RelDataTypeField field =
          scope.getValidator().getCatalogReader().field(foundNs.getRowType(), originalFieldName);
      int origPos = namespaceOffset + field.getIndex();

      groupExprProjection.put(origPos, ref);
    }

    return ImmutableBitSet.of(ref);
  }