System.Data.SQLite
Check-in [489188361e]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Prevent delegates used for native callbacks from being disposed while in use.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | sessionStreamManager
Files: files | file ages | folders
SHA1: 489188361e5126829141bd14b23f1e139aac57b5
User & Date: mistachkin 2017-10-13 17:11:54
Context
2017-10-13
17:46
Corrections to tests. Closed-Leaf check-in: acbeea6018 user: mistachkin tags: sessionStreamManager
17:11
Prevent delegates used for native callbacks from being disposed while in use. check-in: 489188361e user: mistachkin tags: sessionStreamManager
16:47
Further adjustments. check-in: fc3f62b4be user: mistachkin tags: sessionStreamManager
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to System.Data.SQLite/SQLiteSession.cs.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
...
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
...
836
837
838
839
840
841
842





843
844
845
846
847
848
849
...
862
863
864
865
866
867
868


























869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
...
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
...
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
....
1009
1010
1011
1012
1013
1014
1015









1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
....
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
....
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
....
1481
1482
1483
1484
1485
1486
1487

1488
1489
1490
1491
1492
1493
1494
....
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542








1543


1544
1545
1546
1547
1548
1549
1550
....
1559
1560
1561
1562
1563
1564
1565

1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
....
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
....
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
....
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
....
1899
1900
1901
1902
1903
1904
1905



1906
1907
1908
1909
1910
1911
1912
....
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
....
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
....
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
....
2498
2499
2500
2501
2502
2503
2504
2505
2506

