Esempio n. 1
0
        /// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception>
        internal IList <QueryRow> ReducedQuery(Cursor cursor, Boolean group, Int32 groupLevel)
        {
            IList <object> keysToReduce   = null;
            IList <object> valuesToReduce = null;
            object         lastKey        = null;

            var reduce = Reduce;

            // FIXME: If reduce is null, then so are keysToReduce and ValuesToReduce, which can throw an NRE below.
            if (reduce != null)
            {
                keysToReduce   = new AList <Object>(ReduceBatchSize);
                valuesToReduce = new AList <Object>(ReduceBatchSize);
            }

            var rows = new AList <QueryRow>();

            cursor.MoveToNext();

            while (!cursor.IsAfterLast())
            {
                var keyData = FromJSON(cursor.GetBlob(0));
                var value   = FromJSON(cursor.GetBlob(1));
                System.Diagnostics.Debug.Assert((keyData != null));
                if (group && !GroupTogether(keyData, lastKey, groupLevel))
                {
                    if (lastKey != null)
                    {
                        // This pair starts a new group, so reduce & record the last one:
                        var reduced = (reduce != null) ? reduce(keysToReduce, valuesToReduce, false) : null;

                        var key = GroupKey(lastKey, groupLevel);
                        var row = new QueryRow(null, 0, key, reduced, null);
                        row.Database = Database;
                        rows.AddItem(row); // NOTE.ZJG: Change to `yield return row` to convert to a generator.

                        keysToReduce.Clear();
                        valuesToReduce.Clear();
                    }
                    lastKey = keyData;
                }
                keysToReduce.AddItem(keyData);
                valuesToReduce.AddItem(value);
                cursor.MoveToNext();
            }
            // NOTE.ZJG: Need to handle grouping differently if switching this to a generator.
            if (keysToReduce.Count > 0)
            {
                // Finish the last group (or the entire list, if no grouping):
                var key     = group ? GroupKey(lastKey, groupLevel) : null;
                var reduced = (reduce != null) ? reduce(keysToReduce, valuesToReduce, false) : null;
                var row     = new QueryRow(null, 0, key, reduced, null);
                row.Database = Database;
                rows.AddItem(row);
            }
            return(rows);
        }
Esempio n. 2
0
        internal IList <QueryRow> ReducedQuery(Cursor cursor, bool group, int groupLevel)
        {
            IList <object> keysToReduce   = null;
            IList <object> valuesToReduce = null;
            object         lastKey        = null;

            if (GetReduce() != null)
            {
                keysToReduce   = new AList <object>(ReduceBatchSize);
                valuesToReduce = new AList <object>(ReduceBatchSize);
            }
            IList <QueryRow> rows = new AList <QueryRow>();

            cursor.MoveToNext();
            while (!cursor.IsAfterLast())
            {
                JsonDocument keyDoc   = new JsonDocument(cursor.GetBlob(0));
                JsonDocument valueDoc = new JsonDocument(cursor.GetBlob(1));
                System.Diagnostics.Debug.Assert((keyDoc != null));
                object keyObject = keyDoc.JsonObject();
                if (group && !GroupTogether(keyObject, lastKey, groupLevel))
                {
                    if (lastKey != null)
                    {
                        // This pair starts a new group, so reduce & record the last one:
                        object reduced = (reduceBlock != null) ? reduceBlock.Reduce(keysToReduce, valuesToReduce
                                                                                    , false) : null;
                        object   key = GroupKey(lastKey, groupLevel);
                        QueryRow row = new QueryRow(null, 0, key, reduced, null);
                        row.SetDatabase(database);
                        rows.AddItem(row);
                        keysToReduce.Clear();
                        valuesToReduce.Clear();
                    }
                    lastKey = keyObject;
                }
                keysToReduce.AddItem(keyObject);
                valuesToReduce.AddItem(valueDoc.JsonObject());
                cursor.MoveToNext();
            }
            if (keysToReduce.Count > 0)
            {
                // Finish the last group (or the entire list, if no grouping):
                object key     = group ? GroupKey(lastKey, groupLevel) : null;
                object reduced = (reduceBlock != null) ? reduceBlock.Reduce(keysToReduce, valuesToReduce
                                                                            , false) : null;
                QueryRow row = new QueryRow(null, 0, key, reduced, null);
                row.SetDatabase(database);
                rows.AddItem(row);
            }
            return(rows);
        }
Esempio n. 3
0
        public long GetLastSequenceIndexed()
        {
            string sql = "SELECT lastSequence FROM views WHERE name=?";

            string[] args   = new string[] { name };
            Cursor   cursor = null;
            long     result = -1;

            try
            {
                cursor = database.GetDatabase().RawQuery(sql, args);
                if (cursor.MoveToNext())
                {
                    result = cursor.GetLong(0);
                }
            }
            catch (Exception e)
            {
                Log.E(Log.TagView, "Error getting last sequence indexed", e);
            }
            finally
            {
                if (cursor != null)
                {
                    cursor.Close();
                }
            }
            return(result);
        }
Esempio n. 4
0
 public int GetViewId()
 {
     if (viewId < 0)
     {
         string   sql    = "SELECT view_id FROM views WHERE name=?";
         string[] args   = new string[] { name };
         Cursor   cursor = null;
         try
         {
             cursor = database.GetDatabase().RawQuery(sql, args);
             if (cursor.MoveToNext())
             {
                 viewId = cursor.GetInt(0);
             }
             else
             {
                 viewId = 0;
             }
         }
         catch (SQLException e)
         {
             Log.E(Log.TagView, "Error getting view id", e);
             viewId = 0;
         }
         finally
         {
             if (cursor != null)
             {
                 cursor.Close();
             }
         }
     }
     return(viewId);
 }
