private LanguageNode handleAndFunction(FunctionCall fc) {
      // and functions take incomplete simple parts and turn them into complete parts, if so desired
      ArrayList<Part> incompletes = new ArrayList<Part>();
      ArrayList<ExpressionNode> ok = new ArrayList<ExpressionNode>();
      ArrayList<Part> subparts = new ArrayList<Part>();
      for (ExpressionNode en : fc.getParameters()) {
        Part p = state.get(en);
        if (p == null || p.isComplete()) {
          ok.add(en);
          if (p != null) subparts.add(p);
          continue;
        }
        incompletes.add(p);
      }
      if (incompletes.isEmpty()) return fc;

      // now we have the problem of a mishmash of incompletes.  some may be complex, some may be
      // simple
      // some may be collections.  we need to handle cases like the following:
      // (a = 1) and (b = 2) {a,b} (1 key)
      // (a = 1) and (b = 2 or b = 3) {a,b} (2 keys)
      // (a = 1 or a = 2) and (b = 3) {a,b} (2 keys)
      // (a = 1 or a = 2) and (b = 3 or b = 4) {a,b} (4 keys here)
      // all of the above, where the result is still not complete due to missing tenant column

      MultiMap<Part, ColumnKey> needed = new MultiMap<Part, ColumnKey>();
      MultiMap<ColumnKey, Part> classified = new MultiMap<ColumnKey, Part>();
      for (Part p : incompletes) {
        ListSet<ColumnKey> has = new ListSet<ColumnKey>();
        has.addAll(p.getColumns());
        needed.putAll(p, parent.getNeeded(has));
        for (ColumnKey ck : has) {
          classified.put(ck, p);
        }
      }
      // so let's say we have a part that is (a = 1 and b = 2), needs c and tenant, and we have a
      // part
      // that is c in (1,2,3).  The needed for (a = 1 and b = 2) is {c,tenant}.  we'll pull (c in
      // (1,2,3))
      // so we'll get at least (a = 1 and b = 2 and c = 3) or (a = 1 and b =2 and c = 3) ...
      // these we can then individually try to complete.

      while (!needed.isEmpty()) {
        combineParts(needed, classified, ok, subparts);
      }
      for (Part p : subparts) state.put(p.getParent(), p);
      if (ok.size() == 1) return ok.get(0);
      else {
        // what's left is a mix of unrelated and complete or incomplete subexprs.  unrelated nodes
        // would come in from above, as would previously complete.
        return new FunctionCall(FunctionName.makeAnd(), ok);
      }
    }
 @Override
 public boolean isComplete() {
   for (Part p : parts) if (!p.isComplete()) return false;
   return true;
 }