Index: System.Data.SQLite/SQLiteSession.cs ================================================================== --- System.Data.SQLite/SQLiteSession.cs +++ System.Data.SQLite/SQLiteSession.cs @@ -13,11 +13,10 @@ #endif using System.IO; using System.Globalization; using System.Runtime.InteropServices; -using System.Threading; namespace System.Data.SQLite { #region Session Extension Enumerations public enum SQLiteChangeSetConflictType @@ -708,18 +707,25 @@ #region SQLiteStreamChangeSetIterator Class internal sealed class SQLiteStreamChangeSetIterator : SQLiteChangeSetIterator { + #region Private Data + private SQLiteStreamAdapter streamAdapter; + #endregion + + /////////////////////////////////////////////////////////////////////// + #region Private Constructors private SQLiteStreamChangeSetIterator( + SQLiteStreamAdapter streamAdapter, IntPtr iterator, bool ownHandle ) : base(iterator, ownHandle) { - // do nothing. + this.streamAdapter = streamAdapter; } #endregion /////////////////////////////////////////////////////////////////////// @@ -730,23 +736,29 @@ ) { if (stream == null) throw new ArgumentNullException("stream"); + SQLiteStreamAdapter streamAdapter = null; SQLiteStreamChangeSetIterator result = null; IntPtr iterator = IntPtr.Zero; try { + streamAdapter = new SQLiteStreamAdapter(stream, flags); + SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3changeset_start_strm( - ref iterator, new SQLiteStreamAdapter(stream, flags).xInput, - IntPtr.Zero); + ref iterator, streamAdapter.GetInputDelegate(), IntPtr.Zero); if (rc != SQLiteErrorCode.Ok) - throw new SQLiteException(rc, "sqlite3changeset_start_strm"); + { + throw new SQLiteException( + rc, "sqlite3changeset_start_strm"); + } - result = new SQLiteStreamChangeSetIterator(iterator, true); + result = new SQLiteStreamChangeSetIterator( + streamAdapter, iterator, true); } finally { if (result == null) { @@ -755,10 +767,16 @@ UnsafeNativeMethods.sqlite3changeset_finalize( iterator); iterator = IntPtr.Zero; } + + if (streamAdapter != null) + { + streamAdapter.Dispose(); + streamAdapter = null; + } } } return result; } @@ -819,10 +837,15 @@ internal sealed class SQLiteStreamAdapter : IDisposable { #region Private Data private Stream stream; /* EXEMPT: NOT OWNED */ private SQLiteConnectionFlags flags; + + /////////////////////////////////////////////////////////////////////// + + private UnsafeNativeMethods.xSessionInput xInput; + private UnsafeNativeMethods.xSessionOutput xOutput; #endregion /////////////////////////////////////////////////////////////////////// #region Public Constructors @@ -845,33 +868,59 @@ } #endregion /////////////////////////////////////////////////////////////////////// + #region Public Methods + public UnsafeNativeMethods.xSessionInput GetInputDelegate() + { + CheckDisposed(); + + if (xInput == null) + xInput = new UnsafeNativeMethods.xSessionInput(Input); + + return xInput; + } + + /////////////////////////////////////////////////////////////////////// + + public UnsafeNativeMethods.xSessionOutput GetOutputDelegate() + { + CheckDisposed(); + + if (xOutput == null) + xOutput = new UnsafeNativeMethods.xSessionOutput(Output); + + return xOutput; + } + #endregion + + /////////////////////////////////////////////////////////////////////// + #region Native Callback Methods - internal SQLiteErrorCode xInput( + private SQLiteErrorCode Input( IntPtr context, IntPtr pData, ref int nData ) { try { - Stream localStream = Interlocked.CompareExchange( - ref stream, null, null); + Stream localStream = stream; if (localStream == null) return SQLiteErrorCode.Misuse; if (nData > 0) { byte[] bytes = new byte[nData]; + int nRead = localStream.Read(bytes, 0, nData); - nData = localStream.Read(bytes, 0, nData); + if ((nRead > 0) && (pData != IntPtr.Zero)) + Marshal.Copy(bytes, 0, pData, nRead); - if (nData > 0) - Marshal.Copy(bytes, 0, pData, nData); + nData = nRead; } return SQLiteErrorCode.Ok; } catch (Exception e) @@ -883,11 +932,11 @@ SQLiteLog.LogMessage( SQLiteBase.COR_E_EXCEPTION, HelperMethods.StringFormat( CultureInfo.CurrentCulture, UnsafeNativeMethods.ExceptionMessageFormat, - "xInput", e)); /* throw */ + "xSessionInput", e)); /* throw */ } } catch { // do nothing. @@ -897,29 +946,30 @@ return SQLiteErrorCode.IoErr_Read; } /////////////////////////////////////////////////////////////////////// - internal SQLiteErrorCode xOutput( + private SQLiteErrorCode Output( IntPtr context, IntPtr pData, int nData ) { try { - Stream localStream = Interlocked.CompareExchange( - ref stream, null, null); + Stream localStream = stream; if (localStream == null) return SQLiteErrorCode.Misuse; if (nData > 0) { byte[] bytes = new byte[nData]; - Marshal.Copy(pData, bytes, 0, nData); + if (pData != IntPtr.Zero) + Marshal.Copy(pData, bytes, 0, nData); + localStream.Write(bytes, 0, nData); } localStream.Flush(); @@ -934,11 +984,11 @@ SQLiteLog.LogMessage( SQLiteBase.COR_E_EXCEPTION, HelperMethods.StringFormat( CultureInfo.CurrentCulture, UnsafeNativeMethods.ExceptionMessageFormat, - "xOutput", e)); /* throw */ + "xSessionOutput", e)); /* throw */ } } catch { // do nothing. @@ -978,23 +1028,32 @@ private /* protected virtual */ void Dispose(bool disposing) { try { - //if (!disposed) - //{ - // if (disposing) - // { - // //////////////////////////////////// - // // dispose managed resources here... - // //////////////////////////////////// - // } - - // ////////////////////////////////////// - // // release unmanaged resources here... - // ////////////////////////////////////// - //} + if (!disposed) + { + if (disposing) + { + //////////////////////////////////// + // dispose managed resources here... + //////////////////////////////////// + + if (xInput != null) + xInput = null; + + if (xOutput != null) + xOutput = null; + + if (stream != null) + stream = null; /* NOT OWNED */ + } + + ////////////////////////////////////// + // release unmanaged resources here... + ////////////////////////////////////// + } } finally { // // NOTE: Everything should be fully disposed at this point. @@ -1015,14 +1074,164 @@ } #endregion /////////////////////////////////////////////////////////////////////////// + #region SQLiteSessionStreamManager Class + internal sealed class SQLiteSessionStreamManager : IDisposable + { + #region Private Data + private Dictionary streamAdapters; + private SQLiteConnectionFlags flags; + #endregion + + /////////////////////////////////////////////////////////////////////// + + #region Public Constructors + public SQLiteSessionStreamManager( + SQLiteConnectionFlags flags + ) + { + this.flags = flags; + + InitializeStreamAdapters(); + } + #endregion + + /////////////////////////////////////////////////////////////////////// + + #region Private Methods + private void InitializeStreamAdapters() + { + if (streamAdapters != null) + return; + + streamAdapters = new Dictionary(); + } + + /////////////////////////////////////////////////////////////////////// + + private void DisposeStreamAdapters() + { + if (streamAdapters == null) + return; + + foreach (KeyValuePair pair + in streamAdapters) + { + SQLiteStreamAdapter streamAdapter = pair.Value; + + if (streamAdapter == null) + continue; + + streamAdapter.Dispose(); + } + + streamAdapters.Clear(); + streamAdapters = null; + } + #endregion + + /////////////////////////////////////////////////////////////////////// + + #region Public Methods + public SQLiteStreamAdapter GetAdapter( + Stream stream + ) + { + CheckDisposed(); + + if (stream == null) + return null; + + SQLiteStreamAdapter streamAdapter; + + if (streamAdapters.TryGetValue(stream, out streamAdapter)) + return streamAdapter; + + streamAdapter = new SQLiteStreamAdapter(stream, flags); + streamAdapters.Add(stream, streamAdapter); + + return streamAdapter; + } + #endregion + + /////////////////////////////////////////////////////////////////////// + + #region IDisposable Members + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + #endregion + + /////////////////////////////////////////////////////////////////////// + + #region IDisposable "Pattern" Members + private bool disposed; + private void CheckDisposed() /* throw */ + { +#if THROW_ON_DISPOSED + if (disposed) + { + throw new ObjectDisposedException( + typeof(SQLiteSessionStreamManager).Name); + } +#endif + } + + /////////////////////////////////////////////////////////////////////// + + private /* protected virtual */ void Dispose(bool disposing) + { + try + { + if (!disposed) + { + if (disposing) + { + //////////////////////////////////// + // dispose managed resources here... + //////////////////////////////////// + + DisposeStreamAdapters(); + } + + ////////////////////////////////////// + // release unmanaged resources here... + ////////////////////////////////////// + } + } + finally + { + // + // NOTE: Everything should be fully disposed at this point. + // + disposed = true; + } + } + #endregion + + /////////////////////////////////////////////////////////////////////// + + #region Destructor + ~SQLiteSessionStreamManager() + { + Dispose(false); + } + #endregion + } + #endregion + + /////////////////////////////////////////////////////////////////////////// + #region SQLiteChangeGroup Class internal sealed class SQLiteChangeGroup : ISQLiteChangeGroup { #region Private Data + private SQLiteSessionStreamManager streamManager; private SQLiteConnectionFlags flags; /////////////////////////////////////////////////////////////////////// private IntPtr changeGroup; @@ -1035,11 +1244,11 @@ SQLiteConnectionFlags flags ) { this.flags = flags; - Initialize(); + InitializeHandle(); } #endregion /////////////////////////////////////////////////////////////////////// @@ -1050,11 +1259,11 @@ throw new InvalidOperationException("change group not open"); } /////////////////////////////////////////////////////////////////////// - private void Initialize() + private void InitializeHandle() { if (changeGroup != IntPtr.Zero) return; SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3changegroup_new( @@ -1061,10 +1270,31 @@ ref changeGroup); if (rc != SQLiteErrorCode.Ok) throw new SQLiteException(rc, "sqlite3changegroup_new"); } + + /////////////////////////////////////////////////////////////////////// + + private void InitializeStreamManager() + { + if (streamManager != null) + return; + + streamManager = new SQLiteSessionStreamManager(flags); + } + + /////////////////////////////////////////////////////////////////////// + + private SQLiteStreamAdapter GetStreamAdapter( + Stream stream + ) + { + InitializeStreamManager(); + + return streamManager.GetAdapter(stream); + } #endregion /////////////////////////////////////////////////////////////////////// #region ISQLiteChangeGroup Members @@ -1110,14 +1340,21 @@ CheckDisposed(); CheckHandle(); if (stream == null) throw new ArgumentNullException("stream"); + + SQLiteStreamAdapter streamAdapter = GetStreamAdapter(stream); + + if (streamAdapter == null) + { + throw new SQLiteException( + "could not get or create adapter for input stream"); + } SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3changegroup_add_strm( - changeGroup, new SQLiteStreamAdapter(stream, flags).xInput, - IntPtr.Zero); + changeGroup, streamAdapter.GetInputDelegate(), IntPtr.Zero); if (rc != SQLiteErrorCode.Ok) throw new SQLiteException(rc, "sqlite3changegroup_add_strm"); } @@ -1165,14 +1402,21 @@ CheckDisposed(); CheckHandle(); if (stream == null) throw new ArgumentNullException("stream"); + + SQLiteStreamAdapter streamAdapter = GetStreamAdapter(stream); + + if (streamAdapter == null) + { + throw new SQLiteException( + "could not get or create adapter for output stream"); + } SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3changegroup_output_strm( - changeGroup, new SQLiteStreamAdapter(stream, flags).xOutput, - IntPtr.Zero); + changeGroup, streamAdapter.GetOutputDelegate(), IntPtr.Zero); if (rc != SQLiteErrorCode.Ok) throw new SQLiteException(rc, "sqlite3changegroup_output_strm"); } #endregion @@ -1214,22 +1458,28 @@ { //////////////////////////////////// // dispose managed resources here... //////////////////////////////////// - if (changeGroup != IntPtr.Zero) + if (streamManager != null) { - UnsafeNativeMethods.sqlite3changegroup_delete( - changeGroup); - - changeGroup = IntPtr.Zero; + streamManager.Dispose(); + streamManager = null; } } ////////////////////////////////////// // release unmanaged resources here... ////////////////////////////////////// + + if (changeGroup != IntPtr.Zero) + { + UnsafeNativeMethods.sqlite3changegroup_delete( + changeGroup); + + changeGroup = IntPtr.Zero; + } } } finally { // @@ -1255,18 +1505,20 @@ #region SQLiteSession Class internal sealed class SQLiteSession : SQLiteConnectionLock, ISQLiteSession { #region Private Data + private SQLiteSessionStreamManager streamManager; private string databaseName; /////////////////////////////////////////////////////////////////////// private IntPtr session; /////////////////////////////////////////////////////////////////////// + private UnsafeNativeMethods.xSessionFilter xFilter; private SessionTableFilterCallback tableFilterCallback; private object tableFilterClientData; #endregion /////////////////////////////////////////////////////////////////////// @@ -1279,11 +1531,11 @@ ) : base(handle, flags) { this.databaseName = databaseName; - Initialize(); + InitializeHandle(); } #endregion /////////////////////////////////////////////////////////////////////// @@ -1294,11 +1546,11 @@ throw new InvalidOperationException("session is not open"); } /////////////////////////////////////////////////////////////////////// - private void Initialize() + private void InitializeHandle() { if (session != IntPtr.Zero) return; SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3session_create( @@ -1314,21 +1566,53 @@ private UnsafeNativeMethods.xSessionFilter ApplyTableFilter( SessionTableFilterCallback callback, /* in: NULL OK */ object clientData /* in: NULL OK */ ) { - this.tableFilterCallback = callback; - this.tableFilterClientData = clientData; + tableFilterCallback = callback; + tableFilterClientData = clientData; - return (callback != null) ? - xFilter : (UnsafeNativeMethods.xSessionFilter)null; + if (callback == null) + { + if (xFilter != null) + xFilter = null; + + return null; + } + + if (xFilter == null) + xFilter = new UnsafeNativeMethods.xSessionFilter(Filter); + + return xFilter; } + + /////////////////////////////////////////////////////////////////////// + + private void InitializeStreamManager() + { + if (streamManager != null) + return; + + streamManager = new SQLiteSessionStreamManager(GetFlags()); + } + + /////////////////////////////////////////////////////////////////////// + + private SQLiteStreamAdapter GetStreamAdapter( + Stream stream + ) + { + InitializeStreamManager(); + + return streamManager.GetAdapter(stream); + } + #endregion /////////////////////////////////////////////////////////////////////// #region Native Callback Methods - private int xFilter( + private int Filter( IntPtr context, /* NOT USED */ IntPtr pTblName ) { try @@ -1345,11 +1629,11 @@ SQLiteLog.LogMessage( /* throw */ SQLiteBase.COR_E_EXCEPTION, HelperMethods.StringFormat( CultureInfo.CurrentCulture, UnsafeNativeMethods.ExceptionMessageFormat, - "xFilter", e)); + "xSessionFilter", e)); } } catch { // do nothing. @@ -1356,11 +1640,10 @@ } } return 0; } - #endregion #endregion /////////////////////////////////////////////////////////////////////// #region ISQLiteSession Members @@ -1505,15 +1788,20 @@ CheckHandle(); if (stream == null) throw new ArgumentNullException("stream"); - SQLiteConnectionFlags flags = GetFlags(); + SQLiteStreamAdapter streamAdapter = GetStreamAdapter(stream); + + if (streamAdapter == null) + { + throw new SQLiteException( + "could not get or create adapter for output stream"); + } SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3session_changeset_strm( - session, new SQLiteStreamAdapter(stream, flags).xOutput, - IntPtr.Zero); + session, streamAdapter.GetOutputDelegate(), IntPtr.Zero); if (rc != SQLiteErrorCode.Ok) throw new SQLiteException(rc, "sqlite3session_changeset_strm"); } @@ -1560,15 +1848,20 @@ CheckHandle(); if (stream == null) throw new ArgumentNullException("stream"); - SQLiteConnectionFlags flags = GetFlags(); + SQLiteStreamAdapter streamAdapter = GetStreamAdapter(stream); + + if (streamAdapter == null) + { + throw new SQLiteException( + "could not get or create adapter for output stream"); + } SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3session_patchset_strm( - session, new SQLiteStreamAdapter(stream, flags).xOutput, - IntPtr.Zero); + session, streamAdapter.GetOutputDelegate(), IntPtr.Zero); if (rc != SQLiteErrorCode.Ok) throw new SQLiteException(rc, "sqlite3session_patchset_strm"); } @@ -1645,16 +1938,25 @@ { try { if (!disposed) { - //if (disposing) - //{ - // //////////////////////////////////// - // // dispose managed resources here... - // //////////////////////////////////// - //} + if (disposing) + { + //////////////////////////////////// + // dispose managed resources here... + //////////////////////////////////// + + if (xFilter != null) + xFilter = null; + + if (streamManager != null) + { + streamManager.Dispose(); + streamManager = null; + } + } ////////////////////////////////////// // release unmanaged resources here... ////////////////////////////////////// @@ -1741,11 +2043,11 @@ SQLiteLog.LogMessage( /* throw */ SQLiteBase.COR_E_EXCEPTION, HelperMethods.StringFormat( CultureInfo.CurrentCulture, UnsafeNativeMethods.ExceptionMessageFormat, - "xFilter", e)); + "xSessionFilter", e)); } } catch { // do nothing. @@ -1797,11 +2099,11 @@ SQLiteLog.LogMessage( /* throw */ SQLiteBase.COR_E_EXCEPTION, HelperMethods.StringFormat( CultureInfo.CurrentCulture, UnsafeNativeMethods.ExceptionMessageFormat, - "xConflict", e)); + "xSessionConflict", e)); } } catch { // do nothing. @@ -2144,10 +2446,12 @@ #region SQLiteStreamChangeSet Class internal sealed class SQLiteStreamChangeSet : SQLiteChangeSetBase, ISQLiteChangeSet { #region Private Data + private SQLiteStreamAdapter inputStreamAdapter; + private SQLiteStreamAdapter outputStreamAdapter; private Stream inputStream; private Stream outputStream; #endregion /////////////////////////////////////////////////////////////////////// @@ -2174,10 +2478,16 @@ if (inputStream == null) { throw new InvalidOperationException( "input stream unavailable"); } + + if (inputStreamAdapter == null) + { + inputStreamAdapter = new SQLiteStreamAdapter( + inputStream, GetFlags()); + } } /////////////////////////////////////////////////////////////////////// private void CheckOutputStream() @@ -2185,10 +2495,16 @@ if (outputStream == null) { throw new InvalidOperationException( "output stream unavailable"); } + + if (outputStreamAdapter == null) + { + outputStreamAdapter = new SQLiteStreamAdapter( + outputStream, GetFlags()); + } } #endregion /////////////////////////////////////////////////////////////////////// @@ -2197,15 +2513,13 @@ { CheckDisposed(); CheckInputStream(); CheckOutputStream(); - SQLiteConnectionFlags flags = GetFlags(); - SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3changeset_invert_strm( - new SQLiteStreamAdapter(inputStream, flags).xInput, IntPtr.Zero, - new SQLiteStreamAdapter(outputStream, flags).xOutput, IntPtr.Zero); + inputStreamAdapter.GetInputDelegate(), IntPtr.Zero, + outputStreamAdapter.GetOutputDelegate(), IntPtr.Zero); if (rc != SQLiteErrorCode.Ok) throw new SQLiteException(rc, "sqlite3changeset_invert_strm"); return null; @@ -2230,18 +2544,15 @@ "not a stream based change set", "changeSet"); } streamChangeSet.CheckInputStream(); - SQLiteConnectionFlags otherFlags = streamChangeSet.GetFlags(); - SQLiteConnectionFlags flags = GetFlags(); - SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3changeset_concat_strm( - new SQLiteStreamAdapter(inputStream, flags).xInput, - IntPtr.Zero, new SQLiteStreamAdapter(streamChangeSet.inputStream, - otherFlags).xInput, IntPtr.Zero, new SQLiteStreamAdapter( - outputStream, flags).xOutput, IntPtr.Zero); + inputStreamAdapter.GetInputDelegate(), IntPtr.Zero, + streamChangeSet.inputStreamAdapter.GetInputDelegate(), + IntPtr.Zero, outputStreamAdapter.GetOutputDelegate(), + IntPtr.Zero); if (rc != SQLiteErrorCode.Ok) throw new SQLiteException(rc, "sqlite3changeset_concat_strm"); return null; @@ -2277,15 +2588,13 @@ tableFilterCallback, clientData); UnsafeNativeMethods.xSessionConflict xConflict = GetDelegate( conflictCallback, clientData); - SQLiteConnectionFlags flags = GetFlags(); - SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3changeset_apply_strm( - GetIntPtr(), new SQLiteStreamAdapter(inputStream, flags).xInput, - IntPtr.Zero, xFilter, xConflict, IntPtr.Zero); + GetIntPtr(), inputStreamAdapter.GetInputDelegate(), IntPtr.Zero, + xFilter, xConflict, IntPtr.Zero); if (rc != SQLiteErrorCode.Ok) throw new SQLiteException(rc, "sqlite3changeset_apply_strm"); } #endregion @@ -2293,12 +2602,12 @@ /////////////////////////////////////////////////////////////////////// #region IEnumerable Members public IEnumerator GetEnumerator() { - SQLiteConnectionFlags flags = GetFlags(); - return new SQLiteStreamChangeSetEnumerator(inputStream, flags); + return new SQLiteStreamChangeSetEnumerator( + inputStream, GetFlags()); } #endregion /////////////////////////////////////////////////////////////////////// Index: Tests/session.eagle ================================================================== --- Tests/session.eagle +++ Tests/session.eagle @@ -88,14 +88,29 @@ } } ############################################################################### -proc createMemoryChangeSetForSession { session } { +proc createMemoryChangeSetForConnection { connection rawData } { + if {[isObjectHandle $connection] && $connection ne "null"} then { + return [$connection -alias CreateChangeSet $rawData] + } + + return null +} + +############################################################################### + +proc createMemoryChangeSetForSession { session {patch false} } { if {[isObjectHandle $session] && $session ne "null"} then { set byteArray null - $session -alias CreateChangeSet byteArray + + if {$patch} then { + $session -alias CreatePatchSet byteArray + } else { + $session -alias CreateChangeSet byteArray + } set rawData [createByteArray [arrayToList byteArray]] object removeref $rawData return $rawData @@ -152,16 +167,21 @@ return false } ############################################################################### -proc writeStreamChangeSetForSession { session fileName } { +proc writeStreamChangeSetForSession { session fileName {patch false} } { if {[isObjectHandle $session] && $session ne "null"} then { set stream [object create -alias \ System.IO.FileStream $fileName Create Write] - $session -alias CreateChangeSet $stream + if {$patch} then { + $session -alias CreatePatchSet $stream + } else { + $session -alias CreateChangeSet $stream + } + $stream Flush; $stream Close return true } @@ -173,12 +193,12 @@ proc changeSetFileToString { connection fileName includeValues } { set result [list] if {[isObjectHandle $connection] && $connection ne "null"} then { if {[openStreamChangeSetForConnection \ - $connection $fileName "" changeSet]} then { - return [changeSetToString $changeSet(changeSet) $includeValues] + $connection $fileName "" state]} then { + return [changeSetToString $state(changeSet) $includeValues] } } return $result } @@ -511,11 +531,15 @@ makeSomeChanges $db t1 [list insert update delete] set rawData [createMemoryChangeSetForSession $session] object removeref $rawData - set changeSet(1) [$connection -alias CreateChangeSet $rawData] + set changeSet(1) \ + [createMemoryChangeSetForConnection $connection $rawData] + + object removeref $changeSet(1) + set changeSet(2) [$changeSet(1) -alias Invert] list [changeSetToString $changeSet(2) true] } -cleanup { cleanupSomeText @@ -644,11 +668,15 @@ lappend result IsEmpty [$session IsEmpty] set rawData [createMemoryChangeSetForSession $session] object removeref $rawData - set changeSet(1) [$connection -alias CreateChangeSet $rawData] + set changeSet(1) \ + [createMemoryChangeSetForConnection $connection $rawData] + + object removeref $changeSet(1) + lappend result [changeSetToString $changeSet(1) false] } -cleanup { cleanupSomeText unset -nocomplain result changeSet rawData byteArray session @@ -701,11 +729,15 @@ lappend result IsEmpty [$session IsEmpty] set rawData [createMemoryChangeSetForSession $session] object removeref $rawData - set changeSet(1) [$connection -alias CreateChangeSet $rawData] + set changeSet(1) \ + [createMemoryChangeSetForConnection $connection $rawData] + + object removeref $changeSet(1) + lappend result [changeSetToString $changeSet(1) false] } -cleanup { cleanupSomeText unset -nocomplain result changeSet rawData byteArray session @@ -819,12 +851,20 @@ set rawData(2) [captureChangeSetRawData $connection main null { makeSomeChanges $db t1 [list insert] }]; object removeref $rawData(2) - set changeSet(1) [$connection -alias CreateChangeSet $rawData(1)] - set changeSet(2) [$connection -alias CreateChangeSet $rawData(2)] + set changeSet(1) \ + [createMemoryChangeSetForConnection $connection $rawData(1)] + + object removeref $changeSet(1) + + set changeSet(2) \ + [createMemoryChangeSetForConnection $connection $rawData(2)] + + object removeref $changeSet(2) + set changeSet(3) [$changeSet(1) -alias CombineWith $changeSet(2)] $changeSet(3) -marshalflags +DynamicCallback \ Apply conflictCallback null @@ -1010,13 +1050,14 @@ rename changeSetFileToString "" rename writeStreamChangeSetForSession "" rename openStreamChangeSetForConnection "" rename writeRawDataToFile "" rename createMemoryChangeSetForSession "" +rename createMemoryChangeSetForConnection "" rename forDisplay "" rename cleanupSomeText "" rename getSomeText "" ############################################################################### runSQLiteTestEpilogue runTestEpilogue