Esempio n. 5
0
        /// <summary>
        /// Defines the View's <see cref="Couchbase.Lite.MapDelegate"/>
        /// and <see cref="Couchbase.Lite.ReduceDelegate"/>.
        /// </summary>
        /// <remarks>
        /// Defines a view's functions.
        /// The view's definition is given as a class that conforms to the Mapper or
        /// Reducer interface (or null to delete the view). The body of the block
        /// should call the 'emit' object (passed in as a paramter) for every key/value pair
        /// it wants to write to the view.
        /// Since the function itself is obviously not stored in the database (only a unique
        /// string idenfitying it), you must re-define the view on every launch of the app!
        /// If the database needs to rebuild the view but the function hasn't been defined yet,
        /// it will fail and the view will be empty, causing weird problems later on.
        /// It is very important that this block be a law-abiding map function! As in other
        /// languages, it must be a "pure" function, with no side effects, that always emits
        /// the same values given the same input document. That means that it should not access
        /// or change any external state; be careful, since callbacks make that so easy that you
        /// might do it inadvertently!  The callback may be called on any thread, or on
        /// multiple threads simultaneously. This won't be a problem if the code is "pure" as
        /// described above, since it will as a consequence also be thread-safe.
        /// </remarks>
        /// <returns>
        /// <c>true</c> if the <see cref="Couchbase.Lite.MapDelegate"/>
        /// and <see cref="Couchbase.Lite.ReduceDelegate"/> were set, otherwise <c>false</c>.
        /// If the values provided are identical to the values that are already set,
        /// then the values will not be updated and <c>false</c> will be returned.
        /// In addition, if <c>true</c> is returned, the index was deleted and
        /// will be rebuilt on the next <see cref="Couchbase.Lite.Query"/> execution.
        /// </returns>
        /// <param name="map">The <see cref="Couchbase.Lite.MapDelegate"/> to set.</param>
        /// <param name="reduce">The <see cref="Couchbase.Lite.ReduceDelegate"/> to set.</param>
        /// <param name="version">
        /// The key of the property value to return. The value of this parameter must change
        /// when the <see cref="Couchbase.Lite.MapDelegate"/> and/or <see cref="Couchbase.Lite.ReduceDelegate"/>
        /// are changed in a way that will cause them to produce different results.
        /// </param>
        public Boolean SetMapReduce(MapDelegate map, ReduceDelegate reduce, String version)
        {
            System.Diagnostics.Debug.Assert(map != null);
            System.Diagnostics.Debug.Assert(version != null); // String.Empty is valid.

            Map    = map;
            Reduce = reduce;

            if (!Database.Open())
            {
                return(false);
            }
            // Update the version column in the database. This is a little weird looking
            // because we want to
            // avoid modifying the database if the version didn't change, and because the
            // row might not exist yet.
            var storageEngine = this.Database.StorageEngine;

            // Older Android doesnt have reliable insert or ignore, will to 2 step
            // FIXME review need for change to execSQL, manual call to changes()
            var    sql    = "SELECT name, version FROM views WHERE name=?"; // TODO: Convert to ADO params.
            var    args   = new [] { Name };
            Cursor cursor = null;

            try
            {
                cursor = storageEngine.RawQuery(sql, args);

                if (!cursor.MoveToNext())
                {
                    // no such record, so insert
                    var insertValues = new ContentValues();
                    insertValues["name"]    = Name;
                    insertValues["version"] = version;
                    storageEngine.Insert("views", null, insertValues);
                    return(true);
                }

                var updateValues = new ContentValues();
                updateValues["version"]      = version;
                updateValues["lastSequence"] = 0;

                var whereArgs    = new [] { Name, version };
                var rowsAffected = storageEngine.Update("views", updateValues, "name=? AND version!=?", whereArgs);

                return(rowsAffected > 0);
            }
            catch (SQLException e)
            {
                Log.E(Database.Tag, "Error setting map block", e);
                return(false);
            }
            finally
            {
                if (cursor != null)
                {
                    cursor.Close();
                }
            }
        }
Esempio n. 6
0
        public long GetLastSequenceIndexed()
        {
            string sql = "SELECT lastSequence FROM views WHERE name=?";

            string[] args   = new string[] { name };
            Cursor   cursor = null;
            long     result = -1;

            try
            {
                Log.D(Database.TagSql, Sharpen.Thread.CurrentThread().GetName() + " start running query: "
                      + sql);
                cursor = database.GetDatabase().RawQuery(sql, args);
                Log.D(Database.TagSql, Sharpen.Thread.CurrentThread().GetName() + " finish running query: "
                      + sql);
                if (cursor.MoveToNext())
                {
                    result = cursor.GetLong(0);
                }
            }
            catch (Exception e)
            {
                Log.E(Database.Tag, "Error getting last sequence indexed", e);
            }
            finally
            {
                if (cursor != null)
                {
                    cursor.Close();
                }
            }
            return(result);
        }
Esempio n. 7
0
        public bool SetMapReduce(Mapper mapBlock, Reducer reduceBlock, string version)
        {
            System.Diagnostics.Debug.Assert((mapBlock != null));
            System.Diagnostics.Debug.Assert((version != null));
            this.mapBlock    = mapBlock;
            this.reduceBlock = reduceBlock;
            if (!database.Open())
            {
                return(false);
            }
            // Update the version column in the database. This is a little weird looking
            // because we want to
            // avoid modifying the database if the version didn't change, and because the
            // row might not exist yet.
            SQLiteStorageEngine storageEngine = this.database.GetDatabase();
            // Older Android doesnt have reliable insert or ignore, will to 2 step
            // FIXME review need for change to execSQL, manual call to changes()
            string sql = "SELECT name, version FROM views WHERE name=?";

            string[] args   = new string[] { name };
            Cursor   cursor = null;

            try
            {
                cursor = storageEngine.RawQuery(sql, args);
                if (!cursor.MoveToNext())
                {
                    // no such record, so insert
                    ContentValues insertValues = new ContentValues();
                    insertValues.Put("name", name);
                    insertValues.Put("version", version);
                    storageEngine.Insert("views", null, insertValues);
                    return(true);
                }
                ContentValues updateValues = new ContentValues();
                updateValues.Put("version", version);
                updateValues.Put("lastSequence", 0);
                string[] whereArgs    = new string[] { name, version };
                int      rowsAffected = storageEngine.Update("views", updateValues, "name=? AND version!=?"
                                                             , whereArgs);
                return(rowsAffected > 0);
            }
            catch (SQLException e)
            {
                Log.E(Log.TagView, "Error setting map block", e);
                return(false);
            }
            finally
            {
                if (cursor != null)
                {
                    cursor.Close();
                }
            }
        }
Esempio n. 8
0
        public IList <IDictionary <string, object> > Dump()
        {
            if (GetViewId() < 0)
            {
                return(null);
            }
            string[] selectArgs = new string[] { Sharpen.Extensions.ToString(GetViewId()) };
            Cursor   cursor     = null;
            IList <IDictionary <string, object> > result = null;

            try
            {
                cursor = database.GetDatabase().RawQuery("SELECT sequence, key, value FROM maps WHERE view_id=? ORDER BY key"
                                                         , selectArgs);
                cursor.MoveToNext();
                result = new AList <IDictionary <string, object> >();
                while (!cursor.IsAfterLast())
                {
                    IDictionary <string, object> row = new Dictionary <string, object>();
                    row.Put("seq", cursor.GetInt(0));
                    row.Put("key", cursor.GetString(1));
                    row.Put("value", cursor.GetString(2));
                    result.AddItem(row);
                    cursor.MoveToNext();
                }
            }
            catch (SQLException e)
            {
                Log.E(Log.TagView, "Error dumping view", e);
                return(null);
            }
            finally
            {
                if (cursor != null)
                {
                    cursor.Close();
                }
            }
            return(result);
        }
