/** * 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); }
/** * 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); }
/** 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; } }
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); }
/** 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); }