/// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> internal SavedRevision PutProperties(IDictionary <String, Object> properties, String prevID, Boolean allowConflict) { string newId = null; if (properties != null && properties.ContainsKey("_id")) { newId = (string)properties.Get("_id"); } if (newId != null && !newId.Equals(Id, StringComparison.InvariantCultureIgnoreCase)) { Log.W(Database.Tag, String.Format("Trying to put wrong _id to this: {0} properties: {1}", this, properties)); // TODO: Make sure all string formats use .NET codes, and not Java. } // Process _attachments dict, converting CBLAttachments to dicts: IDictionary <string, object> attachments = null; if (properties != null && properties.ContainsKey("_attachments")) { attachments = (IDictionary <string, object>)properties.Get("_attachments"); } if (attachments != null && attachments.Count > 0) { var updatedAttachments = Attachment.InstallAttachmentBodies(attachments, Database); properties["_attachments"] = updatedAttachments; } var hasTrueDeletedProperty = false; if (properties != null) { hasTrueDeletedProperty = properties.Get("_deleted") != null && ((bool)properties.Get("_deleted")); } var deleted = (properties == null) || hasTrueDeletedProperty; var rev = new RevisionInternal(Id, null, deleted, Database); if (deleted) { rev.SetJson(Encoding.UTF8.GetBytes("{}")); } if (properties != null) { rev.SetProperties(properties); } var newRev = Database.PutRevision(rev, prevID, allowConflict); if (newRev == null) { return(null); } return(new SavedRevision(this, newRev)); }
private void ImportDoc(string docID, long docNumericID) { // CREATE TABLE revs ( // sequence INTEGER PRIMARY KEY AUTOINCREMENT, // doc_id INTEGER NOT NULL REFERENCES docs(doc_id) ON DELETE CASCADE, // revid TEXT NOT NULL COLLATE REVID, // parent INTEGER REFERENCES revs(sequence) ON DELETE SET NULL, // current BOOLEAN, // deleted BOOLEAN DEFAULT 0, // json BLOB, // no_attachments BOOLEAN, // UNIQUE (doc_id, revid) ); sqlite3_stmt revQuery = null; _inner.PrepareSQL(ref revQuery, "SELECT sequence, revid, parent, current, deleted, json, no_attachments" + " FROM revs WHERE doc_id=? ORDER BY sequence"); raw.sqlite3_bind_int64(revQuery, 1, docNumericID); var tree = new Dictionary <long, IList <object> >(); int err; while (raw.SQLITE_ROW == (err = raw.sqlite3_step(revQuery))) { long sequence = raw.sqlite3_column_int64(revQuery, 0); string revID = raw.sqlite3_column_text(revQuery, 1); long parentSeq = raw.sqlite3_column_int64(revQuery, 2); bool current = raw.sqlite3_column_int(revQuery, 3) != 0; bool noAtts = raw.sqlite3_column_int(revQuery, 6) != 0; if (current) { // Add a leaf revision: bool deleted = raw.sqlite3_column_int(revQuery, 4) != 0; IEnumerable <byte> json = raw.sqlite3_column_blob(revQuery, 5); if (json == null) { json = Encoding.UTF8.GetBytes("{}"); } var nuJson = json.ToList(); if (!noAtts) { try { UpdateAttachmentFollows(nuJson); } catch (CouchbaseLiteException) { Log.To.Upgrade.E(TAG, "Failed to process attachments, rethrowing..."); throw; } catch (Exception e) { throw Misc.CreateExceptionAndLog(Log.To.Upgrade, e, TAG, "Error processing attachments"); } } json = nuJson; RevisionInternal rev = new RevisionInternal(docID, revID, deleted); rev.SetJson(json); var history = new List <string>(); history.Add(revID); while (parentSeq > 0) { var ancestor = tree.Get(parentSeq); Debug.Assert(ancestor != null, String.Format("Couldn't find parent sequence of {0} (doc {1})", parentSeq, docID)); history.Add((string)ancestor[0]); parentSeq = (long)ancestor[1]; } Log.To.Upgrade.V(TAG, "Upgrading doc {0} history {1}", rev, Manager.GetObjectMapper().WriteValueAsString(history)); try { _db.ForceInsert(rev, history, null); } catch (CouchbaseLiteException) { Log.To.Upgrade.E(TAG, "Failed to insert revision {0} into target database, rethrowing...", rev); raw.sqlite3_finalize(revQuery); throw; } catch (Exception e) { raw.sqlite3_finalize(revQuery); throw Misc.CreateExceptionAndLog(Log.To.Upgrade, e, TAG, "Error inserting revision {0} into target database", rev); } NumRevs++; } else { tree[sequence] = new List <object> { revID, parentSeq }; } } raw.sqlite3_finalize(revQuery); ++NumDocs; if (err != raw.SQLITE_OK) { var s = SqliteErrToStatus(err); if (s.IsError) { throw Misc.CreateExceptionAndLog(Log.To.Upgrade, s.Code, TAG, "SQLite error during upgrade ({0})", err); } } }
private Status ImportDoc(string docID, long docNumericID) { // CREATE TABLE revs ( // sequence INTEGER PRIMARY KEY AUTOINCREMENT, // doc_id INTEGER NOT NULL REFERENCES docs(doc_id) ON DELETE CASCADE, // revid TEXT NOT NULL COLLATE REVID, // parent INTEGER REFERENCES revs(sequence) ON DELETE SET NULL, // current BOOLEAN, // deleted BOOLEAN DEFAULT 0, // json BLOB, // no_attachments BOOLEAN, // UNIQUE (doc_id, revid) ); sqlite3_stmt revQuery = null; Status status = PrepareSQL(ref revQuery, "SELECT sequence, revid, parent, current, deleted, json" + " FROM revs WHERE doc_id=? ORDER BY sequence"); if (status.IsError) { return(status); } raw.sqlite3_bind_int64(revQuery, 1, docNumericID); var tree = new Dictionary <long, IList <object> >(); int err; while (raw.SQLITE_ROW == (err = raw.sqlite3_step(revQuery))) { long sequence = raw.sqlite3_column_int64(revQuery, 0); string revID = raw.sqlite3_column_text(revQuery, 1); long parentSeq = raw.sqlite3_column_int64(revQuery, 2); bool current = raw.sqlite3_column_int(revQuery, 3) != 0; if (current) { // Add a leaf revision: bool deleted = raw.sqlite3_column_int(revQuery, 4) != 0; IEnumerable <byte> json = raw.sqlite3_column_blob(revQuery, 5); if (json == null) { json = Encoding.UTF8.GetBytes("{}"); } var nuJson = new List <byte>(json); status = AddAttachmentsToSequence(sequence, nuJson); if (status.IsError) { raw.sqlite3_finalize(revQuery); return(status); } json = nuJson; RevisionInternal rev = new RevisionInternal(docID, revID, deleted); rev.SetJson(json); var history = new List <string>(); history.Add(revID); while (parentSeq > 0) { var ancestor = tree.Get(parentSeq); Debug.Assert(ancestor != null, String.Format("Couldn't find parent sequence of {0} (doc {1})", parentSeq, docID)); history.Add((string)ancestor[0]); parentSeq = (long)ancestor[1]; } Log.D(TAG, "Upgrading doc {0} history {1}", rev, Manager.GetObjectMapper().WriteValueAsString(history)); try { _db.ForceInsert(rev, history, null); } catch (CouchbaseLiteException e) { status = e.CBLStatus; } if (status.IsError) { raw.sqlite3_finalize(revQuery); return(status); } NumRevs++; } else { tree[sequence] = new List <object> { revID, parentSeq }; } } raw.sqlite3_finalize(revQuery); ++NumDocs; return(SqliteErrToStatus(err)); }