Esempio n. 9
0
        internal IList <IDictionary <string, object> > Dump()
        {
            if (Id < 0)
            {
                return(null);
            }

            var result = new List <IDictionary <string, object> >();

            var selectArgs = new string[] { Id.ToString() };

            Cursor cursor = null;

            try
            {
                cursor = Database.StorageEngine.RawQuery(
                    "SELECT sequence, key, value FROM maps WHERE view_id=? ORDER BY key", selectArgs);

                while (cursor.MoveToNext())
                {
                    var row = new Dictionary <string, object>();
                    row.Put("seq", cursor.GetInt(0));
                    row.Put("key", cursor.GetString(1));
                    row.Put("value", cursor.GetString(2));
                    result.AddItem(row);
                }
            }
            catch (SQLException e)
            {
                Log.E(Tag, "Error dumping view", e);
                result = null;
            }
            finally
            {
                if (cursor != null)
                {
                    cursor.Close();
                }
            }

            return(result);
        }
Esempio n. 10
0
        /// <exception cref="System.Exception"></exception>
        public virtual void DumpTableRevs()
        {
            Cursor cursor = database.GetDatabase().RawQuery("SELECT * FROM revs", null);

            while (cursor.MoveToNext())
            {
                int    sequence = cursor.GetInt(0);
                int    doc_id   = cursor.GetInt(1);
                byte[] revid    = cursor.GetBlob(2);
                string revIdStr = null;
                if (revid != null)
                {
                    revIdStr = Sharpen.Runtime.GetStringForBytes(revid);
                }
                int parent  = cursor.GetInt(3);
                int current = cursor.GetInt(4);
                int deleted = cursor.GetInt(5);
                Log.D(Tag, string.Format("Revs row seq: %s doc_id: %s, revIdStr: %s, parent: %s, current: %s, deleted: %s"
                                         , sequence, doc_id, revIdStr, parent, current, deleted));
            }
        }
Esempio n. 11
0
        /// <exception cref="System.Exception"></exception>
        public virtual void DumpTableMaps()
        {
            Cursor cursor = database.GetDatabase().RawQuery("SELECT * FROM maps", null);

            while (cursor.MoveToNext())
            {
                int    viewId   = cursor.GetInt(0);
                int    sequence = cursor.GetInt(1);
                byte[] key      = cursor.GetBlob(2);
                string keyStr   = null;
                if (key != null)
                {
                    keyStr = Sharpen.Runtime.GetStringForBytes(key);
                }
                byte[] value    = cursor.GetBlob(3);
                string valueStr = null;
                if (value != null)
                {
                    valueStr = Sharpen.Runtime.GetStringForBytes(value);
                }
                Log.D(Tag, string.Format("Maps row viewId: %s seq: %s, key: %s, val: %s", viewId,
                                         sequence, keyStr, valueStr));
            }
        }
Esempio n. 12
0
        /// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception>
        internal IList<QueryRow> ReducedQuery(Cursor cursor, Boolean group, Int32 groupLevel)
        {
            IList<object> keysToReduce = null;
            IList<object> valuesToReduce = null;
            object lastKey = null;

            var reduce = Reduce;
            // FIXME: If reduce is null, then so are keysToReduce and ValuesToReduce, which can throw an NRE below.
            if (reduce != null)
            {
                keysToReduce = new AList<Object>(ReduceBatchSize);
                valuesToReduce = new AList<Object>(ReduceBatchSize);
            }

            var rows = new AList<QueryRow>();
            cursor.MoveToNext();

            while (!cursor.IsAfterLast())
            {
                var keyData = FromJSON(cursor.GetBlob(0));
                var value = FromJSON(cursor.GetBlob(1));
                System.Diagnostics.Debug.Assert((keyData != null));
                if (group && !GroupTogether(keyData, lastKey, groupLevel))
                {
                    if (lastKey != null)
                    {
                        // This pair starts a new group, so reduce & record the last one:
                        var reduced = (reduce != null) ? reduce(keysToReduce, valuesToReduce, false) : null;

                        var key = GroupKey(lastKey, groupLevel);
                        var row = new QueryRow(null, 0, key, reduced, null);
                        row.Database = Database;
                        rows.AddItem(row); // NOTE.ZJG: Change to `yield return row` to convert to a generator.

                        keysToReduce.Clear();
                        valuesToReduce.Clear();
                    }
                    lastKey = keyData;
                }
                keysToReduce.AddItem(keyData);
                valuesToReduce.AddItem(value);
                cursor.MoveToNext();
            }
            // NOTE.ZJG: Need to handle grouping differently if switching this to a generator.
            if (keysToReduce.Count > 0)
            {
                // Finish the last group (or the entire list, if no grouping):
                var key = group ? GroupKey(lastKey, groupLevel) : null;
                var reduced = (reduce != null) ? reduce(keysToReduce, valuesToReduce, false) : null;
                var row = new QueryRow(null, 0, key, reduced, null);
                row.Database = Database;
                rows.AddItem(row);
            }
            return rows;
        }
Esempio n. 13
0
        /// <summary>Queries the view.</summary>
        /// <remarks>Queries the view. Does NOT first update the index.</remarks>
        /// <param name="options">The options to use.</param>
        /// <returns>An array of QueryRow objects.</returns>
        /// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception>
        internal IEnumerable <QueryRow> QueryWithOptions(QueryOptions options)
        {
            if (options == null)
            {
                options = new QueryOptions();
            }

            Cursor           cursor = null;
            IList <QueryRow> rows   = new List <QueryRow>();

            try
            {
                cursor = ResultSetWithOptions(options);
                int groupLevel  = options.GetGroupLevel();
                var group       = options.IsGroup() || (groupLevel > 0);
                var reduceBlock = Reduce;
                var reduce      = GroupOrReduce(options);

                if (reduce && (reduceBlock == null) && !group)
                {
                    var msg = "Cannot use reduce option in view " + Name + " which has no reduce block defined";
                    Log.W(Database.Tag, msg);
                    throw new CouchbaseLiteException(StatusCode.BadRequest);
                }

                if (reduce || group)
                {
                    // Reduced or grouped query:
                    rows = ReducedQuery(cursor, group, groupLevel);
                }
                else
                {
                    // regular query
                    cursor.MoveToNext();
                    while (!cursor.IsAfterLast())
                    {
                        var key          = FromJSON(cursor.GetBlob(0));
                        var value        = FromJSON(cursor.GetBlob(1));
                        var docId        = cursor.GetString(2);
                        var sequenceLong = cursor.GetLong(3);
                        var sequence     = Convert.ToInt32(sequenceLong);


                        IDictionary <string, object> docContents = null;
                        if (options.IsIncludeDocs())
                        {
                            // http://wiki.apache.org/couchdb/Introduction_to_CouchDB_views#Linked_documents
                            if (value is IDictionary <string, object> && ((IDictionary <string, object>)value).ContainsKey("_id"))
                            {
                                var linkedDocId = (string)((IDictionary <string, object>)value).Get("_id");
                                var linkedDoc   = Database.GetDocumentWithIDAndRev(linkedDocId, null, DocumentContentOptions.None);
                                docContents = linkedDoc.GetProperties();
                            }
                            else
                            {
                                var revId = cursor.GetString(4);
                                docContents = Database.DocumentPropertiesFromJSON(cursor.GetBlob(5), docId, revId, false, sequenceLong, options.GetContentOptions());
                            }
                        }
                        var row = new QueryRow(docId, sequence, key, value, docContents);
                        row.Database = Database;
                        rows.AddItem <QueryRow>(row);  // NOTE.ZJG: Change to `yield return row` to convert to a generator.
                        cursor.MoveToNext();
                    }
                }
            }
            catch (SQLException e)
            {
                var errMsg = string.Format("Error querying view: {0}", this);
                Log.E(Database.Tag, errMsg, e);
                throw new CouchbaseLiteException(errMsg, e, new Status(StatusCode.DbError));
            }
            finally
            {
                if (cursor != null)
                {
                    cursor.Close();
                }
            }
            return(rows);
        }
