You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2014/11/14 22:33:02 UTC

[54/58] [abbrv] incubator-calcite git commit: [CALCITE-460] Add ImmutableBitSet and replace uses of BitSet

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9d8de38/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPopulationSize.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPopulationSize.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPopulationSize.java
index 2afbc80..2009d09 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPopulationSize.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPopulationSize.java
@@ -26,10 +26,9 @@ import org.apache.calcite.rel.core.Sort;
 import org.apache.calcite.rel.core.Union;
 import org.apache.calcite.rel.core.Values;
 import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.util.BitSets;
 import org.apache.calcite.util.BuiltInMethod;
+import org.apache.calcite.util.ImmutableBitSet;
 
-import java.util.BitSet;
 import java.util.List;
 
 /**
@@ -47,19 +46,19 @@ public class RelMdPopulationSize {
 
   //~ Methods ----------------------------------------------------------------
 
-  public Double getPopulationSize(Filter rel, BitSet groupKey) {
+  public Double getPopulationSize(Filter rel, ImmutableBitSet groupKey) {
     return RelMetadataQuery.getPopulationSize(
         rel.getInput(),
         groupKey);
   }
 
-  public Double getPopulationSize(Sort rel, BitSet groupKey) {
+  public Double getPopulationSize(Sort rel, ImmutableBitSet groupKey) {
     return RelMetadataQuery.getPopulationSize(
         rel.getInput(),
         groupKey);
   }
 
-  public Double getPopulationSize(Union rel, BitSet groupKey) {
+  public Double getPopulationSize(Union rel, ImmutableBitSet groupKey) {
     Double population = 0.0;
     for (RelNode input : rel.getInputs()) {
       Double subPop = RelMetadataQuery.getPopulationSize(input, groupKey);
@@ -71,39 +70,35 @@ public class RelMdPopulationSize {
     return population;
   }
 
-  public Double getPopulationSize(Join rel, BitSet groupKey) {
+  public Double getPopulationSize(Join rel, ImmutableBitSet groupKey) {
     return RelMdUtil.getJoinPopulationSize(rel, groupKey);
   }
 
-  public Double getPopulationSize(SemiJoin rel, BitSet groupKey) {
-    return RelMetadataQuery.getPopulationSize(
-        rel.getLeft(),
-        groupKey);
+  public Double getPopulationSize(SemiJoin rel, ImmutableBitSet groupKey) {
+    return RelMetadataQuery.getPopulationSize(rel.getLeft(), groupKey);
   }
 
-  public Double getPopulationSize(Aggregate rel, BitSet groupKey) {
-    BitSet childKey = new BitSet();
+  public Double getPopulationSize(Aggregate rel, ImmutableBitSet groupKey) {
+    ImmutableBitSet.Builder childKey = ImmutableBitSet.builder();
     RelMdUtil.setAggChildKeys(groupKey, rel, childKey);
-    return RelMetadataQuery.getPopulationSize(
-        rel.getInput(),
-        childKey);
+    return RelMetadataQuery.getPopulationSize(rel.getInput(), childKey.build());
   }
 
-  public Double getPopulationSize(Values rel, BitSet groupKey) {
+  public Double getPopulationSize(Values rel, ImmutableBitSet groupKey) {
     // assume half the rows are duplicates
     return rel.getRows() / 2;
   }
 
-  public Double getPopulationSize(Project rel, BitSet groupKey) {
-    BitSet baseCols = new BitSet();
-    BitSet projCols = new BitSet();
+  public Double getPopulationSize(Project rel, ImmutableBitSet groupKey) {
+    ImmutableBitSet.Builder baseCols = ImmutableBitSet.builder();
+    ImmutableBitSet.Builder projCols = ImmutableBitSet.builder();
     List<RexNode> projExprs = rel.getProjects();
     RelMdUtil.splitCols(projExprs, groupKey, baseCols, projCols);
 
     Double population =
         RelMetadataQuery.getPopulationSize(
             rel.getInput(),
-            baseCols);
+            baseCols.build());
     if (population == null) {
       return null;
     }
@@ -114,7 +109,7 @@ public class RelMdPopulationSize {
       return population;
     }
 
-    for (int bit : BitSets.toIter(projCols)) {
+    for (int bit : projCols.build()) {
       Double subRowCount =
           RelMdUtil.cardOfProjExpr(rel, projExprs.get(bit));
       if (subRowCount == null) {
@@ -132,7 +127,7 @@ public class RelMdPopulationSize {
   }
 
   // Catch-all rule when none of the others apply.
-  public Double getPopulationSize(RelNode rel, BitSet groupKey) {
+  public Double getPopulationSize(RelNode rel, ImmutableBitSet groupKey) {
     // if the keys are unique, return the row count; otherwise, we have
     // no further information on which to return any legitimate value
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9d8de38/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
index e15f074..39a4794 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdPredicates.java
@@ -41,6 +41,7 @@ import org.apache.calcite.rex.RexVisitorImpl;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.util.BitSets;
 import org.apache.calcite.util.BuiltInMethod;
+import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.mapping.Mapping;
 import org.apache.calcite.util.mapping.MappingType;
 import org.apache.calcite.util.mapping.Mappings;
@@ -50,17 +51,16 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Iterators;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 
 import java.util.ArrayList;
 import java.util.BitSet;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.SortedMap;
-import java.util.TreeMap;
 
 /**
  * Utility to infer Predicates that are applicable above a RelNode.
@@ -151,7 +151,7 @@ public class RelMdPredicates {
 
     List<RexNode> projectPullUpPredicates = new ArrayList<RexNode>();
 
-    BitSet columnsMapped = new BitSet(child.getRowType().getFieldCount());
+    ImmutableBitSet.Builder columnsMappedBuilder = ImmutableBitSet.builder();
     Mapping m = Mappings.create(MappingType.PARTIAL_FUNCTION,
         child.getRowType().getFieldCount(),
         project.getRowType().getFieldCount());
@@ -160,15 +160,16 @@ public class RelMdPredicates {
       if (o.e instanceof RexInputRef) {
         int sIdx = ((RexInputRef) o.e).getIndex();
         m.set(sIdx, o.i);
-        columnsMapped.set(sIdx);
+        columnsMappedBuilder.set(sIdx);
       }
     }
 
     // Go over childPullUpPredicates. If a predicate only contains columns in
     // 'columnsMapped' construct a new predicate based on mapping.
+    final ImmutableBitSet columnsMapped = columnsMappedBuilder.build();
     for (RexNode r : childInfo.pulledUpPredicates) {
-      BitSet rCols = RelOptUtil.InputFinder.bits(r);
-      if (BitSets.contains(columnsMapped, rCols)) {
+      ImmutableBitSet rCols = RelOptUtil.InputFinder.bits(r);
+      if (columnsMapped.contains(rCols)) {
         r = r.accept(new RexPermuteInputsShuttle(m, child));
         projectPullUpPredicates.add(r);
       }
@@ -235,18 +236,18 @@ public class RelMdPredicates {
 
     List<RexNode> aggPullUpPredicates = new ArrayList<RexNode>();
 
-    BitSet groupKeys = agg.getGroupSet();
+    ImmutableBitSet groupKeys = agg.getGroupSet();
     Mapping m = Mappings.create(MappingType.PARTIAL_FUNCTION,
         child.getRowType().getFieldCount(), agg.getRowType().getFieldCount());
 
     int i = 0;
-    for (int j : BitSets.toIter(groupKeys)) {
+    for (int j : groupKeys) {
       m.set(j, i++);
     }
 
     for (RexNode r : childInfo.pulledUpPredicates) {
-      BitSet rCols = RelOptUtil.InputFinder.bits(r);
-      if (BitSets.contains(groupKeys, rCols)) {
+      ImmutableBitSet rCols = RelOptUtil.InputFinder.bits(r);
+      if (groupKeys.contains(rCols)) {
         r = r.accept(new RexPermuteInputsShuttle(m, child));
         aggPullUpPredicates.add(r);
       }
@@ -316,11 +317,11 @@ public class RelMdPredicates {
     final int nSysFields;
     final int nFieldsLeft;
     final int nFieldsRight;
-    final BitSet leftFieldsBitSet;
-    final BitSet rightFieldsBitSet;
-    final BitSet allFieldsBitSet;
+    final ImmutableBitSet leftFieldsBitSet;
+    final ImmutableBitSet rightFieldsBitSet;
+    final ImmutableBitSet allFieldsBitSet;
     SortedMap<Integer, BitSet> equivalence;
-    final Map<String, BitSet> exprFields;
+    final Map<String, ImmutableBitSet> exprFields;
     final Set<String> allExprsDigests;
     final Set<String> equalityPredicates;
     final RexNode leftChildPredicates;
@@ -333,13 +334,14 @@ public class RelMdPredicates {
       nFieldsLeft = joinRel.getLeft().getRowType().getFieldList().size();
       nFieldsRight = joinRel.getRight().getRowType().getFieldList().size();
       nSysFields = joinRel.getSystemFieldList().size();
-      leftFieldsBitSet = BitSets.range(nSysFields, nSysFields + nFieldsLeft);
-      rightFieldsBitSet = BitSets.range(nSysFields + nFieldsLeft,
+      leftFieldsBitSet = ImmutableBitSet.range(nSysFields,
+          nSysFields + nFieldsLeft);
+      rightFieldsBitSet = ImmutableBitSet.range(nSysFields + nFieldsLeft,
           nSysFields + nFieldsLeft + nFieldsRight);
-      allFieldsBitSet = BitSets.range(0,
+      allFieldsBitSet = ImmutableBitSet.range(0,
           nSysFields + nFieldsLeft + nFieldsRight);
 
-      exprFields = new HashMap<String, BitSet>();
+      exprFields = Maps.newHashMap();
       allExprsDigests = new HashSet<String>();
 
       if (lPreds == null) {
@@ -370,7 +372,7 @@ public class RelMdPredicates {
         }
       }
 
-      equivalence = new TreeMap<Integer, BitSet>();
+      equivalence = Maps.newTreeMap();
       equalityPredicates = new HashSet<String>();
       for (int i = 0; i < nSysFields + nFieldsLeft + nFieldsRight; i++) {
         equivalence.put(i, BitSets.of(i));
@@ -444,10 +446,10 @@ public class RelMdPredicates {
       List<RexNode> rightInferredPredicates = new ArrayList<RexNode>();
 
       for (RexNode iP : inferredPredicates) {
-        BitSet iPBitSet = RelOptUtil.InputFinder.bits(iP);
-        if (BitSets.contains(leftFieldsBitSet, iPBitSet)) {
+        ImmutableBitSet iPBitSet = RelOptUtil.InputFinder.bits(iP);
+        if (leftFieldsBitSet.contains(iPBitSet)) {
           leftInferredPredicates.add(iP.accept(leftPermute));
-        } else if (BitSets.contains(rightFieldsBitSet, iPBitSet)) {
+        } else if (rightFieldsBitSet.contains(iPBitSet)) {
           rightInferredPredicates.add(iP.accept(rightPermute));
         }
       }
@@ -484,7 +486,7 @@ public class RelMdPredicates {
 
     private void infer(RexNode predicates, Set<String> allExprsDigests,
         List<RexNode> inferedPredicates, boolean includeEqualityInference,
-        BitSet inferringFields) {
+        ImmutableBitSet inferringFields) {
       for (RexNode r : RelOptUtil.conjunctions(predicates)) {
         if (!includeEqualityInference
             && equalityPredicates.contains(r.toString())) {
@@ -494,7 +496,7 @@ public class RelMdPredicates {
           RexNode tr = r.accept(
               new RexPermuteInputsShuttle(m, joinRel.getInput(0),
                   joinRel.getInput(1)));
-          if (BitSets.contains(inferringFields, RelOptUtil.InputFinder.bits(tr))
+          if (inferringFields.contains(RelOptUtil.InputFinder.bits(tr))
               && !allExprsDigests.contains(tr.toString())
               && !isAlwaysTrue(tr)) {
             inferedPredicates.add(tr);
@@ -507,7 +509,7 @@ public class RelMdPredicates {
     Iterable<Mapping> mappings(final RexNode predicate) {
       return new Iterable<Mapping>() {
         public Iterator<Mapping> iterator() {
-          BitSet fields = exprFields.get(predicate.toString());
+          ImmutableBitSet fields = exprFields.get(predicate.toString());
           if (fields.cardinality() == 0) {
             return Iterators.emptyIterator();
           }
@@ -596,7 +598,7 @@ public class RelMdPredicates {
       Mapping nextMapping;
       boolean firstCall;
 
-      ExprsItr(BitSet fields) {
+      ExprsItr(ImmutableBitSet fields) {
         nextMapping = null;
         columns = new int[fields.cardinality()];
         columnSets = new BitSet[fields.cardinality()];

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9d8de38/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java
index 2549570..568f7ce 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdRowCount.java
@@ -25,10 +25,9 @@ import org.apache.calcite.rel.core.Sort;
 import org.apache.calcite.rel.core.Union;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.util.BuiltInMethod;
+import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.NumberUtil;
 
-import java.util.BitSet;
-
 /**
  * RelMdRowCount supplies a default implementation of
  * {@link RelMetadataQuery#getRowCount} for the standard logical algebra.
@@ -83,10 +82,7 @@ public class RelMdRowCount {
   }
 
   public Double getRowCount(Aggregate rel) {
-    BitSet groupKey = new BitSet();
-    for (int i = 0; i < rel.getGroupCount(); i++) {
-      groupKey.set(i);
-    }
+    ImmutableBitSet groupKey = ImmutableBitSet.range(rel.getGroupCount());
 
     // rowcount is the cardinality of the group by columns
     Double distinctRowCount =

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9d8de38/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java
index 1706e13..3bffe26 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdSelectivity.java
@@ -28,8 +28,8 @@ import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
-import org.apache.calcite.util.BitSets;
 import org.apache.calcite.util.BuiltInMethod;
+import org.apache.calcite.util.ImmutableBitSet;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -157,7 +157,7 @@ public class RelMdSelectivity {
     List<RexNode> notPushable = new ArrayList<RexNode>();
     List<RexNode> pushable = new ArrayList<RexNode>();
     RelOptUtil.splitFilters(
-        BitSets.range(rel.getRowType().getFieldCount()),
+        ImmutableBitSet.range(rel.getRowType().getFieldCount()),
         predicate,
         pushable,
         notPushable);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9d8de38/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUniqueKeys.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUniqueKeys.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUniqueKeys.java
index 55083d8..a84a94e 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUniqueKeys.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUniqueKeys.java
@@ -29,8 +29,10 @@ import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.util.BitSets;
 import org.apache.calcite.util.BuiltInMethod;
+import org.apache.calcite.util.ImmutableBitSet;
+
+import com.google.common.collect.ImmutableSet;
 
-import java.util.BitSet;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -52,19 +54,20 @@ public class RelMdUniqueKeys {
 
   //~ Methods ----------------------------------------------------------------
 
-  public Set<BitSet> getUniqueKeys(Filter rel, boolean ignoreNulls) {
+  public Set<ImmutableBitSet> getUniqueKeys(Filter rel, boolean ignoreNulls) {
     return RelMetadataQuery.getUniqueKeys(rel.getInput(), ignoreNulls);
   }
 
-  public Set<BitSet> getUniqueKeys(Sort rel, boolean ignoreNulls) {
+  public Set<ImmutableBitSet> getUniqueKeys(Sort rel, boolean ignoreNulls) {
     return RelMetadataQuery.getUniqueKeys(rel.getInput(), ignoreNulls);
   }
 
-  public Set<BitSet> getUniqueKeys(Correlator rel, boolean ignoreNulls) {
+  public Set<ImmutableBitSet> getUniqueKeys(Correlator rel,
+      boolean ignoreNulls) {
     return RelMetadataQuery.getUniqueKeys(rel.getLeft(), ignoreNulls);
   }
 
-  public Set<BitSet> getUniqueKeys(Project rel, boolean ignoreNulls) {
+  public Set<ImmutableBitSet> getUniqueKeys(Project rel, boolean ignoreNulls) {
     // LogicalProject maps a set of rows to a different set;
     // Without knowledge of the mapping function(whether it
     // preserves uniqueness), it is only safe to derive uniqueness
@@ -76,7 +79,7 @@ public class RelMdUniqueKeys {
 
     List<RexNode> projExprs = rel.getProjects();
 
-    Set<BitSet> projUniqueKeySet = new HashSet<BitSet>();
+    Set<ImmutableBitSet> projUniqueKeySet = new HashSet<ImmutableBitSet>();
 
     // Build an input to output position map.
     for (int i = 0; i < projExprs.size(); i++) {
@@ -92,14 +95,14 @@ public class RelMdUniqueKeys {
       return projUniqueKeySet;
     }
 
-    Set<BitSet> childUniqueKeySet =
+    Set<ImmutableBitSet> childUniqueKeySet =
         RelMetadataQuery.getUniqueKeys(rel.getInput(), ignoreNulls);
 
     if (childUniqueKeySet != null) {
       // Now add to the projUniqueKeySet the child keys that are fully
       // projected.
-      for (BitSet colMask : childUniqueKeySet) {
-        BitSet tmpMask = new BitSet();
+      for (ImmutableBitSet colMask : childUniqueKeySet) {
+        ImmutableBitSet.Builder tmpMask = ImmutableBitSet.builder();
         boolean completeKeyProjected = true;
         for (int bit : BitSets.toIter(colMask)) {
           if (mapInToOutPos.containsKey(bit)) {
@@ -112,7 +115,7 @@ public class RelMdUniqueKeys {
           }
         }
         if (completeKeyProjected) {
-          projUniqueKeySet.add(tmpMask);
+          projUniqueKeySet.add(tmpMask.build());
         }
       }
     }
@@ -120,7 +123,7 @@ public class RelMdUniqueKeys {
     return projUniqueKeySet;
   }
 
-  public Set<BitSet> getUniqueKeys(Join rel, boolean ignoreNulls) {
+  public Set<ImmutableBitSet> getUniqueKeys(Join rel, boolean ignoreNulls) {
     final RelNode left = rel.getLeft();
     final RelNode right = rel.getRight();
 
@@ -133,31 +136,29 @@ public class RelMdUniqueKeys {
     // that is undesirable, use RelMetadataQuery.areColumnsUnique() as
     // an alternative way of getting unique key information.
 
-    Set<BitSet> retSet = new HashSet<BitSet>();
-    Set<BitSet> leftSet = RelMetadataQuery.getUniqueKeys(left, ignoreNulls);
-    Set<BitSet> rightSet = null;
+    Set<ImmutableBitSet> retSet = new HashSet<ImmutableBitSet>();
+    Set<ImmutableBitSet> leftSet =
+        RelMetadataQuery.getUniqueKeys(left, ignoreNulls);
+    Set<ImmutableBitSet> rightSet = null;
 
-    Set<BitSet> tmpRightSet =
+    Set<ImmutableBitSet> tmpRightSet =
         RelMetadataQuery.getUniqueKeys(right, ignoreNulls);
     int nFieldsOnLeft = left.getRowType().getFieldCount();
 
     if (tmpRightSet != null) {
-      rightSet = new HashSet<BitSet>();
-      for (BitSet colMask : tmpRightSet) {
-        BitSet tmpMask = new BitSet();
-        for (int bit : BitSets.toIter(colMask)) {
+      rightSet = new HashSet<ImmutableBitSet>();
+      for (ImmutableBitSet colMask : tmpRightSet) {
+        ImmutableBitSet.Builder tmpMask = ImmutableBitSet.builder();
+        for (int bit : colMask) {
           tmpMask.set(bit + nFieldsOnLeft);
         }
-        rightSet.add(tmpMask);
+        rightSet.add(tmpMask.build());
       }
 
       if (leftSet != null) {
-        for (BitSet colMaskRight : rightSet) {
-          for (BitSet colMaskLeft : leftSet) {
-            BitSet colMaskConcat = new BitSet();
-            colMaskConcat.or(colMaskLeft);
-            colMaskConcat.or(colMaskRight);
-            retSet.add(colMaskConcat);
+        for (ImmutableBitSet colMaskRight : rightSet) {
+          for (ImmutableBitSet colMaskLeft : leftSet) {
+            retSet.add(colMaskLeft.union(colMaskRight));
           }
         }
       }
@@ -196,28 +197,20 @@ public class RelMdUniqueKeys {
     return retSet;
   }
 
-  public Set<BitSet> getUniqueKeys(SemiJoin rel, boolean ignoreNulls) {
+  public Set<ImmutableBitSet> getUniqueKeys(SemiJoin rel, boolean ignoreNulls) {
     // only return the unique keys from the LHS since a semijoin only
     // returns the LHS
     return RelMetadataQuery.getUniqueKeys(rel.getLeft(), ignoreNulls);
   }
 
-  public Set<BitSet> getUniqueKeys(Aggregate rel, boolean ignoreNulls) {
-    Set<BitSet> retSet = new HashSet<BitSet>();
-
+  public Set<ImmutableBitSet> getUniqueKeys(Aggregate rel,
+      boolean ignoreNulls) {
     // group by keys form a unique key
-    if (rel.getGroupCount() > 0) {
-      BitSet groupKey = new BitSet();
-      for (int i = 0; i < rel.getGroupCount(); i++) {
-        groupKey.set(i);
-      }
-      retSet.add(groupKey);
-    }
-    return retSet;
+    return ImmutableSet.of(rel.getGroupSet());
   }
 
   // Catch-all rule when none of the others apply.
-  public Set<BitSet> getUniqueKeys(RelNode rel, boolean ignoreNulls) {
+  public Set<ImmutableBitSet> getUniqueKeys(RelNode rel, boolean ignoreNulls) {
     // no information available
     return null;
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9d8de38/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java
index e3128fb..b9eb267 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdUtil.java
@@ -20,7 +20,6 @@ import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.Aggregate;
 import org.apache.calcite.rel.core.AggregateCall;
-import org.apache.calcite.rel.core.JoinInfo;
 import org.apache.calcite.rel.core.JoinRelType;
 import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.SemiJoin;
@@ -36,15 +35,13 @@ import org.apache.calcite.sql.SqlFunctionCategory;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.type.OperandTypes;
 import org.apache.calcite.sql.type.ReturnTypes;
-import org.apache.calcite.util.BitSets;
-import org.apache.calcite.util.Bug;
+import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.NumberUtil;
 
 import com.google.common.collect.ImmutableList;
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
-import java.util.BitSet;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -160,16 +157,18 @@ public class RelMdUtil {
       RelNode dimRel,
       List<Integer> factKeyList,
       List<Integer> dimKeyList) {
-    BitSet factKeys = new BitSet();
+    ImmutableBitSet.Builder factKeys = ImmutableBitSet.builder();
     for (int factCol : factKeyList) {
       factKeys.set(factCol);
     }
-    BitSet dimKeys = new BitSet();
+    ImmutableBitSet.Builder dimKeyBuilder = ImmutableBitSet.builder();
     for (int dimCol : dimKeyList) {
-      dimKeys.set(dimCol);
+      dimKeyBuilder.set(dimCol);
     }
+    final ImmutableBitSet dimKeys = dimKeyBuilder.build();
 
-    Double factPop = RelMetadataQuery.getPopulationSize(factRel, factKeys);
+    Double factPop =
+        RelMetadataQuery.getPopulationSize(factRel, factKeys.build());
     if (factPop == null) {
       // use the dimension population if the fact population is
       // unavailable; since we're filtering the fact table, that's
@@ -200,7 +199,7 @@ public class RelMdUtil {
       selectivity =
           Math.pow(
               0.1,
-              dimKeys.cardinality());
+              dimKeyBuilder.cardinality());
     } else if (selectivity > 1.0) {
       selectivity = 1.0;
     }
@@ -220,7 +219,7 @@ public class RelMdUtil {
    */
   public static boolean areColumnsDefinitelyUnique(
       RelNode rel,
-      BitSet colMask) {
+      ImmutableBitSet colMask) {
     Boolean b = RelMetadataQuery.areColumnsUnique(rel, colMask, false);
     return b != null && b;
   }
