/**
   * Removes revisions present in the datastore from the input map.
   *
   * @param revisions an multimap from document id to set of revisions. The map is modified in place
   *     for performance consideration.
   */
  void revsDiffBatch(Multimap<String, String> revisions) {

    final String sql =
        String.format(
            "SELECT docs.docid, revs.revid FROM docs, revs "
                + "WHERE docs.doc_id = revs.doc_id AND docs.docid IN (%s) AND revs.revid IN (%s) "
                + "ORDER BY docs.docid",
            SQLDatabaseUtils.makePlaceholders(revisions.keySet().size()),
            SQLDatabaseUtils.makePlaceholders(revisions.size()));

    String[] args = new String[revisions.keySet().size() + revisions.size()];
    String[] keys = revisions.keySet().toArray(new String[revisions.keySet().size()]);
    String[] values = revisions.values().toArray(new String[revisions.size()]);
    System.arraycopy(keys, 0, args, 0, revisions.keySet().size());
    System.arraycopy(values, 0, args, revisions.keySet().size(), revisions.size());

    Cursor cursor = null;
    try {
      cursor = this.sqlDb.rawQuery(sql, args);
      while (cursor.moveToNext()) {
        String docId = cursor.getString(0);
        String revId = cursor.getString(1);
        revisions.remove(docId, revId);
      }
    } catch (SQLException e) {
      e.printStackTrace();
    } finally {
      DatabaseUtils.closeCursorQuietly(cursor);
    }
  }
  private DocumentRevisionTree getAllRevisionsOfDocument(long docNumericID) {
    String sql =
        "SELECT "
            + FULL_DOCUMENT_COLS
            + " FROM revs, docs "
            + "WHERE revs.doc_id=? AND revs.doc_id = docs.doc_id ORDER BY sequence ASC";

    String[] args = {Long.toString(docNumericID)};
    Cursor cursor = null;

    try {
      DocumentRevisionTree tree = new DocumentRevisionTree();
      cursor = this.sqlDb.rawQuery(sql, args);
      while (cursor.moveToNext()) {
        DocumentRevision rev = SQLDatabaseUtils.getFullRevisionFromCurrentCursor(cursor);
        Log.v(LOG_TAG, "Rev: " + rev);
        tree.add(rev);
      }
      return tree;
    } catch (SQLException e) {
      Log.e(LOG_TAG, "Error getting all revisions of document", e);
      return null;
    } finally {
      DatabaseUtils.closeCursorQuietly(cursor);
    }
  }
 @Override
 public List<DocumentRevision> getDocumentsWithIds(List<String> docIds) {
   Preconditions.checkState(this.isOpen(), "Database is closed");
   Preconditions.checkNotNull(docIds, "Input document id list can not be null");
   String sql =
       String.format(
           "SELECT "
               + FULL_DOCUMENT_COLS
               + " FROM revs, docs"
               + " WHERE docid IN ( %1$s ) AND current = 1 AND docs.doc_id = revs.doc_id "
               + " ORDER BY docs.doc_id ",
           SQLDatabaseUtils.makePlaceholders(docIds.size()));
   String[] args = docIds.toArray(new String[docIds.size()]);
   List<DocumentRevision> docs = getRevisionsFromRawQuery(sql, args);
   // Sort in memory since seems not able to sort them using SQL
   return sortDocumentsAccordingToIdList(docIds, docs);
 }
  /**
   * Get list of documents for given list of numeric ids. The result list is ordered by sequence
   * number, and only the current revisions are returned.
   *
   * @param docIds given list of internal ids
   * @return list of documents ordered by sequence number
   */
  List<DocumentRevision> getDocumentsWithInternalIds(List<Long> docIds) {
    Preconditions.checkNotNull(docIds, "Input document internal id list can not be null");
    if (docIds.size() == 0) {
      return Collections.emptyList();
    }

    final String GET_DOCUMENTS_BY_INTERNAL_IDS =
        "SELECT "
            + FULL_DOCUMENT_COLS
            + " FROM revs, docs "
            + "WHERE revs.doc_id IN ( %s ) AND current = 1 AND docs.doc_id = revs.doc_id";

    // Split into batches because SQLite has a limit on the number
    // of placeholders we can use in a single query. 999 is the default
    // value, but it can be lower. It's hard to find this out from Java,
    // so we use a value much lower.
    List<DocumentRevision> result = new ArrayList<DocumentRevision>(docIds.size());

    List<List<Long>> batches = Lists.partition(docIds, SQLITE_QUERY_PLACEHOLDERS_LIMIT);
    for (List<Long> batch : batches) {
      String sql =
          String.format(
              GET_DOCUMENTS_BY_INTERNAL_IDS, SQLDatabaseUtils.makePlaceholders(batch.size()));
      String[] args = new String[batch.size()];
      for (int i = 0; i < batch.size(); i++) {
        args[i] = Long.toString(batch.get(i));
      }
      result.addAll(getRevisionsFromRawQuery(sql, args));
    }

    // Contract is to sort by sequence number, which we need to do
    // outside the sqlDb as we're batching requests.
    Collections.sort(
        result,
        new Comparator<DocumentRevision>() {
          @Override
          public int compare(
              DocumentRevision documentRevision, DocumentRevision documentRevision2) {
            long a = documentRevision.getSequence();
            long b = documentRevision2.getSequence();
            return (int) (a - b);
          }
        });

    return result;
  }
 private List<DocumentRevision> getRevisionsFromRawQuery(String sql, String[] args) {
   List<DocumentRevision> result = new ArrayList<DocumentRevision>();
   Cursor cursor = null;
   try {
     cursor = this.sqlDb.rawQuery(sql, args);
     while (cursor.moveToNext()) {
       DocumentRevision row = SQLDatabaseUtils.getFullRevisionFromCurrentCursor(cursor);
       result.add(row);
     }
   } catch (SQLException e) {
     e
         .printStackTrace(); // To change bodyOne of catch statement use File | Settings | File
                             // Templates.
   } finally {
     DatabaseUtils.closeCursorQuietly(cursor);
   }
   return result;
 }
 @Override
 public BasicDocumentRevision getDocument(String id, String rev) {
   Preconditions.checkState(this.isOpen(), "Database is closed");
   Preconditions.checkArgument(
       !Strings.isNullOrEmpty(id), "DocumentRevisionTree id can not be empty");
   Cursor cursor = null;
   try {
     String[] args = (rev == null) ? new String[] {id} : new String[] {id, rev};
     String sql = (rev == null) ? GET_DOCUMENT_CURRENT_REVISION : GET_DOCUMENT_GIVEN_REVISION;
     cursor = this.sqlDb.rawQuery(sql, args);
     if (cursor.moveToFirst()) {
       return SQLDatabaseUtils.getFullRevisionFromCurrentCursor(cursor);
     } else {
       return null;
     }
   } catch (SQLException e) {
     throw new SQLRuntimeException("Error getting document with id: " + id + "and rev" + rev, e);
   } finally {
     DatabaseUtils.closeCursorQuietly(cursor);
   }
 }