Esempio n. 14
0
        internal void UpdateIndex()
        {
            Log.I(Database.Tag, "Re-indexing view {0} ...", Name);
            System.Diagnostics.Debug.Assert((Map != null));

            if (Id <= 0)
            {
                var msg = string.Format("View.Id <= 0");
                throw new CouchbaseLiteException(msg, new Status(StatusCode.NotFound));
            }

            var    result  = new Status(StatusCode.InternalServerError);
            Cursor cursor  = null;
            Cursor cursor2 = null;

            try
            {
                Database.RunInTransaction(() =>
                {
                    var lastSequence  = LastSequenceIndexed;
                    var dbMaxSequence = Database.LastSequenceNumber;

                    if (lastSequence >= dbMaxSequence)
                    {
                        // nothing to do (eg,  kCBLStatusNotModified)
                        Log.V(Database.Tag, "lastSequence ({0}) == dbMaxSequence ({1}), nothing to do", lastSequence, dbMaxSequence);
                        result.SetCode(StatusCode.NotModified);
                        return(false);
                    }

                    // First remove obsolete emitted results from the 'maps' table:
                    var sequence = lastSequence;
                    if (lastSequence < 0)
                    {
                        var msg = string.Format("lastSequence < 0 ({0})", lastSequence);
                        throw new CouchbaseLiteException(msg, new Status(StatusCode.InternalServerError));
                    }
                    if (lastSequence == 0)
                    {
                        // If the lastSequence has been reset to 0, make sure to remove
                        // any leftover rows:
                        var whereArgs = new string[] { Id.ToString() };
                        Database.StorageEngine.Delete("maps", "view_id=?", whereArgs);
                    }
                    else
                    {
                        Database.OptimizeSQLIndexes();
                        // Delete all obsolete map results (ones from since-replaced
                        // revisions):
                        var args = new [] {
                            Id.ToString(),
                            lastSequence.ToString(),
                            lastSequence.ToString()
                        };

                        Database.StorageEngine.ExecSQL(
                            "DELETE FROM maps WHERE view_id=? AND sequence IN ("
                            + "SELECT parent FROM revs WHERE sequence>? " + "AND +parent>0 AND +parent<=?)",
                            args);
                    }

                    var deleted = 0;
                    cursor      = Database.StorageEngine.IntransactionRawQuery("SELECT changes()");
                    cursor.MoveToNext();
                    deleted = cursor.GetInt(0);
                    cursor.Close();

                    // Find a better way to propagate this back
                    // Now scan every revision added since the last time the view was indexed:
                    var selectArgs = new[] { lastSequence.ToString(), dbMaxSequence.ToString() };
                    cursor         = Database.StorageEngine.IntransactionRawQuery("SELECT revs.doc_id, sequence, docid, revid, json, no_attachments FROM revs, docs "
                                                                                  + "WHERE sequence>? AND sequence<=? AND current!=0 AND deleted=0 "
                                                                                  + "AND revs.doc_id = docs.doc_id "
                                                                                  + "ORDER BY revs.doc_id, revid DESC", selectArgs);

                    var lastDocID = 0L;
                    var keepGoing = cursor.MoveToNext();
                    while (keepGoing)
                    {
                        long docID = cursor.GetLong(0);
                        if (docID != lastDocID)
                        {
                            // Only look at the first-iterated revision of any document,
                            // because this is the
                            // one with the highest revid, hence the "winning" revision
                            // of a conflict.
                            lastDocID = docID;
                            // Reconstitute the document as a dictionary:
                            sequence     = cursor.GetLong(1);
                            string docId = cursor.GetString(2);
                            if (docId.StartsWith("_design/", StringComparison.InvariantCultureIgnoreCase))
                            {
                                // design docs don't get indexed!
                                keepGoing = cursor.MoveToNext();
                                continue;
                            }
                            var revId = cursor.GetString(3);
                            var json  = cursor.GetBlob(4);

                            var noAttachments = cursor.GetInt(5) > 0;

                            // Skip rows with the same doc_id -- these are losing conflicts.
                            while ((keepGoing = cursor.MoveToNext()) && cursor.GetLong(0) == docID)
                            {
                            }

                            if (lastSequence > 0)
                            {
                                // Find conflicts with documents from previous indexings.
                                var selectArgs2 = new[] { Convert.ToString(docID), Convert.ToString(lastSequence) };
                                cursor2         = Database.StorageEngine.IntransactionRawQuery("SELECT revid, sequence FROM revs "
                                                                                               + "WHERE doc_id=? AND sequence<=? AND current!=0 AND deleted=0 " + "ORDER BY revID DESC "
                                                                                               + "LIMIT 1", selectArgs2);
                                if (cursor2.MoveToNext())
                                {
                                    var oldRevId = cursor2.GetString(0);

                                    // This is the revision that used to be the 'winner'.
                                    // Remove its emitted rows:
                                    var oldSequence = cursor2.GetLong(1);
                                    var args        = new[] { Sharpen.Extensions.ToString(Id), Convert.ToString(oldSequence) };
                                    Database.StorageEngine.ExecSQL("DELETE FROM maps WHERE view_id=? AND sequence=?", args);

                                    if (RevisionInternal.CBLCompareRevIDs(oldRevId, revId) > 0)
                                    {
                                        // It still 'wins' the conflict, so it's the one that
                                        // should be mapped [again], not the current revision!
                                        revId           = oldRevId;
                                        sequence        = oldSequence;
                                        var selectArgs3 = new[] { Convert.ToString(sequence) };
                                        json            = Misc.ByteArrayResultForQuery(
                                            Database.StorageEngine,
                                            "SELECT json FROM revs WHERE sequence=?",
                                            selectArgs3
                                            );
                                    }
                                }

                                cursor2.Close();
                                cursor2 = null;
                            }
                            // Get the document properties, to pass to the map function:
                            var contentOptions = DocumentContentOptions.None;
                            if (noAttachments)
                            {
                                contentOptions |= DocumentContentOptions.NoAttachments;
                            }

                            var properties = Database.DocumentPropertiesFromJSON(
                                json, docId, revId, false, sequence, DocumentContentOptions.None
                                );
                            if (properties != null)
                            {
                                // Call the user-defined map() to emit new key/value
                                // pairs from this revision:

                                // This is the emit() block, which gets called from within the
                                // user-defined map() block
                                // that's called down below.

                                var enclosingView = this;
                                var thisSequence  = sequence;
                                var map           = Map;

                                if (map == null)
                                {
                                    throw new CouchbaseLiteException("Map function is missing.");
                                }

                                EmitDelegate emitBlock = (key, value) =>
                                {
                                    // TODO: Do we need to do any null checks on key or value?
                                    try
                                    {
                                        var keyJson   = Manager.GetObjectMapper().WriteValueAsString(key);
                                        var valueJson = value == null ? null : Manager.GetObjectMapper().WriteValueAsString(value);

                                        var insertValues = new ContentValues();
                                        insertValues.Put("view_id", enclosingView.Id);
                                        insertValues["sequence"] = thisSequence;
                                        insertValues["key"]      = keyJson;
                                        insertValues["value"]    = valueJson;

                                        enclosingView.Database.StorageEngine.Insert("maps", null, insertValues);
                                    }
                                    catch (Exception e)
                                    {
                                        Log.E(Database.Tag, "Error emitting", e);
                                    }
                                };

                                map(properties, emitBlock);
                            }
                        }
                        else
                        {
                            keepGoing = cursor.MoveToNext();
                        }
                    }

                    // Finally, record the last revision sequence number that was
                    // indexed:
                    var updateValues             = new ContentValues();
                    updateValues["lastSequence"] = dbMaxSequence;
                    var whereArgs_1 = new string[] { Id.ToString() };
                    Database.StorageEngine.Update("views", updateValues, "view_id=?", whereArgs_1);

                    // FIXME actually count number added :)
                    Log.V(Database.Tag, "...Finished re-indexing view {0} up to sequence {1} (deleted {2} added ?)", Name, Convert.ToString(dbMaxSequence), deleted);
                    result.SetCode(StatusCode.Ok);

                    return(true);
                });
            }
            catch (Exception e)
            {
                throw new CouchbaseLiteException(e, new Status(StatusCode.DbError));
            }
            finally
            {
                if (cursor2 != null)
                {
                    cursor2.Close();
                }

                if (cursor != null)
                {
                    cursor.Close();
                }

                if (!result.IsSuccessful)
                {
                    Log.W(Database.Tag, "Failed to rebuild view {0}:{1}", Name, result.GetCode());
                }
            }
        }