@@ -228,13 +227,11 @@ public class RelMdUtil {
   public static Boolean areColumnsUnique(
       RelNode rel,
       List<RexInputRef> columnRefs) {
-    BitSet colMask = new BitSet();
-
+    ImmutableBitSet.Builder colMask = ImmutableBitSet.builder();
     for (RexInputRef columnRef : columnRefs) {
       colMask.set(columnRef.getIndex());
     }
-
-    return RelMetadataQuery.areColumnsUnique(rel, colMask);
+    return RelMetadataQuery.areColumnsUnique(rel, colMask.build());
   }
 
   public static boolean areColumnsDefinitelyUnique(RelNode rel,
@@ -256,7 +253,7 @@ public class RelMdUtil {
    * if no metadata is available)
    */
   public static boolean areColumnsDefinitelyUniqueWhenNullsFiltered(RelNode rel,
-      BitSet colMask) {
+      ImmutableBitSet colMask) {
     Boolean b = RelMetadataQuery.areColumnsUnique(rel, colMask, true);
     if (b == null) {
       return false;
@@ -267,13 +264,13 @@ public class RelMdUtil {
   public static Boolean areColumnsUniqueWhenNullsFiltered(
       RelNode rel,
       List<RexInputRef> columnRefs) {
-    BitSet colMask = new BitSet();
+    ImmutableBitSet.Builder colMask = ImmutableBitSet.builder();
 
     for (RexInputRef columnRef : columnRefs) {
       colMask.set(columnRef.getIndex());
     }
 
-    return RelMetadataQuery.areColumnsUnique(rel, colMask, true);
+    return RelMetadataQuery.areColumnsUnique(rel, colMask.build(), true);
   }
 
   public static boolean areColumnsDefinitelyUniqueWhenNullsFiltered(
@@ -288,7 +285,7 @@ public class RelMdUtil {
 
   /**
    * Separates a bit-mask representing a join into masks representing the left
-   * and right inputs into the join
+   * and right inputs into the join.
    *
    * @param groupKey      original bit-mask
    * @param leftMask      left bit-mask to be set
@@ -296,11 +293,11 @@ public class RelMdUtil {
    * @param nFieldsOnLeft number of fields in the left input
    */
   public static void setLeftRightBitmaps(
-      BitSet groupKey,
-      BitSet leftMask,
-      BitSet rightMask,
+      ImmutableBitSet groupKey,
+      ImmutableBitSet.Builder leftMask,
+      ImmutableBitSet.Builder rightMask,
       int nFieldsOnLeft) {
-    for (int bit : BitSets.toIter(groupKey)) {
+    for (int bit : groupKey) {
       if (bit < nFieldsOnLeft) {
         leftMask.set(bit);
       } else {
@@ -434,35 +431,6 @@ public class RelMdUtil {
   }
 
   /**
-   * Locates the columns corresponding to equijoins within a joinrel.
-   *
-   * @param leftChild     left input into the join
-   * @param rightChild    right input into the join
-   * @param predicate     join predicate
-   * @param leftJoinCols  bitmap that will be set with the columns on the LHS
-   *                      of the join that participate in equijoins
-   * @param rightJoinCols bitmap that will be set with the columns on the RHS
-   *                      of the join that participate in equijoins
-   * @return remaining join filters that are not equijoins; may return a
-   * {@link RexLiteral} true, but never null
-   *
-   * @deprecated Will be removed after 0.9.1
-   */
-  public static RexNode findEquiJoinCols(
-      RelNode leftChild,
-      RelNode rightChild,
-      RexNode predicate,
-      BitSet leftJoinCols,
-      BitSet rightJoinCols) {
-    Bug.upgrade("remove after 0.9.1");
-    // locate the equijoin conditions
-    final JoinInfo joinInfo = JoinInfo.of(leftChild, rightChild, predicate);
-    BitSets.populate(leftJoinCols, joinInfo.leftKeys);
-    BitSets.populate(rightJoinCols, joinInfo.rightKeys);
-    return joinInfo.getRemaining(leftChild.getCluster().getRexBuilder());
-  }
-
-  /**
    * AND's two predicates together, either of which may be null, removing
    * redundant filters.
    *
@@ -527,18 +495,18 @@ public class RelMdUtil {
 
   /**
    * Takes a bitmap representing a set of input references and extracts the
-   * ones that reference the group by columns in an aggregate
+   * ones that reference the group by columns in an aggregate.
    *
    * @param groupKey the original bitmap
    * @param aggRel   the aggregate
    * @param childKey sets bits from groupKey corresponding to group by columns
    */
   public static void setAggChildKeys(
-      BitSet groupKey,
+      ImmutableBitSet groupKey,
       Aggregate aggRel,
-      BitSet childKey) {
+      ImmutableBitSet.Builder childKey) {
     List<AggregateCall> aggCalls = aggRel.getAggCallList();
-    for (int bit : BitSets.toIter(groupKey)) {
+    for (int bit : groupKey) {
       if (bit < aggRel.getGroupCount()) {
         // group by column
         childKey.set(bit);
@@ -556,7 +524,6 @@ public class RelMdUtil {
   /**
    * Forms two bitmaps by splitting the columns in a bitmap according to
    * whether or not the column references the child input or is an expression
-   *
    * @param projExprs Project expressions
    * @param groupKey  Bitmap whose columns will be split
    * @param baseCols  Bitmap representing columns from the child input
@@ -564,10 +531,10 @@ public class RelMdUtil {
    */
   public static void splitCols(
       List<RexNode> projExprs,
-      BitSet groupKey,
-      BitSet baseCols,
-      BitSet projCols) {
-    for (int bit : BitSets.toIter(groupKey)) {
+      ImmutableBitSet groupKey,
+      ImmutableBitSet.Builder baseCols,
+      ImmutableBitSet.Builder projCols) {
+    for (int bit : groupKey) {
       final RexNode e = projExprs.get(bit);
       if (e instanceof RexInputRef) {
         baseCols.set(((RexInputRef) e).getIndex());
@@ -598,9 +565,9 @@ public class RelMdUtil {
    */
   public static Double getJoinPopulationSize(
       RelNode joinRel,
-      BitSet groupKey) {
-    BitSet leftMask = new BitSet();
-    BitSet rightMask = new BitSet();
+      ImmutableBitSet groupKey) {
+    ImmutableBitSet.Builder leftMask = ImmutableBitSet.builder();
+    ImmutableBitSet.Builder rightMask = ImmutableBitSet.builder();
     RelNode left = joinRel.getInputs().get(0);
     RelNode right = joinRel.getInputs().get(1);
 
@@ -615,10 +582,10 @@ public class RelMdUtil {
         NumberUtil.multiply(
             RelMetadataQuery.getPopulationSize(
                 left,
-                leftMask),
+                leftMask.build()),
             RelMetadataQuery.getPopulationSize(
                 right,
-                rightMask));
+                rightMask.build()));
 
     return RelMdUtil.numDistinctVals(
         population,
@@ -640,12 +607,12 @@ public class RelMdUtil {
   public static Double getJoinDistinctRowCount(
       RelNode joinRel,
       JoinRelType joinType,
-      BitSet groupKey,
+      ImmutableBitSet groupKey,
       RexNode predicate,
       boolean useMaxNdv) {
     Double distRowCount;
-    BitSet leftMask = new BitSet();
-    BitSet rightMask = new BitSet();
+    ImmutableBitSet.Builder leftMask = ImmutableBitSet.builder();
+    ImmutableBitSet.Builder rightMask = ImmutableBitSet.builder();
     RelNode left = joinRel.getInputs().get(0);
     RelNode right = joinRel.getInputs().get(1);
 
@@ -685,22 +652,22 @@ public class RelMdUtil {
     if (useMaxNdv) {
       distRowCount = Math.max(RelMetadataQuery.getDistinctRowCount(
                 left,
-                leftMask,
+                leftMask.build(),
                 leftPred),
             RelMetadataQuery.getDistinctRowCount(
                 right,
-                rightMask,
+                rightMask.build(),
                 rightPred));
     } else {
       distRowCount =
         NumberUtil.multiply(
             RelMetadataQuery.getDistinctRowCount(
                 left,
-                leftMask,
+                leftMask.build(),
                 leftPred),
             RelMetadataQuery.getDistinctRowCount(
                 right,
-                rightMask,
+                rightMask.build(),
                 rightPred));
     }
 
@@ -723,8 +690,7 @@ public class RelMdUtil {
 
     public Double visitInputRef(RexInputRef var) {
       int index = var.getIndex();
-      BitSet col = new BitSet(index);
-      col.set(index);
+      ImmutableBitSet col = ImmutableBitSet.of(index);
       Double distinctRowCount =
           RelMetadataQuery.getDistinctRowCount(
               rel.getInput(),

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9d8de38/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java
index 4d86f79..c537ef1 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMetadataQuery.java
@@ -22,10 +22,10 @@ import org.apache.calcite.plan.RelOptTable;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.sql.SqlExplainLevel;
+import org.apache.calcite.util.ImmutableBitSet;
 
 import com.google.common.collect.Iterables;
 
-import java.util.BitSet;
 import java.util.Set;
 
 /**
@@ -214,7 +214,7 @@ public abstract class RelMetadataQuery {
    * @return set of keys, or null if this information cannot be determined
    * (whereas empty set indicates definitely no keys at all)
    */
-  public static Set<BitSet> getUniqueKeys(RelNode rel) {
+  public static Set<ImmutableBitSet> getUniqueKeys(RelNode rel) {
     final BuiltInMetadata.UniqueKeys metadata =
         rel.metadata(BuiltInMetadata.UniqueKeys.class);
     return metadata.getUniqueKeys(false);
@@ -231,7 +231,8 @@ public abstract class RelMetadataQuery {
    * @return set of keys, or null if this information cannot be determined
    * (whereas empty set indicates definitely no keys at all)
    */
-  public static Set<BitSet> getUniqueKeys(RelNode rel, boolean ignoreNulls) {
+  public static Set<ImmutableBitSet> getUniqueKeys(RelNode rel,
+      boolean ignoreNulls) {
     final BuiltInMetadata.UniqueKeys metadata =
         rel.metadata(BuiltInMetadata.UniqueKeys.class);
     return metadata.getUniqueKeys(ignoreNulls);
@@ -239,7 +240,7 @@ public abstract class RelMetadataQuery {
 
   /**
    * Returns the
-   * {@link BuiltInMetadata.ColumnUniqueness#areColumnsUnique(BitSet, boolean)}
+   * {@link BuiltInMetadata.ColumnUniqueness#areColumnsUnique(org.apache.calcite.util.ImmutableBitSet, boolean)}
    * statistic.
    *
    * @param rel     the relational expression
@@ -248,7 +249,7 @@ public abstract class RelMetadataQuery {
    * @return true or false depending on whether the columns are unique, or
    * null if not enough information is available to make that determination
    */
-  public static Boolean areColumnsUnique(RelNode rel, BitSet columns) {
+  public static Boolean areColumnsUnique(RelNode rel, ImmutableBitSet columns) {
     final BuiltInMetadata.ColumnUniqueness metadata =
         rel.metadata(BuiltInMetadata.ColumnUniqueness.class);
     return metadata.areColumnsUnique(columns, false);
@@ -256,7 +257,7 @@ public abstract class RelMetadataQuery {
 
   /**
    * Returns the
-   * {@link BuiltInMetadata.ColumnUniqueness#areColumnsUnique(BitSet, boolean)}
+   * {@link BuiltInMetadata.ColumnUniqueness#areColumnsUnique(org.apache.calcite.util.ImmutableBitSet, boolean)}
    * statistic.
    *
    * @param rel         the relational expression
@@ -267,7 +268,7 @@ public abstract class RelMetadataQuery {
    * @return true or false depending on whether the columns are unique, or
    * null if not enough information is available to make that determination
    */
-  public static Boolean areColumnsUnique(RelNode rel, BitSet columns,
+  public static Boolean areColumnsUnique(RelNode rel, ImmutableBitSet columns,
       boolean ignoreNulls) {
     final BuiltInMetadata.ColumnUniqueness metadata =
         rel.metadata(BuiltInMetadata.ColumnUniqueness.class);
@@ -276,7 +277,7 @@ public abstract class RelMetadataQuery {
 
   /**
    * Returns the
-   * {@link BuiltInMetadata.PopulationSize#getPopulationSize(BitSet)}
+   * {@link BuiltInMetadata.PopulationSize#getPopulationSize(org.apache.calcite.util.ImmutableBitSet)}
    * statistic.
    *
    * @param rel      the relational expression
@@ -285,7 +286,8 @@ public abstract class RelMetadataQuery {
    * @return distinct row count for the given groupKey, or null if no reliable
    * estimate can be determined
    */
-  public static Double getPopulationSize(RelNode rel, BitSet groupKey) {
+  public static Double getPopulationSize(RelNode rel,
+      ImmutableBitSet groupKey) {
     final BuiltInMetadata.PopulationSize metadata =
         rel.metadata(BuiltInMetadata.PopulationSize.class);
     Double result = metadata.getPopulationSize(groupKey);
@@ -294,7 +296,7 @@ public abstract class RelMetadataQuery {
 
   /**
    * Returns the
-   * {@link BuiltInMetadata.DistinctRowCount#getDistinctRowCount(BitSet, RexNode)}
+   * {@link BuiltInMetadata.DistinctRowCount#getDistinctRowCount(org.apache.calcite.util.ImmutableBitSet, org.apache.calcite.rex.RexNode)}
    * statistic.
    *
    * @param rel       the relational expression
@@ -305,7 +307,7 @@ public abstract class RelMetadataQuery {
    */
   public static Double getDistinctRowCount(
       RelNode rel,
-      BitSet groupKey,
+      ImmutableBitSet groupKey,
       RexNode predicate) {
     final BuiltInMetadata.DistinctRowCount metadata =
         rel.metadata(BuiltInMetadata.DistinctRowCount.class);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9d8de38/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java
index 915ae87..f513cad 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java
@@ -31,7 +31,7 @@ import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
-import org.apache.calcite.util.BitSets;
+import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 
@@ -40,7 +40,6 @@ import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
 
 import java.util.ArrayList;
-import java.util.BitSet;
 import java.util.HashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -124,12 +123,12 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
         aggregate.getRowType().getFieldList();
     final List<RexInputRef> refs = new ArrayList<RexInputRef>();
     final List<String> fieldNames = aggregate.getRowType().getFieldNames();
-    final BitSet groupSet = aggregate.getGroupSet();
+    final ImmutableBitSet groupSet = aggregate.getGroupSet();
     for (int i : Util.range(groupSet.cardinality())) {
       refs.add(RexInputRef.of(i, aggFields));
     }
 
-    // Aggregate the original relation, including any non-distinct aggs.
+    // Aggregate the original relation, including any non-distinct aggregates.
 
     List<AggregateCall> newAggCallList = new ArrayList<AggregateCall>();
     final int groupCount = groupSet.cardinality();
@@ -147,7 +146,7 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
       newAggCallList.add(aggCall);
     }
 
-    // In the case where there are no non-distinct aggs (regardless of
+    // In the case where there are no non-distinct aggregates (regardless of
     // whether there are group bys), there's no need to generate the
     // extra aggregate and join.
     RelNode rel;
@@ -207,7 +206,7 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
     return aggregate.copy(
         aggregate.getTraitSet(),
         distinct,
-        BitSets.range(aggregate.getGroupSet().cardinality()),
+        ImmutableBitSet.range(aggregate.getGroupSet().cardinality()),
         newAggCalls);
   }
 
@@ -346,7 +345,7 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
         aggregate.copy(
             aggregate.getTraitSet(),
             distinct,
-            BitSets.range(aggregate.getGroupSet().cardinality()),
+            ImmutableBitSet.range(aggregate.getGroupSet().cardinality()),
             aggCallList);
 
     // If there's no left child yet, no need to create the join
@@ -464,7 +463,7 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
     final RelNode child = aggregate.getInput();
     final List<RelDataTypeField> childFields =
         child.getRowType().getFieldList();
-    for (int i : BitSets.toIter(aggregate.getGroupSet())) {
+    for (int i : aggregate.getGroupSet()) {
       sourceOf.put(i, projects.size());
       projects.add(RexInputRef.of2(i, childFields));
     }
@@ -483,7 +482,7 @@ public final class AggregateExpandDistinctAggregatesRule extends RelOptRule {
     return aggregate.copy(
         aggregate.getTraitSet(),
         project,
-        BitSets.range(projects.size()),
+        ImmutableBitSet.range(projects.size()),
         ImmutableList.<AggregateCall>of());
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9d8de38/core/src/main/java/org/apache/calcite/rel/rules/AggregateFilterTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateFilterTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateFilterTransposeRule.java
index 4b909cc..665191d 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateFilterTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateFilterTransposeRule.java
@@ -28,14 +28,13 @@ import org.apache.calcite.rel.metadata.RelMetadataQuery;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.sql.SqlAggFunction;
-import org.apache.calcite.util.BitSets;
+import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.mapping.Mappings;
 
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 
-import java.util.BitSet;
 import java.util.List;
 
 /**
@@ -68,10 +67,10 @@ public class AggregateFilterTransposeRule extends RelOptRule {
     final Filter filter = call.rel(1);
 
     // Do the columns used by the filter appear in the output of the aggregate?
-    final BitSet filterColumns =
+    final ImmutableBitSet filterColumns =
         RelOptUtil.InputFinder.bits(filter.getCondition());
-    final BitSet newGroupSet =
-        BitSets.union(aggregate.getGroupSet(), filterColumns);
+    final ImmutableBitSet newGroupSet =
+        aggregate.getGroupSet().union(filterColumns);
     final RelNode input = filter.getInput();
     final Boolean unique =
         RelMetadataQuery.areColumnsUnique(input, newGroupSet);
@@ -87,7 +86,7 @@ public class AggregateFilterTransposeRule extends RelOptRule {
     final Mappings.TargetMapping mapping = Mappings.target(
         new Function<Integer, Integer>() {
           public Integer apply(Integer a0) {
-            return BitSets.toList(newGroupSet).indexOf(a0);
+            return newGroupSet.indexOf(a0);
           }
         },
         input.getRowType().getFieldCount(),
@@ -96,16 +95,16 @@ public class AggregateFilterTransposeRule extends RelOptRule {
         RexUtil.apply(mapping, filter.getCondition());
     final Filter newFilter = filter.copy(filter.getTraitSet(),
         newAggregate, newCondition);
-    if (BitSets.contains(aggregate.getGroupSet(), filterColumns)) {
+    if (aggregate.getGroupSet().contains(filterColumns)) {
       // Everything needed by the filter is returned by the aggregate.
       assert newGroupSet.equals(aggregate.getGroupSet());
       call.transformTo(newFilter);
     } else {
       // The filter needs at least one extra column.
       // Now aggregate it away.
-      final BitSet topGroupSet = new BitSet();
-      for (int c : BitSets.toIter(aggregate.getGroupSet())) {
-        topGroupSet.set(BitSets.toList(newGroupSet).indexOf(c));
+      final ImmutableBitSet.Builder topGroupSet = ImmutableBitSet.builder();
+      for (int c : aggregate.getGroupSet()) {
+        topGroupSet.set(newGroupSet.indexOf(c));
       }
       final List<AggregateCall> topAggCallList = Lists.newArrayList();
       int i = newGroupSet.cardinality();
@@ -125,8 +124,8 @@ public class AggregateFilterTransposeRule extends RelOptRule {
                 ImmutableList.of(i++), aggregateCall.type, aggregateCall.name));
       }
       final Aggregate topAggregate =
-          aggregate.copy(aggregate.getTraitSet(), newFilter, topGroupSet,
-              topAggCallList);
+          aggregate.copy(aggregate.getTraitSet(), newFilter,
+              topGroupSet.build(), topAggCallList);
       call.transformTo(topAggregate);
     }
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9d8de38/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectMergeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectMergeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectMergeRule.java
index 8b1dafc..e321d83 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectMergeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectMergeRule.java
@@ -26,12 +26,11 @@ import org.apache.calcite.rel.core.Project;
 import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.util.BitSets;
+import org.apache.calcite.util.ImmutableBitSet;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 
-import java.util.BitSet;
 import java.util.List;
 
 /**
@@ -68,7 +67,7 @@ public class AggregateProjectMergeRule extends RelOptRule {
   public static RelNode apply(Aggregate aggregate,
       Project project) {
     final List<Integer> newKeys = Lists.newArrayList();
-    for (int key : BitSets.toIter(aggregate.getGroupSet())) {
+    for (int key : aggregate.getGroupSet()) {
       final RexNode rex = project.getProjects().get(key);
       if (rex instanceof RexInputRef) {
         newKeys.add(((RexInputRef) rex).getIndex());
@@ -94,7 +93,7 @@ public class AggregateProjectMergeRule extends RelOptRule {
       aggCalls.add(aggregateCall.copy(newArgs.build()));
     }
 
-    final BitSet newGroupSet = BitSets.of(newKeys);
+    final ImmutableBitSet newGroupSet = ImmutableBitSet.of(newKeys);
     final Aggregate newAggregate =
         aggregate.copy(aggregate.getTraitSet(), project.getInput(), newGroupSet,
             aggCalls.build());
@@ -102,10 +101,10 @@ public class AggregateProjectMergeRule extends RelOptRule {
     // Add a project if the group set is not in the same order or
     // contains duplicates.
     RelNode rel = newAggregate;
-    if (!BitSets.toList(newGroupSet).equals(newKeys)) {
+    if (!newGroupSet.toList().equals(newKeys)) {
       final List<Integer> posList = Lists.newArrayList();
       for (int newKey : newKeys) {
-        posList.add(BitSets.toList(newGroupSet).indexOf(newKey));
+        posList.add(newGroupSet.indexOf(newKey));
       }
       for (int i = newAggregate.getGroupSet().cardinality();
            i < newAggregate.getRowType().getFieldCount(); i++) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9d8de38/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java
index cb99e86..d696407 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateProjectPullUpConstantsRule.java
@@ -29,7 +29,7 @@ import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexLocalRef;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexProgram;
-import org.apache.calcite.util.BitSets;
+import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.IntList;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Permutation;
@@ -98,7 +98,7 @@ public class AggregateProjectPullUpConstantsRule extends RelOptRule {
     final RelDataType childRowType = child.getRowType();
     IntList constantList = new IntList();
     Map<Integer, RexNode> constants = new HashMap<Integer, RexNode>();
-    for (int i : BitSets.toIter(aggregate.getGroupSet())) {
+    for (int i : aggregate.getGroupSet()) {
       final RexLocalRef ref = program.getProjectList().get(i);
       if (program.isConstant(ref)) {
         constantList.add(i);
@@ -140,7 +140,7 @@ public class AggregateProjectPullUpConstantsRule extends RelOptRule {
           new LogicalAggregate(
               aggregate.getCluster(),
               child,
-              BitSets.range(newGroupCount),
+              ImmutableBitSet.range(newGroupCount),
               newAggCalls);
     } else {
       // Create the mapping from old field positions to new field
@@ -185,7 +185,7 @@ public class AggregateProjectPullUpConstantsRule extends RelOptRule {
           new LogicalAggregate(
               aggregate.getCluster(),
               project,
-              BitSets.range(newGroupCount),
+              ImmutableBitSet.range(newGroupCount),
               newAggCalls);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9d8de38/core/src/main/java/org/apache/calcite/rel/rules/AggregateStarTableRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateStarTableRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateStarTableRule.java
index d511f79..019a01f 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateStarTableRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateStarTableRule.java
@@ -37,14 +37,13 @@ import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.schema.Table;
 import org.apache.calcite.schema.impl.StarTable;
 import org.apache.calcite.sql.SqlAggFunction;
-import org.apache.calcite.util.BitSets;
+import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.mapping.AbstractSourceMapping;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 
-import java.util.BitSet;
 import java.util.List;
 
 /**
@@ -136,11 +135,11 @@ public class AggregateStarTableRule extends RelOptRule {
             + ", rolling up " + tileKey.dimensions + " to "
             + aggregate.getGroupSet());
       }
-      assert BitSets.contains(tileKey.dimensions, aggregate.getGroupSet());
+      assert tileKey.dimensions.contains(aggregate.getGroupSet());
       final List<AggregateCall> aggCalls = Lists.newArrayList();
-      BitSet groupSet = new BitSet();
-      for (int key : BitSets.toIter(aggregate.getGroupSet())) {
-        groupSet.set(BitSets.toList(tileKey.dimensions).indexOf(key));
+      ImmutableBitSet.Builder groupSet = ImmutableBitSet.builder();
+      for (int key : aggregate.getGroupSet()) {
+        groupSet.set(tileKey.dimensions.indexOf(key));
       }
       for (AggregateCall aggCall : aggregate.getAggCallList()) {
         final AggregateCall copy =
@@ -150,7 +149,8 @@ public class AggregateStarTableRule extends RelOptRule {
         }
         aggCalls.add(copy);
       }
-      rel = aggregate.copy(aggregate.getTraitSet(), rel, groupSet, aggCalls);
+      rel = aggregate.copy(aggregate.getTraitSet(), rel, groupSet.build(),
+          aggCalls);
     } else if (!tileKey.measures.equals(measures)) {
       System.out.println("Using materialization "
           + aggregateRelOptTable.getQualifiedName()
@@ -162,8 +162,8 @@ public class AggregateStarTableRule extends RelOptRule {
               aggregate.getRowType().getFieldCount()) {
             public int getSourceOpt(int source) {
               if (source < aggregate.getGroupCount()) {
-                int in = BitSets.toList(tileKey.dimensions).get(source);
-                return BitSets.toList(aggregate.getGroupSet()).indexOf(in);
+                int in = tileKey.dimensions.nth(source);
+                return aggregate.getGroupSet().indexOf(in);
               }
               Lattice.Measure measure =
                   measures.get(source - aggregate.getGroupCount());
@@ -184,8 +184,7 @@ public class AggregateStarTableRule extends RelOptRule {
     if (aggregateCall.isDistinct()) {
       return null;
     }
-    final SqlAggFunction aggregation =
-        (SqlAggFunction) aggregateCall.getAggregation();
+    final SqlAggFunction aggregation = aggregateCall.getAggregation();
     final Pair<SqlAggFunction, List<Integer>> seek =
         Pair.of(aggregation, aggregateCall.getArgList());
     final int offset = tileKey.dimensions.cardinality();
@@ -209,13 +208,13 @@ public class AggregateStarTableRule extends RelOptRule {
     {
       List<Integer> newArgs = Lists.newArrayList();
       for (Integer arg : aggregateCall.getArgList()) {
-        int z = BitSets.toList(tileKey.dimensions).indexOf(arg);
+        int z = tileKey.dimensions.indexOf(arg);
         if (z < 0) {
           break tryGroup;
         }
         newArgs.add(z);
       }
-      return AggregateCall.create((SqlAggFunction) aggregation, false, newArgs,
+      return AggregateCall.create(aggregation, false, newArgs,
           groupCount, input, null, aggregateCall.name);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9d8de38/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java b/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
index c3a7e25..8af01e3 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/FilterAggregateTransposeRule.java
@@ -26,12 +26,11 @@ import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.util.BitSets;
+import org.apache.calcite.util.ImmutableBitSet;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 
-import java.util.BitSet;
 import java.util.List;
 
 /**
@@ -80,7 +79,7 @@ public class FilterAggregateTransposeRule extends RelOptRule {
 
     final List<RexNode> conditions =
         RelOptUtil.conjunctions(filterRel.getCondition());
-    final BitSet groupKeys = aggRel.getGroupSet();
+    final ImmutableBitSet groupKeys = aggRel.getGroupSet();
     final RexBuilder rexBuilder = filterRel.getCluster().getRexBuilder();
     final List<RelDataTypeField> origFields =
         aggRel.getRowType().getFieldList();
@@ -89,8 +88,8 @@ public class FilterAggregateTransposeRule extends RelOptRule {
     final List<RexNode> remainingConditions = Lists.newArrayList();
 
     for (RexNode condition : conditions) {
-      BitSet rCols = RelOptUtil.InputFinder.bits(condition);
-      if (BitSets.contains(groupKeys, rCols)) {
+      ImmutableBitSet rCols = RelOptUtil.InputFinder.bits(condition);
+      if (groupKeys.contains(rCols)) {
         pushedConditions.add(
             condition.accept(
                 new RelOptUtil.RexInputConverter(rexBuilder, origFields,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9d8de38/core/src/main/java/org/apache/calcite/rel/rules/JoinAssociateRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinAssociateRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinAssociateRule.java
index 6a38a9a..455176f 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/JoinAssociateRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinAssociateRule.java
@@ -27,12 +27,11 @@ import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexPermuteInputsShuttle;
 import org.apache.calcite.rex.RexUtil;
-import org.apache.calcite.util.BitSets;
+import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.mapping.Mappings;
 
 import com.google.common.collect.Lists;
 
-import java.util.BitSet;
 import java.util.List;
 
 /**
@@ -90,8 +89,9 @@ public class JoinAssociateRule extends RelOptRule {
     final int aCount = relA.getRowType().getFieldCount();
     final int bCount = relB.getRowType().getFieldCount();
     final int cCount = relC.getRowType().getFieldCount();
-    final BitSet aBitSet = BitSets.range(0, aCount);
-    final BitSet bBitSet = BitSets.range(aCount, aCount + bCount);
+    final ImmutableBitSet aBitSet = ImmutableBitSet.range(0, aCount);
+    final ImmutableBitSet bBitSet =
+        ImmutableBitSet.range(aCount, aCount + bCount);
 
     if (!topJoin.getSystemFieldList().isEmpty()) {
       // FIXME Enable this rule for joins with system fields

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9d8de38/core/src/main/java/org/apache/calcite/rel/rules/JoinPushThroughJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinPushThroughJoinRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinPushThroughJoinRule.java
index 8e024aa..6a292f6 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/JoinPushThroughJoinRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinPushThroughJoinRule.java
@@ -30,11 +30,10 @@ import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexPermuteInputsShuttle;
 import org.apache.calcite.rex.RexUtil;
-import org.apache.calcite.util.BitSets;
+import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.mapping.Mappings;
 
 import java.util.ArrayList;
-import java.util.BitSet;
 import java.util.List;
 
 /**
@@ -118,7 +117,8 @@ public class JoinPushThroughJoinRule extends RelOptRule {
     final int aCount = relA.getRowType().getFieldCount();
     final int bCount = relB.getRowType().getFieldCount();
     final int cCount = relC.getRowType().getFieldCount();
-    final BitSet bBitSet = BitSets.range(aCount, aCount + bCount);
+    final ImmutableBitSet bBitSet =
+        ImmutableBitSet.range(aCount, aCount + bCount);
 
     // becomes
     //
@@ -225,7 +225,7 @@ public class JoinPushThroughJoinRule extends RelOptRule {
     final int aCount = relA.getRowType().getFieldCount();
     final int bCount = relB.getRowType().getFieldCount();
     final int cCount = relC.getRowType().getFieldCount();
-    final BitSet aBitSet = BitSets.range(aCount);
+    final ImmutableBitSet aBitSet = ImmutableBitSet.range(aCount);
 
     // becomes
     //
@@ -317,11 +317,11 @@ public class JoinPushThroughJoinRule extends RelOptRule {
    */
   static void split(
       RexNode condition,
-      BitSet bitSet,
+      ImmutableBitSet bitSet,
       List<RexNode> intersecting,
       List<RexNode> nonIntersecting) {
     for (RexNode node : RelOptUtil.conjunctions(condition)) {
-      BitSet inputBitSet = RelOptUtil.InputFinder.bits(node);
+      ImmutableBitSet inputBitSet = RelOptUtil.InputFinder.bits(node);
       if (bitSet.intersects(inputBitSet)) {
         intersecting.add(node);
       } else {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9d8de38/core/src/main/java/org/apache/calcite/rel/rules/JoinToMultiJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/JoinToMultiJoinRule.java b/core/src/main/java/org/apache/calcite/rel/rules/JoinToMultiJoinRule.java
index 082575a..fe7fa8c 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/JoinToMultiJoinRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/JoinToMultiJoinRule.java
@@ -29,6 +29,7 @@ import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.rex.RexVisitorImpl;
+import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.ImmutableIntList;
 import org.apache.calcite.util.Pair;
 
@@ -36,7 +37,6 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 
-import java.util.BitSet;
 import java.util.List;
 import java.util.Map;
 
@@ -125,7 +125,7 @@ public class JoinToMultiJoinRule extends RelOptRule {
 
     // combine the children MultiJoin inputs into an array of inputs
     // for the new MultiJoin
-    final List<BitSet> projFieldsList = Lists.newArrayList();
+    final List<ImmutableBitSet> projFieldsList = Lists.newArrayList();
     final List<int[]> joinFieldRefCountsList = Lists.newArrayList();
     final List<RelNode> newInputs =
         combineInputs(
@@ -195,7 +195,7 @@ public class JoinToMultiJoinRule extends RelOptRule {
       Join join,
       RelNode left,
       RelNode right,
-      List<BitSet> projFieldsList,
+      List<ImmutableBitSet> projFieldsList,
       List<int[]> joinFieldRefCountsList) {
     final List<RelNode> newInputs = Lists.newArrayList();
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9d8de38/core/src/main/java/org/apache/calcite/rel/rules/LoptMultiJoin.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/LoptMultiJoin.java b/core/src/main/java/org/apache/calcite/rel/rules/LoptMultiJoin.java
index 071dbc1..e75cc7c 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/LoptMultiJoin.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/LoptMultiJoin.java
@@ -29,10 +29,12 @@ import org.apache.calcite.rex.RexCall;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.util.BitSets;
+import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.IntList;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
 
 import java.util.ArrayList;
 import java.util.BitSet;
@@ -94,14 +96,14 @@ public class LoptMultiJoin {
    * bitmap contains the non-null generating factors that the null generating
    * factor is dependent upon
    */
-  private final BitSet [] outerJoinFactors;
+  private final ImmutableBitSet [] outerJoinFactors;
 
   /**
    * Bitmap corresponding to the fields projected from each join factor, after
    * row scan processing has completed. This excludes fields referenced in
    * join conditions, unless the field appears in the final projection list.
    */
-  private List<BitSet> projFields;
+  private List<ImmutableBitSet> projFields;
 
   /**
    * Map containing reference counts of the fields referenced in join
@@ -116,13 +118,13 @@ public class LoptMultiJoin {
    * For each join filter, associates a bitmap indicating all factors
    * referenced by the filter
    */
-  private Map<RexNode, BitSet> factorsRefByJoinFilter;
+  private Map<RexNode, ImmutableBitSet> factorsRefByJoinFilter;
 
   /**
    * For each join filter, associates a bitmap indicating all fields
    * referenced by the filter
    */
-  private Map<RexNode, BitSet> fieldsRefByJoinFilter;
+  private Map<RexNode, ImmutableBitSet> fieldsRefByJoinFilter;
 
   /**
    * Starting RexInputRef index corresponding to each join factor
@@ -138,7 +140,7 @@ public class LoptMultiJoin {
    * Bitmap indicating which factors each factor references in join filters
    * that correspond to comparisons
    */
-  BitSet [] factorsRefByFactor;
+  ImmutableBitSet [] factorsRefByFactor;
 
   /**
    * Weights of each factor combination
@@ -212,15 +214,15 @@ public class LoptMultiJoin {
     // upon.
     joinTypes = ImmutableList.copyOf(multiJoin.getJoinTypes());
     List<RexNode> outerJoinConds = this.multiJoin.getOuterJoinConditions();
-    outerJoinFactors = new BitSet[nJoinFactors];
+    outerJoinFactors = new ImmutableBitSet[nJoinFactors];
     for (int i = 0; i < nJoinFactors; i++) {
       if (outerJoinConds.get(i) != null) {
         // set a bitmap containing the factors referenced in the
         // ON condition of the outer join; mask off the factor
         // corresponding to the factor itself
-        BitSet dependentFactors =
+        ImmutableBitSet dependentFactors =
             getJoinFilterFactorBitmap(outerJoinConds.get(i), false);
-        dependentFactors.clear(i);
+        dependentFactors = dependentFactors.clear(i);
         outerJoinFactors[i] = dependentFactors;
       }
     }
@@ -291,7 +293,7 @@ public class LoptMultiJoin {
    * @return bitmap corresponding to the factors referenced within the
    * specified join filter
    */
-  public BitSet getFactorsRefByJoinFilter(RexNode joinFilter) {
+  public ImmutableBitSet getFactorsRefByJoinFilter(RexNode joinFilter) {
     return factorsRefByJoinFilter.get(joinFilter);
   }
 
@@ -307,7 +309,7 @@ public class LoptMultiJoin {
    *
    * @return bitmap corresponding to the fields referenced by a join filter
    */
-  public BitSet getFieldsRefByJoinFilter(RexNode joinFilter) {
+  public ImmutableBitSet getFieldsRefByJoinFilter(RexNode joinFilter) {
     return fieldsRefByJoinFilter.get(joinFilter);
   }
 
@@ -324,7 +326,7 @@ public class LoptMultiJoin {
    * @return bitmap corresponding to the factors referenced by the specified
    * factor in the various join filters that correspond to comparisons
    */
-  public BitSet getFactorsRefByFactor(int factIdx) {
+  public ImmutableBitSet getFactorsRefByFactor(int factIdx) {
     return factorsRefByFactor[factIdx];
   }
 
@@ -354,7 +356,7 @@ public class LoptMultiJoin {
    * dependent upon, if the factor is null generating in a left or right outer
    * join; otherwise null is returned
    */
-  public BitSet getOuterJoinFactors(int factIdx) {
+  public ImmutableBitSet getOuterJoinFactors(int factIdx) {
     return outerJoinFactors[factIdx];
   }
 
@@ -373,7 +375,7 @@ public class LoptMultiJoin {
    *
    * @return bitmap containing the fields that are projected from a factor
    */
-  public BitSet getProjFields(int factIdx) {
+  public ImmutableBitSet getProjFields(int factIdx) {
     return projFields.get(factIdx);
   }
 
@@ -438,10 +440,10 @@ public class LoptMultiJoin {
    *
    * @return the bitmap containing the factor references
    */
-  BitSet getJoinFilterFactorBitmap(
+  ImmutableBitSet getJoinFilterFactorBitmap(
       RexNode joinFilter,
       boolean setFields) {
-    BitSet fieldRefBitmap = fieldBitmap(joinFilter);
+    ImmutableBitSet fieldRefBitmap = fieldBitmap(joinFilter);
     if (setFields) {
       fieldsRefByJoinFilter.put(joinFilter, fieldRefBitmap);
     }
@@ -449,10 +451,10 @@ public class LoptMultiJoin {
     return factorBitmap(fieldRefBitmap);
   }
 
-  private BitSet fieldBitmap(RexNode joinFilter) {
-    BitSet fieldRefBitmap = new BitSet(nTotalFields);
-    joinFilter.accept(new RelOptUtil.InputFinder(fieldRefBitmap));
-    return fieldRefBitmap;
+  private ImmutableBitSet fieldBitmap(RexNode joinFilter) {
+    final RelOptUtil.InputFinder inputFinder = new RelOptUtil.InputFinder();
+    joinFilter.accept(inputFinder);
+    return inputFinder.inputBitSet.build();
   }
 
   /**
@@ -460,8 +462,8 @@ public class LoptMultiJoin {
    * references
    */
   private void setJoinFilterRefs() {
-    fieldsRefByJoinFilter = new HashMap<RexNode, BitSet>();
-    factorsRefByJoinFilter = new HashMap<RexNode, BitSet>();
+    fieldsRefByJoinFilter = Maps.newHashMap();
+    factorsRefByJoinFilter = Maps.newHashMap();
     ListIterator<RexNode> filterIter = allJoinFilters.listIterator();
     while (filterIter.hasNext()) {
       RexNode joinFilter = filterIter.next();
@@ -471,7 +473,7 @@ public class LoptMultiJoin {
       if (joinFilter.isAlwaysTrue()) {
         filterIter.remove();
       }
-      BitSet factorRefBitmap =
+      ImmutableBitSet factorRefBitmap =
           getJoinFilterFactorBitmap(joinFilter, true);
       factorsRefByJoinFilter.put(joinFilter, factorRefBitmap);
     }
@@ -485,13 +487,13 @@ public class LoptMultiJoin {
    * @return bitmap representing factors referenced that will
    * be set by this method
    */
-  private BitSet factorBitmap(BitSet fieldRefBitmap) {
-    BitSet factorRefBitmap = new BitSet(nJoinFactors);
-    for (int field : BitSets.toIter(fieldRefBitmap)) {
+  private ImmutableBitSet factorBitmap(ImmutableBitSet fieldRefBitmap) {
+    ImmutableBitSet.Builder factorRefBitmap = ImmutableBitSet.builder();
+    for (int field : fieldRefBitmap) {
       int factor = findRef(field);
       factorRefBitmap.set(factor);
     }
-    return factorRefBitmap;
+    return factorRefBitmap.build();
   }
 
   /**
@@ -519,13 +521,13 @@ public class LoptMultiJoin {
    */
   public void setFactorWeights() {
     factorWeights = new int[nJoinFactors][nJoinFactors];
-    factorsRefByFactor = new BitSet[nJoinFactors];
+    factorsRefByFactor = new ImmutableBitSet[nJoinFactors];
     for (int i = 0; i < nJoinFactors; i++) {
-      factorsRefByFactor[i] = new BitSet(nJoinFactors);
+      factorsRefByFactor[i] = ImmutableBitSet.of();
     }
 
     for (RexNode joinFilter : allJoinFilters) {
-      BitSet factorRefs = factorsRefByJoinFilter.get(joinFilter);
+      ImmutableBitSet factorRefs = factorsRefByJoinFilter.get(joinFilter);
 
       // don't give weights to non-comparison expressions
       if (!(joinFilter instanceof RexCall)) {
@@ -538,9 +540,12 @@ public class LoptMultiJoin {
       // OR the factors referenced in this join filter into the
       // bitmaps corresponding to each of the factors; however,
       // exclude the bit corresponding to the factor itself
-      for (int factor : BitSets.toIter(factorRefs)) {
-        factorsRefByFactor[factor].or(factorRefs);
-        factorsRefByFactor[factor].clear(factor);
+      for (int factor : factorRefs) {
+        factorsRefByFactor[factor] =
+            ImmutableBitSet.builder(factorsRefByFactor[factor])
+                .addAll(factorRefs)
+                .clear(factor)
+                .build();
       }
 
       if (factorRefs.cardinality() == 2) {
@@ -548,8 +553,8 @@ public class LoptMultiJoin {
         int rightFactor = factorRefs.nextSetBit(leftFactor + 1);
 
         final RexCall call = (RexCall) joinFilter;
-        BitSet leftFields = fieldBitmap(call.getOperands().get(0));
-        BitSet leftBitmap = factorBitmap(leftFields);
+        ImmutableBitSet leftFields = fieldBitmap(call.getOperands().get(0));
+        ImmutableBitSet leftBitmap = factorBitmap(leftFields);
 
         // filter contains only two factor references, one on each
         // side of the operator
@@ -571,7 +576,7 @@ public class LoptMultiJoin {
       } else {
         // multiple factor references -- set a weight for each
         // combination of factors referenced within the filter
-        final IntList list = BitSets.toList(factorRefs);
+        final IntList list = factorRefs.toList();
         for (int outer : list) {
           for (int inner : list) {
             if (outer != inner) {
@@ -618,7 +623,8 @@ public class LoptMultiJoin {
    * @param joinTree join tree to be examined
    * @param childFactors bitmap to be set
    */
-  public void getChildFactors(LoptJoinTree joinTree, BitSet childFactors) {
+  public void getChildFactors(LoptJoinTree joinTree,
+      ImmutableBitSet.Builder childFactors) {
     for (int child : joinTree.getTreeOrder()) {
       childFactors.set(child);
     }
@@ -791,18 +797,18 @@ public class LoptMultiJoin {
   }
 
   public Edge createEdge(RexNode condition) {
-    BitSet fieldRefBitmap = fieldBitmap(condition);
-    BitSet factorRefBitmap = factorBitmap(fieldRefBitmap);
+    ImmutableBitSet fieldRefBitmap = fieldBitmap(condition);
+    ImmutableBitSet factorRefBitmap = factorBitmap(fieldRefBitmap);
     return new Edge(condition, factorRefBitmap, fieldRefBitmap);
   }
 
   /** Information about a join-condition. */
   static class Edge {
-    final BitSet factors;
-    final BitSet columns;
+    final ImmutableBitSet factors;
+    final ImmutableBitSet columns;
     final RexNode condition;
 
-    Edge(RexNode condition, BitSet factors, BitSet columns) {
+    Edge(RexNode condition, ImmutableBitSet factors, ImmutableBitSet columns) {
       this.condition = condition;
       this.factors = factors;
       this.columns = columns;

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9d8de38/core/src/main/java/org/apache/calcite/rel/rules/LoptOptimizeJoinRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/LoptOptimizeJoinRule.java b/core/src/main/java/org/apache/calcite/rel/rules/LoptOptimizeJoinRule.java
index 2f5643b..7a365f3 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/LoptOptimizeJoinRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/LoptOptimizeJoinRule.java
@@ -41,6 +41,7 @@ import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.util.BitSets;
+import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.ImmutableIntList;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.mapping.IntPair;
@@ -150,7 +151,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
     outerForLoop:
       for (int factIdx : removalCandidates) {
         // reject the factor if it is referenced in the projection list
-        BitSet projFields = multiJoin.getProjFields(factIdx);
+        ImmutableBitSet projFields = multiJoin.getProjFields(factIdx);
         if ((projFields == null) || (projFields.cardinality() > 0)) {
           continue;
         }
@@ -163,9 +164,10 @@ public class LoptOptimizeJoinRule extends RelOptRule {
         List<RexNode> ojFilters = new ArrayList<RexNode>();
         RelOptUtil.decomposeConjunction(outerJoinCond, ojFilters);
         int numFields = multiJoin.getNumFieldsInJoinFactor(factIdx);
-        BitSet joinKeys = new BitSet(numFields);
-        BitSet otherJoinKeys =
-            new BitSet(multiJoin.getNumTotalFields());
+        final ImmutableBitSet.Builder joinKeyBuilder =
+            ImmutableBitSet.builder();
+        final ImmutableBitSet.Builder otherJoinKeyBuilder =
+            ImmutableBitSet.builder();
         int firstFieldNum = multiJoin.getJoinStart(factIdx);
         int lastFieldNum = firstFieldNum + numFields;
         for (RexNode filter : ojFilters) {
@@ -185,8 +187,8 @@ public class LoptOptimizeJoinRule extends RelOptRule {
           int rightRef =
               ((RexInputRef) filterCall.getOperands().get(1)).getIndex();
           setJoinKey(
-              joinKeys,
-              otherJoinKeys,
+              joinKeyBuilder,
+              otherJoinKeyBuilder,
               leftRef,
               rightRef,
               firstFieldNum,
@@ -194,12 +196,13 @@ public class LoptOptimizeJoinRule extends RelOptRule {
               true);
         }
 
-        if (joinKeys.cardinality() == 0) {
+        if (joinKeyBuilder.cardinality() == 0) {
           continue;
         }
 
         // make sure the only join fields referenced are the ones in
         // the current outer join
+        final ImmutableBitSet joinKeys = joinKeyBuilder.build();
         int [] joinFieldRefCounts =
             multiJoin.getJoinFieldRefCounts(factIdx);
         for (int i = 0; i < joinFieldRefCounts.length; i++) {
@@ -223,7 +226,8 @@ public class LoptOptimizeJoinRule extends RelOptRule {
           // the join keys from the other factors that join with
           // this one.  Later, in the outermost loop, we'll have
           // the opportunity to retry removing those factors.
-          for (int otherKey : BitSets.toIter(otherJoinKeys)) {
+          final ImmutableBitSet otherJoinKeys = otherJoinKeyBuilder.build();
+          for (int otherKey : otherJoinKeys) {
             int otherFactor = multiJoin.findRef(otherKey);
             if (multiJoin.isNullGenerating(otherFactor)) {
               retryCandidates.add(otherFactor);
@@ -256,8 +260,8 @@ public class LoptOptimizeJoinRule extends RelOptRule {
    * one
    */
   private void setJoinKey(
-      BitSet joinKeys,
-      BitSet otherJoinKeys,
+      ImmutableBitSet.Builder joinKeys,
+      ImmutableBitSet.Builder otherJoinKeys,
       int ref1,
       int ref2,
       int firstFieldNum,
@@ -325,7 +329,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
       int factor2 = selfJoinPairs.get(factor1);
       List<RexNode> selfJoinFilters = new ArrayList<RexNode>();
       for (RexNode filter : multiJoin.getJoinFilters()) {
-        BitSet joinFactors =
+        ImmutableBitSet joinFactors =
             multiJoin.getFactorsRefByJoinFilter(filter);
         if ((joinFactors.cardinality() == 2)
             && joinFactors.get(factor1)
@@ -571,12 +575,15 @@ public class LoptOptimizeJoinRule extends RelOptRule {
       LoptJoinTree joinTree,
       List<RexNode> filters,
       int factor) {
-    BitSet childFactors = BitSets.of(joinTree.getTreeOrder());
-    childFactors.set(factor);
+    final ImmutableBitSet childFactors =
+        ImmutableBitSet.builder()
+            .addAll(joinTree.getTreeOrder())
+            .set(factor)
+            .build();
 
     int factorStart = multiJoin.getJoinStart(factor);
     int nFields = multiJoin.getNumFieldsInJoinFactor(factor);
-    BitSet joinKeys = new BitSet(nFields);
+    final ImmutableBitSet.Builder joinKeys = ImmutableBitSet.builder();
 
     // first loop through the inner join filters, picking out the ones
     // that reference only the factors in either the join tree or the
@@ -607,7 +614,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
     } else {
       return RelMetadataQuery.getDistinctRowCount(
           semiJoinOpt.getChosenSemiJoin(factor),
-          joinKeys,
+          joinKeys.build(),
           null);
     }
   }
@@ -630,12 +637,12 @@ public class LoptOptimizeJoinRule extends RelOptRule {
   private void setFactorJoinKeys(
       LoptMultiJoin multiJoin,
       List<RexNode> filters,
-      BitSet joinFactors,
+      ImmutableBitSet joinFactors,
       int factorStart,
       int nFields,
-      BitSet joinKeys) {
+      ImmutableBitSet.Builder joinKeys) {
     for (RexNode joinFilter : filters) {
-      BitSet filterFactors =
+      ImmutableBitSet filterFactors =
           multiJoin.getFactorsRefByJoinFilter(joinFilter);
 
       // if all factors in the join filter are in the bitmap containing
@@ -643,8 +650,8 @@ public class LoptOptimizeJoinRule extends RelOptRule {
       // fields corresponding to the specified factor to the join key
       // bitmap; in doing so, adjust the join keys so they start at
       // offset 0
-      if (BitSets.contains(joinFactors, filterFactors)) {
-        BitSet joinFields =
+      if (joinFactors.contains(filterFactors)) {
+        ImmutableBitSet joinFields =
             multiJoin.getFieldsRefByJoinFilter(joinFilter);
         for (int field = joinFields.nextSetBit(factorStart);
              (field >= 0)
@@ -711,9 +718,9 @@ public class LoptOptimizeJoinRule extends RelOptRule {
       // this factor joins with that have already been added to
       // the tree
       BitSet factorsNeeded =
-          (BitSet) multiJoin.getFactorsRefByFactor(nextFactor).clone();
+          multiJoin.getFactorsRefByFactor(nextFactor).toBitSet();
       if (multiJoin.isNullGenerating(nextFactor)) {
-        factorsNeeded.or(multiJoin.getOuterJoinFactors(nextFactor));
+        factorsNeeded.or(multiJoin.getOuterJoinFactors(nextFactor).toBitSet());
       }
       factorsNeeded.and(factorsAdded);
       joinTree =
@@ -1243,24 +1250,27 @@ public class LoptOptimizeJoinRule extends RelOptRule {
     // ones that reference only the factors in the new join tree
     final RexBuilder rexBuilder =
         multiJoin.getMultiJoinRel().getCluster().getRexBuilder();
-    final BitSet childFactors = BitSets.of(rightTree.getTreeOrder());
+    final ImmutableBitSet.Builder childFactorBuilder =
+        ImmutableBitSet.builder();
+    childFactorBuilder.addAll(rightTree.getTreeOrder());
     if (leftIdx >= 0) {
-      childFactors.set(leftIdx);
+      childFactorBuilder.set(leftIdx);
     } else {
-      BitSets.setAll(childFactors, leftTree.getTreeOrder());
+      childFactorBuilder.addAll(leftTree.getTreeOrder());
     }
-    multiJoin.getChildFactors(rightTree, childFactors);
+    multiJoin.getChildFactors(rightTree, childFactorBuilder);
 
+    final ImmutableBitSet childFactor = childFactorBuilder.build();
     RexNode condition = null;
     final ListIterator<RexNode> filterIter = filtersToAdd.listIterator();
     while (filterIter.hasNext()) {
       RexNode joinFilter = filterIter.next();
-      BitSet filterBitmap =
+      ImmutableBitSet filterBitmap =
           multiJoin.getFactorsRefByJoinFilter(joinFilter);
 
       // if all factors in the join filter are in the join tree,
       // AND the filter to the current join condition
-      if (BitSets.contains(childFactors, filterBitmap)) {
+      if (childFactor.contains(filterBitmap)) {
         if (condition == null) {
           condition = joinFilter;
         } else {
@@ -1837,14 +1847,6 @@ public class LoptOptimizeJoinRule extends RelOptRule {
    * if this is a removable self-join, swap so the factor that should be
    * preserved when the self-join is removed is put on the left.
    *
-   * <p>Note that unlike Broadbase, we do not swap if in the join condition,
-   * the RHS references more columns than the LHS. This can help for queries
-   * like (select * from A,B where A.A between B.X and B.Y). By putting B on
-   * the left, that would result in a sargable predicate with two endpoints.
-   * However, since {@link org.eigenbase.sarg.SargRexAnalyzer} currently
-   * doesn't handle these type of sargable predicates, there's no point in
-   * doing the swap for this reason.
-   *
    * @param multiJoin join factors being optimized
    * @param left left side of join tree
    * @param right right hand side of join tree

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b9d8de38/core/src/main/java/org/apache/calcite/rel/rules/LoptSemiJoinOptimizer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/LoptSemiJoinOptimizer.java b/core/src/main/java/org/apache/calcite/rel/rules/LoptSemiJoinOptimizer.java
index 2f95c20..402cd0f 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/LoptSemiJoinOptimizer.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/LoptSemiJoinOptimizer.java
@@ -33,14 +33,13 @@ import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
-import org.apache.calcite.util.BitSets;
+import org.apache.calcite.util.ImmutableBitSet;
 import org.apache.calcite.util.ImmutableIntList;
 
 import com.google.common.collect.Lists;
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.BitSet;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
@@ -209,7 +208,7 @@ public class LoptSemiJoinOptimizer {
     // a join filter and we've already verified that the operands are
     // RexInputRefs, verify that the factors belong to the fact and
     // dimension table
-    BitSet joinRefs = multiJoin.getFactorsRefByJoinFilter(joinFilter);
+    ImmutableBitSet joinRefs = multiJoin.getFactorsRefByJoinFilter(joinFilter);
     assert joinRefs.cardinality() == 2;
     int factor1 = joinRefs.nextSetBit(0);
     int factor2 = joinRefs.nextSetBit(factor1 + 1);
@@ -647,11 +646,8 @@ public class LoptSemiJoinOptimizer {
     // selectivity value is required because of the overhead of
     // index lookups on a very large fact table.  Half was chosen as
     // a middle ground based on testing that was done with a large
-    // dataset.
-    BitSet dimCols = new BitSet();
-    for (int dimCol : semiJoin.getRightKeys()) {
-      dimCols.set(dimCol);
-    }
+    // data set.
+    final ImmutableBitSet dimCols = ImmutableBitSet.of(semiJoin.getRightKeys());
     double selectivity =
         RelMdUtil.computeSemiJoinSelectivity(factRel, dimRel, semiJoin);
     if (selectivity > .5) {
@@ -724,10 +720,7 @@ public class LoptSemiJoinOptimizer {
 
     // Check if the semijoin keys corresponding to the dimension table
     // are unique.  The semijoin will filter out the nulls.
-    BitSet dimKeys = new BitSet();
-    for (Integer key : semiJoin.getRightKeys()) {
-      dimKeys.set(key);
-    }
+    final ImmutableBitSet dimKeys = ImmutableBitSet.of(semiJoin.getRightKeys());
     RelNode dimRel = multiJoin.getJoinFactor(dimIdx);
     if (!RelMdUtil.areColumnsDefinitelyUniqueWhenNullsFiltered(
         dimRel,
@@ -738,12 +731,12 @@ public class LoptSemiJoinOptimizer {
     // check that the only fields referenced from the dimension table
     // in either its projection or join conditions are the dimension
     // keys
-    BitSet dimProjRefs = multiJoin.getProjFields(dimIdx);
+    ImmutableBitSet dimProjRefs = multiJoin.getProjFields(dimIdx);
     if (dimProjRefs == null) {
       int nDimFields = multiJoin.getNumFieldsInJoinFactor(dimIdx);
-      dimProjRefs = BitSets.range(0, nDimFields);
+      dimProjRefs = ImmutableBitSet.range(0, nDimFields);
     }
-    if (!BitSets.contains(dimKeys, dimProjRefs)) {
+    if (!dimKeys.contains(dimProjRefs)) {
       return;
     }
     int [] dimJoinRefCounts = multiJoin.getJoinFieldRefCounts(dimIdx);