2507
2508
2509
2510
2511
2512
2513
2514
....
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
#if DEBUG
using System.Diagnostics;
#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
    {
        Data = 1,
................................................................................
            IntPtr iterator = IntPtr.Zero;

            try
            {
                streamAdapter = new SQLiteStreamAdapter(stream, flags);

                SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3changeset_start_strm(
                    ref iterator, streamAdapter.xInput, IntPtr.Zero);

                if (rc != SQLiteErrorCode.Ok)
                {
                    throw new SQLiteException(
                        rc, "sqlite3changeset_start_strm");
                }

................................................................................

    #region SQLiteStreamAdapter Class
    internal sealed class SQLiteStreamAdapter : IDisposable
    {
        #region Private Data
        private Stream stream; /* EXEMPT: NOT OWNED */
        private SQLiteConnectionFlags flags;





        #endregion

        ///////////////////////////////////////////////////////////////////////

        #region Public Constructors
        public SQLiteStreamAdapter(
            Stream stream,
................................................................................
        {
            return flags;
        }
        #endregion

        ///////////////////////////////////////////////////////////////////////



























        #region Native Callback Methods
        public SQLiteErrorCode xInput(
            IntPtr context,
            IntPtr pData,
            ref int nData
            )
        {
            CheckDisposed();

            try
            {
                Stream localStream = Interlocked.CompareExchange(
                    ref stream, null, null);

                if (localStream == null)
                    return SQLiteErrorCode.Misuse;

                if (nData > 0)
                {
                    byte[] bytes = new byte[nData];
................................................................................
                    if (HelperMethods.LogCallbackExceptions(GetFlags()))
                    {
                        SQLiteLog.LogMessage(
                            SQLiteBase.COR_E_EXCEPTION,
                            HelperMethods.StringFormat(
                            CultureInfo.CurrentCulture,
                            UnsafeNativeMethods.ExceptionMessageFormat,
                            "xInput", e)); /* throw */
                    }
                }
                catch
                {
                    // do nothing.
                }
            }

            return SQLiteErrorCode.IoErr_Read;
        }

        ///////////////////////////////////////////////////////////////////////

        public SQLiteErrorCode xOutput(
            IntPtr context,
            IntPtr pData,
            int nData
            )
        {
            CheckDisposed();

            try
            {
                Stream localStream = Interlocked.CompareExchange(
                    ref stream, null, null);

                if (localStream == null)
                    return SQLiteErrorCode.Misuse;

                if (nData > 0)
                {
                    byte[] bytes = new byte[nData];
................................................................................
                    if (HelperMethods.LogCallbackExceptions(GetFlags()))
                    {
                        SQLiteLog.LogMessage(
                            SQLiteBase.COR_E_EXCEPTION,
                            HelperMethods.StringFormat(
                            CultureInfo.CurrentCulture,
                            UnsafeNativeMethods.ExceptionMessageFormat,
                            "xOutput", e)); /* throw */
                    }
                }
                catch
                {
                    // do nothing.
                }
            }
................................................................................
                if (!disposed)
                {
                    if (disposing)
                    {
                        ////////////////////////////////////
                        // dispose managed resources here...
                        ////////////////////////////////////









                    }

                    //////////////////////////////////////
                    // release unmanaged resources here...
                    //////////////////////////////////////

                    Interlocked.Exchange(ref stream, null); /* NOT OWNED */
                }
            }
            finally
            {
                //
                // NOTE: Everything should be fully disposed at this point.
                //
................................................................................
            if (streamAdapter == null)
            {
                throw new SQLiteException(
                    "could not get or create adapter for input stream");
            }

            SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3changegroup_add_strm(
                changeGroup, streamAdapter.xInput, IntPtr.Zero);

            if (rc != SQLiteErrorCode.Ok)
                throw new SQLiteException(rc, "sqlite3changegroup_add_strm");
        }

        ///////////////////////////////////////////////////////////////////////

................................................................................
            if (streamAdapter == null)
            {
                throw new SQLiteException(
                    "could not get or create adapter for output stream");
            }

            SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3changegroup_output_strm(
                changeGroup, streamAdapter.xOutput, IntPtr.Zero);

            if (rc != SQLiteErrorCode.Ok)
                throw new SQLiteException(rc, "sqlite3changegroup_output_strm");
        }
        #endregion

        ///////////////////////////////////////////////////////////////////////
................................................................................

        ///////////////////////////////////////////////////////////////////////

        private IntPtr session;

        ///////////////////////////////////////////////////////////////////////


        private SessionTableFilterCallback tableFilterCallback;
        private object tableFilterClientData;
        #endregion

        ///////////////////////////////////////////////////////////////////////

        #region Public Constructors
................................................................................
        ///////////////////////////////////////////////////////////////////////

        private UnsafeNativeMethods.xSessionFilter ApplyTableFilter(
            SessionTableFilterCallback callback, /* in: NULL OK */
            object clientData                    /* in: NULL OK */
            )
        {
            this.tableFilterCallback = callback;
            this.tableFilterClientData = clientData;

            return (callback != null) ?








                xFilter : (UnsafeNativeMethods.xSessionFilter)null;


        }

        ///////////////////////////////////////////////////////////////////////

        private void InitializeStreamManager()
        {
            if (streamManager != null)
................................................................................
            Stream stream
            )
        {
            InitializeStreamManager();

            return streamManager.GetAdapter(stream);
        }


        ///////////////////////////////////////////////////////////////////////

        #region Native Callback Methods
        private int xFilter(
            IntPtr context, /* NOT USED */
            IntPtr pTblName
            )
        {
            try
            {
                return tableFilterCallback(tableFilterClientData,
................................................................................
                    if (HelperMethods.LogCallbackExceptions(GetFlags()))
                    {
                        SQLiteLog.LogMessage( /* throw */
                            SQLiteBase.COR_E_EXCEPTION,
                            HelperMethods.StringFormat(
                            CultureInfo.CurrentCulture,
                            UnsafeNativeMethods.ExceptionMessageFormat,
                            "xFilter", e));
                    }
                }
                catch
                {
                    // do nothing.
                }
            }

            return 0;
        }
        #endregion
        #endregion

        ///////////////////////////////////////////////////////////////////////

        #region ISQLiteSession Members
        public bool IsEnabled()
        {
................................................................................
            if (streamAdapter == null)
            {
                throw new SQLiteException(
                    "could not get or create adapter for output stream");
            }

            SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3session_changeset_strm(
                session, streamAdapter.xOutput, IntPtr.Zero);

            if (rc != SQLiteErrorCode.Ok)
                throw new SQLiteException(rc, "sqlite3session_changeset_strm");
        }

        ///////////////////////////////////////////////////////////////////////

................................................................................
            if (streamAdapter == null)
            {
                throw new SQLiteException(
                    "could not get or create adapter for output stream");
            }

            SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3session_patchset_strm(
                session, streamAdapter.xOutput, IntPtr.Zero);

            if (rc != SQLiteErrorCode.Ok)
                throw new SQLiteException(rc, "sqlite3session_patchset_strm");
        }

        ///////////////////////////////////////////////////////////////////////

................................................................................
                if (!disposed)
                {
                    if (disposing)
                    {
                        ////////////////////////////////////
                        // dispose managed resources here...
                        ////////////////////////////////////




                        if (streamManager != null)
                        {
                            streamManager.Dispose();
                            streamManager = null;
                        }
                    }
................................................................................
                        if (HelperMethods.LogCallbackExceptions(GetFlags()))
                        {
                            SQLiteLog.LogMessage( /* throw */
                                SQLiteBase.COR_E_EXCEPTION,
                                HelperMethods.StringFormat(
                                CultureInfo.CurrentCulture,
                                UnsafeNativeMethods.ExceptionMessageFormat,
                                "xFilter", e));
                        }
                    }
                    catch
                    {
                        // do nothing.
                    }
                }
................................................................................
                        if (HelperMethods.LogCallbackExceptions(GetFlags()))
                        {
                            SQLiteLog.LogMessage( /* throw */
                                SQLiteBase.COR_E_EXCEPTION,
                                HelperMethods.StringFormat(
                                CultureInfo.CurrentCulture,
                                UnsafeNativeMethods.ExceptionMessageFormat,
                                "xConflict", e));
                        }
                    }
                    catch
                    {
                        // do nothing.
                    }
                }