Esempio n. 15
0
        public IList <QueryRow> QueryWithOptions(QueryOptions options)
        {
            if (options == null)
            {
                options = new QueryOptions();
            }
            Cursor           cursor = null;
            IList <QueryRow> rows   = new AList <QueryRow>();

            try
            {
                cursor = ResultSetWithOptions(options);
                int  groupLevel = options.GetGroupLevel();
                bool group      = options.IsGroup() || (groupLevel > 0);
                bool reduce     = options.IsReduce() || group;
                if (reduce && (reduceBlock == null) && !group)
                {
                    Log.W(Log.TagView, "Cannot use reduce option in view %s which has no reduce block defined"
                          , name);
                    throw new CouchbaseLiteException(new Status(Status.BadRequest));
                }
                if (reduce || group)
                {
                    // Reduced or grouped query:
                    rows = ReducedQuery(cursor, group, groupLevel);
                }
                else
                {
                    // regular query
                    cursor.MoveToNext();
                    while (!cursor.IsAfterLast())
                    {
                        JsonDocument keyDoc   = new JsonDocument(cursor.GetBlob(0));
                        JsonDocument valueDoc = new JsonDocument(cursor.GetBlob(1));
                        string       docId    = cursor.GetString(2);
                        int          sequence = Sharpen.Extensions.ValueOf(cursor.GetString(3));
                        IDictionary <string, object> docContents = null;
                        if (options.IsIncludeDocs())
                        {
                            object valueObject = valueDoc.JsonObject();
                            // http://wiki.apache.org/couchdb/Introduction_to_CouchDB_views#Linked_documents
                            if (valueObject is IDictionary && ((IDictionary)valueObject).ContainsKey("_id"))
                            {
                                string           linkedDocId = (string)((IDictionary)valueObject).Get("_id");
                                RevisionInternal linkedDoc   = database.GetDocumentWithIDAndRev(linkedDocId, null,
                                                                                                EnumSet.NoneOf <Database.TDContentOptions>());
                                docContents = linkedDoc.GetProperties();
                            }
                            else
                            {
                                docContents = database.DocumentPropertiesFromJSON(cursor.GetBlob(5), docId, cursor
                                                                                  .GetString(4), false, cursor.GetLong(3), options.GetContentOptions());
                            }
                        }
                        QueryRow row = new QueryRow(docId, sequence, keyDoc.JsonObject(), valueDoc.JsonObject
                                                        (), docContents);
                        row.SetDatabase(database);
                        rows.AddItem(row);
                        cursor.MoveToNext();
                    }
                }
            }
            catch (SQLException e)
            {
                string errMsg = string.Format("Error querying view: %s", this);
                Log.E(Log.TagView, errMsg, e);
                throw new CouchbaseLiteException(errMsg, e, new Status(Status.DbError));
            }
            finally
            {
                if (cursor != null)
                {
                    cursor.Close();
                }
            }
            return(rows);
        }
