/// <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); } }
/// <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); }
/// <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); }
public static Result ApplySessionChangeSet(this SQLite.SQLiteConnection db, SQLiteChangeSet changeSet, FilterCallback xFilter, ConflictCallback xConflict, object ctx) { return(ChangeSetApply(db, changeSet, xFilter, xConflict, ctx)); }
/// <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)); }