................................................................................
        public ISQLiteChangeSet Invert()
        {
            CheckDisposed();
            CheckInputStream();
            CheckOutputStream();

            SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3changeset_invert_strm(
                inputStreamAdapter.xInput, IntPtr.Zero,
                outputStreamAdapter.xOutput, IntPtr.Zero);

            if (rc != SQLiteErrorCode.Ok)
                throw new SQLiteException(rc, "sqlite3changeset_invert_strm");

            return null;
        }

................................................................................
                throw new ArgumentException(
                    "not a stream based change set", "changeSet");
            }

            streamChangeSet.CheckInputStream();

            SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3changeset_concat_strm(
                inputStreamAdapter.xInput, IntPtr.Zero,
                streamChangeSet.inputStreamAdapter.xInput, IntPtr.Zero,

                outputStreamAdapter.xOutput, IntPtr.Zero);

            if (rc != SQLiteErrorCode.Ok)
                throw new SQLiteException(rc, "sqlite3changeset_concat_strm");

            return null;
        }

................................................................................
            UnsafeNativeMethods.xSessionFilter xFilter = GetDelegate(
                tableFilterCallback, clientData);

            UnsafeNativeMethods.xSessionConflict xConflict = GetDelegate(
                conflictCallback, clientData);

            SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3changeset_apply_strm(
                GetIntPtr(), inputStreamAdapter.xInput, IntPtr.Zero, xFilter,
                xConflict, IntPtr.Zero);

            if (rc != SQLiteErrorCode.Ok)
                throw new SQLiteException(rc, "sqlite3changeset_apply_strm");
        }
        #endregion

        ///////////////////////////////////////////////////////////////////////







<







 







|







 







>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

|





<
<


|
<







 







|













|





<
<


|
<







 







|







 







>
>
>
>
>
>
>
>
>





<
<







 







|







 







|







 







>







 







|
|

|
>
>
>
>
>
>
>
>
|
>
>







 







>




|







 







|










<







 







|







 







|







 







>
>
>







 







|







 







|







 







|
|







 







|
|
>
|







 







|
|







11
12
13
14
15
16
17

18
19
20
21
22
23
24
...
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
...
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
...
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905


906
907
908

909
910
911
912
913
914
915
...
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956


957
958
959

960
961
962
963
964
965
966
...
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
....
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053


1054
1055
1056
1057
1058
1059
1060
....
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
....
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
....
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
....
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
....
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
....
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644

1645
1646
1647
1648
1649
1650
1651
....
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
....
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
....
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
....
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
....
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
....
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
....
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
....
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
#if DEBUG
using System.Diagnostics;
#endif

using System.IO;
using System.Globalization;
using System.Runtime.InteropServices;


namespace System.Data.SQLite
{
    #region Session Extension Enumerations
    public enum SQLiteChangeSetConflictType
    {
        Data = 1,
................................................................................
            IntPtr iterator = IntPtr.Zero;