Esempio n. 16
0
        internal void UpdateIndex()
        {
            Log.V(Database.Tag, "Re-indexing view " + Name + " ...");
            System.Diagnostics.Debug.Assert((Map != null));

            if (Id < 0)
            {
                var msg = string.Format("View.Id < 0");
                throw new CouchbaseLiteException(msg, new Status(StatusCode.NotFound));
            }

            Database.BeginTransaction();

            var    result = new Status(StatusCode.InternalServerError);
            Cursor cursor = null;

            try
            {
                var lastSequence  = LastSequenceIndexed;
                var dbMaxSequence = Database.LastSequenceNumber;

                if (lastSequence == dbMaxSequence)
                {
                    // nothing to do (eg,  kCBLStatusNotModified)
                    var msg = String.Format("lastSequence ({0}) == dbMaxSequence ({1}), nothing to do", lastSequence, dbMaxSequence);
                    Log.D(Database.Tag, msg);
                    result.SetCode(StatusCode.Ok);
                    return;
                }

                // First remove obsolete emitted results from the 'maps' table:
                var sequence = lastSequence;
                if (lastSequence < 0)
                {
                    var msg = string.Format("lastSequence < 0 ({0})", lastSequence);
                    throw new CouchbaseLiteException(msg, new Status(StatusCode.InternalServerError));
                }
                if (lastSequence == 0)
                {
                    // If the lastSequence has been reset to 0, make sure to remove
                    // any leftover rows:
                    var whereArgs = new string[] { Sharpen.Extensions.ToString(Id) };
                    Database.StorageEngine.Delete("maps", "view_id=@", whereArgs);
                }
                else
                {
                    // Delete all obsolete map results (ones from since-replaced
                    // revisions):
                    var args = new [] {
                        Id.ToString(),
                        lastSequence.ToString(),
                        lastSequence.ToString()
                    };

                    Database.StorageEngine.ExecSQL(
                        "DELETE FROM maps WHERE view_id=@ AND sequence IN ("
                        + "SELECT parent FROM revs WHERE sequence>@ " + "AND parent>0 AND parent<=@)",
                        args);
                }
                var deleted = 0;
                cursor = Database.StorageEngine.RawQuery("SELECT changes()", null); // TODO: Convert to ADO params.
                cursor.MoveToNext();
                deleted = cursor.GetInt(0);
                cursor.Close();

                // find a better way to propagate this back
                // Now scan every revision added since the last time the view was
                // indexed:
                var selectArgs = new[] { Convert.ToString(lastSequence) };
                cursor = Database.StorageEngine.RawQuery("SELECT revs.doc_id, sequence, docid, revid, json FROM revs, docs "
                                                         + "WHERE sequence>@ AND current!=0 AND deleted=0 " + "AND revs.doc_id = docs.doc_id "
                                                         + "ORDER BY revs.doc_id, revid DESC", CommandBehavior.SequentialAccess, selectArgs);
                cursor.MoveToNext();

                var lastDocID = 0L;
                while (!cursor.IsAfterLast())
                {
                    long docID = cursor.GetLong(0);
                    if (docID != lastDocID)
                    {
                        // Only look at the first-iterated revision of any document,
                        // because this is the
                        // one with the highest revid, hence the "winning" revision
                        // of a conflict.
                        lastDocID = docID;
                        // Reconstitute the document as a dictionary:
                        sequence = cursor.GetLong(1);
                        string docId = cursor.GetString(2);
                        if (docId.StartsWith("_design/", StringComparison.InvariantCultureIgnoreCase))
                        {
                            // design docs don't get indexed!
                            cursor.MoveToNext();
                            continue;
                        }
                        var revId      = cursor.GetString(3);
                        var json       = cursor.GetBlob(4);
                        var properties = Database.DocumentPropertiesFromJSON(
                            json, docId, revId, false, sequence, EnumSet.NoneOf <TDContentOptions>()
                            );
                        if (properties != null)
                        {
                            // Call the user-defined map() to emit new key/value
                            // pairs from this revision:
                            Log.V(Database.Tag, "  call map for sequence=" + System.Convert.ToString(sequence
                                                                                                     ));
                            // This is the emit() block, which gets called from within the
                            // user-defined map() block
                            // that's called down below.

                            var enclosingView = this;
                            var thisSequence  = sequence;
                            var map           = Map;

                            if (map == null)
                            {
                                throw new CouchbaseLiteException("Map function is missing.");
                            }

                            EmitDelegate emitBlock = (key, value) =>
                            {
                                // TODO: Do we need to do any null checks on key or value?
                                try
                                {
                                    var keyJson   = Manager.GetObjectMapper().WriteValueAsString(key);
                                    var valueJson = value == null ? null : Manager.GetObjectMapper().WriteValueAsString(value);
                                    Log.V(Database.Tag, String.Format("    emit({0}, {1})", keyJson, valueJson));

                                    var insertValues = new ContentValues();
                                    insertValues.Put("view_id", enclosingView.Id);
                                    insertValues["sequence"] = thisSequence;
                                    insertValues["key"]      = keyJson;
                                    insertValues["value"]    = valueJson;

                                    enclosingView.Database.StorageEngine.Insert("maps", null, insertValues);
                                }
                                catch (Exception e)
                                {
                                    Log.E(Database.Tag, "Error emitting", e);
                                }
                            };

                            map(properties, emitBlock);
                        }
                    }
                    cursor.MoveToNext();
                }
                // Finally, record the last revision sequence number that was
                // indexed:
                ContentValues updateValues = new ContentValues();
                updateValues["lastSequence"] = dbMaxSequence;
                var whereArgs_1 = new string[] { Sharpen.Extensions.ToString(Id) };
                Database.StorageEngine.Update("views", updateValues, "view_id=@", whereArgs_1);
                // FIXME actually count number added :)
                Log.V(Database.Tag, "...Finished re-indexing view " + Name + " up to sequence " +
                      System.Convert.ToString(dbMaxSequence) + " (deleted " + deleted + " added " + "?" + ")");
                result.SetCode(StatusCode.Ok);
            }
            catch (SQLException e)
            {
                throw new CouchbaseLiteException(e, new Status(StatusCode.DbError));
            }
            finally
            {
                if (cursor != null)
                {
                    cursor.Close();
                }
                if (!result.IsSuccessful())
                {
                    Log.W(Database.Tag, "Failed to rebuild view " + Name + ": " + result.GetCode());
                }
                if (Database != null)
                {
                    Database.EndTransaction(result.IsSuccessful());
                }
            }
        }
