Пример #1
0
        /// <summary>
        /// returns a handle used to iterate over all changes to a session since tracking began
        /// See https://sqlite.org/session/sqlite3session_changeset.html
        /// </summary>
        /// <param name="session">open session handle currently tracking changes</param>
        /// <param name="changeSet">buffer struct holding the returned change set</param>
        /// <returns></returns>
        public static Result GenerateChangeSet(IntPtr session, out SQLiteChangeSet changeSet)
        {
            // default to no ChangeSet (returned if any errors)
            changeSet = new SQLiteChangeSet(0, new Sqlite3ChangesetBuffer(IntPtr.Zero));

            if (session == IntPtr.Zero)
            {
                return(Result.Misuse);
            }

            try
            {
                var result = GenerateChangeSet(session, out int size, out Sqlite3ChangesetBuffer buffer);
                if (result == Result.OK)
                {
                    changeSet = new SQLiteChangeSet(size, buffer);
                }
                return(result);
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e);
                return(Result.Internal);
            }
        }
Пример #2
0
        /// <summary>
        /// Given a changeset, prepares the inverse such that applying In then Out change sets
        /// will give the equivalent of no changes to the database.
        /// See https://sqlite.org/session/sqlite3changeset_invert.html
        /// </summary>
        /// <param name="changeSetIn">existing change set</param>
        /// <param name="changeSetOut">inverse of In change set</param>
        /// <returns>result status of inversion; Result.OK if successful, otherwise corresponding error code</returns>
        public static Result InvertChangeSet(SQLiteChangeSet changeSetIn, out SQLiteChangeSet changeSetOut)
        {
            if (changeSetIn.buffer.IsInvalid)
            {
                changeSetOut = new SQLiteChangeSet(0, new Sqlite3ChangesetBuffer(IntPtr.Zero));
                return(Result.Misuse);
            }

            var result = InvertChangeSet(changeSetIn.size, changeSetIn.buffer, out int size, out Sqlite3ChangesetBuffer buffer);

            changeSetOut = new SQLiteChangeSet(size, buffer);
            return(result);
        }
Пример #3
0
        /// <summary>
        /// Applies a given change set to provided db
        /// with possibility to limit which tables are changed via xFilter delegate,
        /// and custom conflict resolution via xConflict delegate
        /// See https://sqlite.org/session/sqlite3changeset_apply.html
        /// </summary>
        /// <param name="db">which db ("main" only) to apply changes to</param>
        /// <param name="changeSet">change set to apply to db</param>
        /// <param name="xFilter">use null to not filter, else delegate to limit tables changes applied to</param>
        /// <param name="xConflict">use null to ignore conflicts, else delegate to handle conflicts</param>
        /// <param name="ctx">context passed as first argument to xFilter and xConflict delegates</param>
        /// <returns></returns>
        public static Result ChangeSetApply(SQLite.SQLiteConnection db, SQLiteChangeSet changeSet, FilterCallback xFilter, ConflictCallback xConflict, object ctx)
        {
            Sqlite3DatabaseHandle dbHandle = db?.Handle ?? IntPtr.Zero;

            if (dbHandle == IntPtr.Zero)
            {
                return(Result.Misuse);
            }

            if (xConflict == null)
            {
                xConflict = new ConflictCallback(CallbackIgnoreConflicts);
            }

            // pinning not needed since just passing back thru; see https://blogs.msdn.microsoft.com/jmstall/2006/10/09/gchandle-tointptr-vs-gchandle-addrofpinnedobject/
            // Warning: if conflict handler is in unmanaged code then ctx should be pinned in Alloc and use AddrOfPinnedObject instead of ToIntPtr
            GCHandle gch    = GCHandle.Alloc(ctx);                                  // ok if ctx is null; pinning is unneeded since not kept past ChangeSetApply call
            IntPtr   pCtx   = (ctx == null) ? IntPtr.Zero : GCHandle.ToIntPtr(gch); // we don't pass GCHandle wrapper if null, instead pass NULL
            var      result = ChangeSetApply(dbHandle, changeSet.size, changeSet.buffer, xFilter, xConflict, pCtx);

            gch.Free();

            return(result);
        }
Пример #4
0
 public static Result ApplySessionChangeSet(this SQLite.SQLiteConnection db, SQLiteChangeSet changeSet, FilterCallback xFilter, ConflictCallback xConflict, object ctx)
 {
     return(ChangeSetApply(db, changeSet, xFilter, xConflict, ctx));
 }
Пример #5
0
 /// <summary>
 /// Obtain a handle to allow iterating through changes in a change set
 /// See https://sqlite.org/session/sqlite3changeset_start.html
 /// </summary>
 /// <param name="iter">handle returned for iteratoring changes</param>
 /// <param name="changeSet">the change set to iterate through</param>
 /// <returns></returns>
 public static Result ChangeSetStart(out Sqlite3ChangesetIterator iter, SQLiteChangeSet changeSet)
 {
     return(ChangeSetStart(out iter, changeSet.size, changeSet.buffer));
 }