            try
            {
                streamAdapter = new SQLiteStreamAdapter(stream, flags);

                SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3changeset_start_strm(
                    ref iterator, streamAdapter.GetInputDelegate(), IntPtr.Zero);

                if (rc != SQLiteErrorCode.Ok)
                {
                    throw new SQLiteException(
                        rc, "sqlite3changeset_start_strm");
                }

................................................................................

    #region SQLiteStreamAdapter Class
    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
        public SQLiteStreamAdapter(
            Stream stream,
................................................................................
        {
            return flags;
        }
        #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
        private SQLiteErrorCode Input(
            IntPtr context,
            IntPtr pData,
            ref int nData
            )
        {


            try
            {
                Stream localStream = stream;


                if (localStream == null)
                    return SQLiteErrorCode.Misuse;

                if (nData > 0)
                {
                    byte[] bytes = new byte[nData];
................................................................................
                    if (HelperMethods.LogCallbackExceptions(GetFlags()))
                    {
                        SQLiteLog.LogMessage(
                            SQLiteBase.COR_E_EXCEPTION,
                            HelperMethods.StringFormat(
                            CultureInfo.CurrentCulture,
                            UnsafeNativeMethods.ExceptionMessageFormat,
                            "xSessionInput", e)); /* throw */
                    }
                }
                catch
                {
                    // do nothing.
                }
            }

            return SQLiteErrorCode.IoErr_Read;
        }

        ///////////////////////////////////////////////////////////////////////

        private SQLiteErrorCode Output(
            IntPtr context,
            IntPtr pData,
            int nData
            )
        {


            try
            {
                Stream localStream = stream;


                if (localStream == null)
                    return SQLiteErrorCode.Misuse;

                if (nData > 0)
                {
                    byte[] bytes = new byte[nData];
................................................................................
                    if (HelperMethods.LogCallbackExceptions(GetFlags()))
                    {
                        SQLiteLog.LogMessage(
                            SQLiteBase.COR_E_EXCEPTION,
                            HelperMethods.StringFormat(
                            CultureInfo.CurrentCulture,
                            UnsafeNativeMethods.ExceptionMessageFormat,
                            "xSessionOutput", e)); /* throw */
                    }
                }
                catch
                {
                    // do nothing.
                }
            }
................................................................................
                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.
                //
................................................................................
            if (streamAdapter == null)
            {
                throw new SQLiteException(
                    "could not get or create adapter for input stream");
            }

            SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3changegroup_add_strm(
                changeGroup, streamAdapter.GetInputDelegate(), IntPtr.Zero);

            if (rc != SQLiteErrorCode.Ok)
                throw new SQLiteException(rc, "sqlite3changegroup_add_strm");
        }

        ///////////////////////////////////////////////////////////////////////

................................................................................
            if (streamAdapter == null)
            {
                throw new SQLiteException(
                    "could not get or create adapter for output stream");
            }

            SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3changegroup_output_strm(
                changeGroup, streamAdapter.GetOutputDelegate(), IntPtr.Zero);

            if (rc != SQLiteErrorCode.Ok)
                throw new SQLiteException(rc, "sqlite3changegroup_output_strm");
        }
        #endregion

        ///////////////////////////////////////////////////////////////////////
................................................................................

        ///////////////////////////////////////////////////////////////////////

        private IntPtr session;

        ///////////////////////////////////////////////////////////////////////

        private UnsafeNativeMethods.xSessionFilter xFilter;
        private SessionTableFilterCallback tableFilterCallback;
        private object tableFilterClientData;
        #endregion

        ///////////////////////////////////////////////////////////////////////

        #region Public Constructors
................................................................................
        ///////////////////////////////////////////////////////////////////////

        private UnsafeNativeMethods.xSessionFilter ApplyTableFilter(
            SessionTableFilterCallback callback, /* in: NULL OK */
            object clientData                    /* in: NULL OK */
            )
        {
            tableFilterCallback = callback;
            tableFilterClientData = clientData;

            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)
................................................................................
            Stream stream
            )
        {
            InitializeStreamManager();

            return streamManager.GetAdapter(stream);
        }
        #endregion

        ///////////////////////////////////////////////////////////////////////

        #region Native Callback Methods
        private int Filter(
            IntPtr context, /* NOT USED */
            IntPtr pTblName
            )
        {
            try
            {
                return tableFilterCallback(tableFilterClientData,
................................................................................
                    if (HelperMethods.LogCallbackExceptions(GetFlags()))
                    {
                        SQLiteLog.LogMessage( /* throw */
                            SQLiteBase.COR_E_EXCEPTION,
                            HelperMethods.StringFormat(
                            CultureInfo.CurrentCulture,
                            UnsafeNativeMethods.ExceptionMessageFormat,
                            "xSessionFilter", e));
                    }
                }
                catch
                {
                    // do nothing.
                }
            }

            return 0;
        }

        #endregion

        ///////////////////////////////////////////////////////////////////////

        #region ISQLiteSession Members
        public bool IsEnabled()
        {
................................................................................
            if (streamAdapter == null)
            {
                throw new SQLiteException(
                    "could not get or create adapter for output stream");
            }

            SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3session_changeset_strm(
                session, streamAdapter.GetOutputDelegate(), IntPtr.Zero);

            if (rc != SQLiteErrorCode.Ok)
                throw new SQLiteException(rc, "sqlite3session_changeset_strm");
        }