Esempio n. 17
0
        public void UpdateIndex()
        {
            Log.V(Log.TagView, "Re-indexing view: %s", name);
            System.Diagnostics.Debug.Assert((mapBlock != null));
            if (GetViewId() <= 0)
            {
                string msg = string.Format("getViewId() < 0");
                throw new CouchbaseLiteException(msg, new Status(Status.NotFound));
            }
            database.BeginTransaction();
            Status result = new Status(Status.InternalServerError);
            Cursor cursor = null;

            try
            {
                long lastSequence  = GetLastSequenceIndexed();
                long dbMaxSequence = database.GetLastSequenceNumber();
                if (lastSequence == dbMaxSequence)
                {
                    // nothing to do (eg,  kCBLStatusNotModified)
                    Log.V(Log.TagView, "lastSequence (%s) == dbMaxSequence (%s), nothing to do", lastSequence
                          , dbMaxSequence);
                    result.SetCode(Status.NotModified);
                    return;
                }
                // First remove obsolete emitted results from the 'maps' table:
                long sequence = lastSequence;
                if (lastSequence < 0)
                {
                    string msg = string.Format("lastSequence < 0 (%s)", lastSequence);
                    throw new CouchbaseLiteException(msg, new Status(Status.InternalServerError));
                }
                if (lastSequence == 0)
                {
                    // If the lastSequence has been reset to 0, make sure to remove
                    // any leftover rows:
                    string[] whereArgs = new string[] { Sharpen.Extensions.ToString(GetViewId()) };
                    database.GetDatabase().Delete("maps", "view_id=?", whereArgs);
                }
                else
                {
                    // Delete all obsolete map results (ones from since-replaced
                    // revisions):
                    string[] args = new string[] { Sharpen.Extensions.ToString(GetViewId()), System.Convert.ToString
                                                       (lastSequence), System.Convert.ToString(lastSequence) };
                    database.GetDatabase().ExecSQL("DELETE FROM maps WHERE view_id=? AND sequence IN ("
                                                   + "SELECT parent FROM revs WHERE sequence>? " + "AND parent>0 AND parent<=?)",
                                                   args);
                }
                int deleted = 0;
                cursor = database.GetDatabase().RawQuery("SELECT changes()", null);
                cursor.MoveToNext();
                deleted = cursor.GetInt(0);
                cursor.Close();
                // This is the emit() block, which gets called from within the
                // user-defined map() block
                // that's called down below.
                AbstractTouchMapEmitBlock emitBlock = new _AbstractTouchMapEmitBlock_428(this);
                //Log.v(Log.TAG_VIEW, "    emit(" + keyJson + ", "
                //        + valueJson + ")");
                // find a better way to propagate this back
                // Now scan every revision added since the last time the view was
                // indexed:
                string[] selectArgs = new string[] { System.Convert.ToString(lastSequence) };
                cursor = database.GetDatabase().RawQuery("SELECT revs.doc_id, sequence, docid, revid, json, no_attachments FROM revs, docs "
                                                         + "WHERE sequence>? AND current!=0 AND deleted=0 " + "AND revs.doc_id = docs.doc_id "
                                                         + "ORDER BY revs.doc_id, revid DESC", selectArgs);
                long lastDocID = 0;
                bool keepGoing = cursor.MoveToNext();
                while (keepGoing)
                {
                    long docID = cursor.GetLong(0);
                    if (docID != lastDocID)
                    {
                        // Only look at the first-iterated revision of any document,
                        // because this is the
                        // one with the highest revid, hence the "winning" revision
                        // of a conflict.
                        lastDocID = docID;
                        // Reconstitute the document as a dictionary:
                        sequence = cursor.GetLong(1);
                        string docId = cursor.GetString(2);
                        if (docId.StartsWith("_design/"))
                        {
                            // design docs don't get indexed!
                            keepGoing = cursor.MoveToNext();
                            continue;
                        }
                        string revId         = cursor.GetString(3);
                        byte[] json          = cursor.GetBlob(4);
                        bool   noAttachments = cursor.GetInt(5) > 0;
                        while ((keepGoing = cursor.MoveToNext()) && cursor.GetLong(0) == docID)
                        {
                        }
                        // Skip rows with the same doc_id -- these are losing conflicts.
                        if (lastSequence > 0)
                        {
                            // Find conflicts with documents from previous indexings.
                            string[] selectArgs2 = new string[] { System.Convert.ToString(docID), System.Convert.ToString
                                                                      (lastSequence) };
                            Cursor cursor2 = database.GetDatabase().RawQuery("SELECT revid, sequence FROM revs "
                                                                             + "WHERE doc_id=? AND sequence<=? AND current!=0 AND deleted=0 " + "ORDER BY revID DESC "
                                                                             + "LIMIT 1", selectArgs2);
                            if (cursor2.MoveToNext())
                            {
                                string oldRevId = cursor2.GetString(0);
                                // This is the revision that used to be the 'winner'.
                                // Remove its emitted rows:
                                long     oldSequence = cursor2.GetLong(1);
                                string[] args        = new string[] { Sharpen.Extensions.ToString(GetViewId()), System.Convert.ToString
                                                                          (oldSequence) };
                                database.GetDatabase().ExecSQL("DELETE FROM maps WHERE view_id=? AND sequence=?",
                                                               args);
                                if (RevisionInternal.CBLCompareRevIDs(oldRevId, revId) > 0)
                                {
                                    // It still 'wins' the conflict, so it's the one that
                                    // should be mapped [again], not the current revision!
                                    revId    = oldRevId;
                                    sequence = oldSequence;
                                    string[] selectArgs3 = new string[] { System.Convert.ToString(sequence) };
                                    json = Utils.ByteArrayResultForQuery(database.GetDatabase(), "SELECT json FROM revs WHERE sequence=?"
                                                                         , selectArgs3);
                                }
                            }
                        }
                        // Get the document properties, to pass to the map function:
                        EnumSet <Database.TDContentOptions> contentOptions = EnumSet.NoneOf <Database.TDContentOptions
                                                                                             >();
                        if (noAttachments)
                        {
                            contentOptions.AddItem(Database.TDContentOptions.TDNoAttachments);
                        }
                        IDictionary <string, object> properties = database.DocumentPropertiesFromJSON(json
                                                                                                      , docId, revId, false, sequence, contentOptions);
                        if (properties != null)
                        {
                            // Call the user-defined map() to emit new key/value
                            // pairs from this revision:
                            emitBlock.SetSequence(sequence);
                            mapBlock.Map(properties, emitBlock);
                        }
                    }
                }
                // Finally, record the last revision sequence number that was
                // indexed:
                ContentValues updateValues = new ContentValues();
                updateValues.Put("lastSequence", dbMaxSequence);
                string[] whereArgs_1 = new string[] { Sharpen.Extensions.ToString(GetViewId()) };
                database.GetDatabase().Update("views", updateValues, "view_id=?", whereArgs_1);
                // FIXME actually count number added :)
                Log.V(Log.TagView, "Finished re-indexing view: %s " + " up to sequence %s" + " (deleted %s added ?)"
                      , name, dbMaxSequence, deleted);
                result.SetCode(Status.Ok);
            }
            catch (SQLException e)
            {
                throw new CouchbaseLiteException(e, new Status(Status.DbError));
            }
            finally
            {
                if (cursor != null)
                {
                    cursor.Close();
                }
                if (!result.IsSuccessful())
                {
                    Log.W(Log.TagView, "Failed to rebuild view %s.  Result code: %d", name, result.GetCode
                              ());
                }
                if (database != null)
                {
                    database.EndTransaction(result.IsSuccessful());
                }
            }
        }
Esempio n. 18
0
        public void UpdateIndex()
        {
            Log.V(Database.Tag, "Re-indexing view " + name + " ...");
            System.Diagnostics.Debug.Assert((mapBlock != null));
            if (GetViewId() < 0)
            {
                string msg = string.Format("getViewId() < 0");
                throw new CouchbaseLiteException(msg, new Status(Status.NotFound));
            }
            database.BeginTransaction();
            Status result = new Status(Status.InternalServerError);
            Cursor cursor = null;

            try
            {
                long lastSequence  = GetLastSequenceIndexed();
                long dbMaxSequence = database.GetLastSequenceNumber();
                if (lastSequence == dbMaxSequence)
                {
                    // nothing to do (eg,  kCBLStatusNotModified)
                    string msg = string.Format("lastSequence (%d) == dbMaxSequence (%d), nothing to do"
                                               , lastSequence, dbMaxSequence);
                    Log.D(Database.Tag, msg);
                    result.SetCode(Status.Ok);
                    return;
                }
                // First remove obsolete emitted results from the 'maps' table:
                long sequence = lastSequence;
                if (lastSequence < 0)
                {
                    string msg = string.Format("lastSequence < 0 (%s)", lastSequence);
                    throw new CouchbaseLiteException(msg, new Status(Status.InternalServerError));
                }
                if (lastSequence == 0)
                {
                    // If the lastSequence has been reset to 0, make sure to remove
                    // any leftover rows:
                    string[] whereArgs = new string[] { Sharpen.Extensions.ToString(GetViewId()) };
                    database.GetDatabase().Delete("maps", "view_id=?", whereArgs);
                }
                else
                {
                    // Delete all obsolete map results (ones from since-replaced
                    // revisions):
                    string[] args = new string[] { Sharpen.Extensions.ToString(GetViewId()), System.Convert.ToString
                                                       (lastSequence), System.Convert.ToString(lastSequence) };
                    database.GetDatabase().ExecSQL("DELETE FROM maps WHERE view_id=? AND sequence IN ("
                                                   + "SELECT parent FROM revs WHERE sequence>? " + "AND parent>0 AND parent<=?)",
                                                   args);
                }
                int deleted = 0;
                cursor = database.GetDatabase().RawQuery("SELECT changes()", null);
                cursor.MoveToNext();
                deleted = cursor.GetInt(0);
                cursor.Close();
                // This is the emit() block, which gets called from within the
                // user-defined map() block
                // that's called down below.
                AbstractTouchMapEmitBlock emitBlock = new _AbstractTouchMapEmitBlock_446(this);
                // find a better way to propagate this back
                // Now scan every revision added since the last time the view was
                // indexed:
                string[] selectArgs = new string[] { System.Convert.ToString(lastSequence) };
                cursor = database.GetDatabase().RawQuery("SELECT revs.doc_id, sequence, docid, revid, json FROM revs, docs "
                                                         + "WHERE sequence>? AND current!=0 AND deleted=0 " + "AND revs.doc_id = docs.doc_id "
                                                         + "ORDER BY revs.doc_id, revid DESC", selectArgs);
                cursor.MoveToNext();
                long lastDocID = 0;
                while (!cursor.IsAfterLast())
                {
                    long docID = cursor.GetLong(0);
                    if (docID != lastDocID)
                    {
                        // Only look at the first-iterated revision of any document,
                        // because this is the
                        // one with the highest revid, hence the "winning" revision
                        // of a conflict.
                        lastDocID = docID;
                        // Reconstitute the document as a dictionary:
                        sequence = cursor.GetLong(1);
                        string docId = cursor.GetString(2);
                        if (docId.StartsWith("_design/"))
                        {
                            // design docs don't get indexed!
                            cursor.MoveToNext();
                            continue;
                        }
                        string revId = cursor.GetString(3);
                        byte[] json  = cursor.GetBlob(4);
                        IDictionary <string, object> properties = database.DocumentPropertiesFromJSON(json
                                                                                                      , docId, revId, false, sequence, EnumSet.NoneOf <Database.TDContentOptions>());
                        if (properties != null)
                        {
                            // Call the user-defined map() to emit new key/value
                            // pairs from this revision:
                            Log.V(Database.Tag, "  call map for sequence=" + System.Convert.ToString(sequence
                                                                                                     ));
                            emitBlock.SetSequence(sequence);
                            mapBlock.Map(properties, emitBlock);
                        }
                    }
                    cursor.MoveToNext();
                }
                // Finally, record the last revision sequence number that was
                // indexed:
                ContentValues updateValues = new ContentValues();
                updateValues.Put("lastSequence", dbMaxSequence);
                string[] whereArgs_1 = new string[] { Sharpen.Extensions.ToString(GetViewId()) };
                database.GetDatabase().Update("views", updateValues, "view_id=?", whereArgs_1);
                // FIXME actually count number added :)
                Log.V(Database.Tag, "...Finished re-indexing view " + name + " up to sequence " +
                      System.Convert.ToString(dbMaxSequence) + " (deleted " + deleted + " added " + "?"
                      + ")");
                result.SetCode(Status.Ok);
            }
            catch (SQLException e)
            {
                throw new CouchbaseLiteException(e, new Status(Status.DbError));
            }
            finally
            {
                if (cursor != null)
                {
                    cursor.Close();
                }
                if (!result.IsSuccessful())
                {
                    Log.W(Database.Tag, "Failed to rebuild view " + name + ": " + result.GetCode());
                }
                if (database != null)
                {
                    database.EndTransaction(result.IsSuccessful());
                }
            }
        }
Esempio n. 19
0
 internal IList<QueryRow> ReducedQuery(Cursor cursor, bool group, int groupLevel)
 {
     IList<object> keysToReduce = null;
     IList<object> valuesToReduce = null;
     object lastKey = null;
     if (GetReduce() != null)
     {
         keysToReduce = new AList<object>(ReduceBatchSize);
         valuesToReduce = new AList<object>(ReduceBatchSize);
     }
     IList<QueryRow> rows = new AList<QueryRow>();
     cursor.MoveToNext();
     while (!cursor.IsAfterLast())
     {
         JsonDocument keyDoc = new JsonDocument(cursor.GetBlob(0));
         JsonDocument valueDoc = new JsonDocument(cursor.GetBlob(1));
         System.Diagnostics.Debug.Assert((keyDoc != null));
         object keyObject = keyDoc.JsonObject();
         if (group && !GroupTogether(keyObject, lastKey, groupLevel))
         {
             if (lastKey != null)
             {
                 // This pair starts a new group, so reduce & record the last one:
                 object reduced = (reduceBlock != null) ? reduceBlock.Reduce(keysToReduce, valuesToReduce
                     , false) : null;
                 object key = GroupKey(lastKey, groupLevel);
                 QueryRow row = new QueryRow(null, 0, key, reduced, null);
                 row.SetDatabase(database);
                 rows.AddItem(row);
                 keysToReduce.Clear();
                 valuesToReduce.Clear();
             }
             lastKey = keyObject;
         }
         keysToReduce.AddItem(keyObject);
         valuesToReduce.AddItem(valueDoc.JsonObject());
         cursor.MoveToNext();
     }
     if (keysToReduce.Count > 0)
     {
         // Finish the last group (or the entire list, if no grouping):
         object key = group ? GroupKey(lastKey, groupLevel) : null;
         object reduced = (reduceBlock != null) ? reduceBlock.Reduce(keysToReduce, valuesToReduce
             , false) : null;
         QueryRow row = new QueryRow(null, 0, key, reduced, null);
         row.SetDatabase(database);
         rows.AddItem(row);
     }
     return rows;
 }