        ///////////////////////////////////////////////////////////////////////

................................................................................
            if (streamAdapter == null)
            {
                throw new SQLiteException(
                    "could not get or create adapter for output stream");
            }

            SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3session_patchset_strm(
                session, streamAdapter.GetOutputDelegate(), IntPtr.Zero);

            if (rc != SQLiteErrorCode.Ok)
                throw new SQLiteException(rc, "sqlite3session_patchset_strm");
        }

        ///////////////////////////////////////////////////////////////////////

................................................................................
                if (!disposed)
                {
                    if (disposing)
                    {
                        ////////////////////////////////////
                        // dispose managed resources here...
                        ////////////////////////////////////

                        if (xFilter != null)
                            xFilter = null;

                        if (streamManager != null)
                        {
                            streamManager.Dispose();
                            streamManager = null;
                        }
                    }
................................................................................
                        if (HelperMethods.LogCallbackExceptions(GetFlags()))
                        {
                            SQLiteLog.LogMessage( /* throw */
                                SQLiteBase.COR_E_EXCEPTION,
                                HelperMethods.StringFormat(
                                CultureInfo.CurrentCulture,
                                UnsafeNativeMethods.ExceptionMessageFormat,
                                "xSessionFilter", e));
                        }
                    }
                    catch
                    {
                        // do nothing.
                    }
                }
................................................................................
                        if (HelperMethods.LogCallbackExceptions(GetFlags()))
                        {
                            SQLiteLog.LogMessage( /* throw */
                                SQLiteBase.COR_E_EXCEPTION,
                                HelperMethods.StringFormat(
                                CultureInfo.CurrentCulture,
                                UnsafeNativeMethods.ExceptionMessageFormat,
                                "xSessionConflict", e));
                        }
                    }
                    catch
                    {
                        // do nothing.
                    }
                }
................................................................................
        public ISQLiteChangeSet Invert()
        {
            CheckDisposed();
            CheckInputStream();
            CheckOutputStream();

            SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3changeset_invert_strm(
                inputStreamAdapter.GetInputDelegate(), IntPtr.Zero,
                outputStreamAdapter.GetOutputDelegate(), IntPtr.Zero);

            if (rc != SQLiteErrorCode.Ok)
                throw new SQLiteException(rc, "sqlite3changeset_invert_strm");

            return null;
        }

................................................................................
                throw new ArgumentException(
                    "not a stream based change set", "changeSet");
            }

            streamChangeSet.CheckInputStream();

            SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3changeset_concat_strm(
                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;
        }

................................................................................
            UnsafeNativeMethods.xSessionFilter xFilter = GetDelegate(
                tableFilterCallback, clientData);

            UnsafeNativeMethods.xSessionConflict xConflict = GetDelegate(
                conflictCallback, clientData);

            SQLiteErrorCode rc = UnsafeNativeMethods.sqlite3changeset_apply_strm(
                GetIntPtr(), inputStreamAdapter.GetInputDelegate(), IntPtr.Zero,
                xFilter, xConflict, IntPtr.Zero);

            if (rc != SQLiteErrorCode.Ok)
                throw new SQLiteException(rc, "sqlite3changeset_apply_strm");
        }
        #endregion

        ///////////////////////////////////////////////////////////////////////

Changes to Tests/session.eagle.

470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
  set session [$connection -alias CreateSession main]
  $session AttachTable null

  makeSomeChanges $db t1 [list insert update delete]

  set rawData [createMemoryChangeSetForSession $session]

debug break

  writeRawDataToFile $fileName(1) $rawData
  writeStreamChangeSetForSession $session $fileName(2)
  openStreamChangeSetForConnection $connection $fileName(2) "" state

  list [expr {[file size $fileName(1)] > 0}] \
      [string equal [readFile $fileName(1)] [readFile $fileName(2)]] \
      [changeSetToString $state(changeSet) true]







<
<







470
471
472
473
474
475
476


477
478
479
480
481
482
483
  set session [$connection -alias CreateSession main]
  $session AttachTable null

  makeSomeChanges $db t1 [list insert update delete]

  set rawData [createMemoryChangeSetForSession $session]



  writeRawDataToFile $fileName(1) $rawData
  writeStreamChangeSetForSession $session $fileName(2)
  openStreamChangeSetForConnection $connection $fileName(2) "" state

  list [expr {[file size $fileName(1)] > 0}] \
      [string equal [readFile $fileName(1)] [readFile $fileName(2)]] \
      [changeSetToString $state(changeSet) true]