System.Data.SQLite

Check-in [187e8cb03d]
Login

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

Overview
Comment:Add UnbindFunction method to the SQLiteConnection class.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 187e8cb03dd8b88f8a6b017f97d39e44e36302c6
User & Date: mistachkin 2015-07-17 01:08:47.507
Context
2015-07-17
02:01
Add the UnbindFunctionsOnClose connection flag. check-in: 2a6efe65f7 user: mistachkin tags: trunk
01:08
Add UnbindFunction method to the SQLiteConnection class. check-in: 187e8cb03d user: mistachkin tags: trunk
00:54
Update SQLite core library to the latest trunk code. check-in: f7d0d964fb user: mistachkin tags: trunk
Changes
Side-by-Side Diff Ignore Whitespace Patch
Changes to Doc/Extra/Provider/version.html.
52
53
54
55
56
57
58

59
60
61
62
63
64
65
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66







+







      <li>Change the base type for the SQLiteConnectionFlags enumeration to long integer.&nbsp;<b>** Potentially Incompatible Change **</b></li>
      <li>Add extended return codes to the SQLiteErrorCode enumeration. Pursuant to <a href="https://system.data.sqlite.org/index.html/info/71bedaca19">[71bedaca19]</a>.&nbsp;<b>** Potentially Incompatible Change **</b></li>
      <li>Improve exception handling in all native callbacks implemented in the SQLiteConnection class.</li>
      <li>Add Progress event and ProgressOps connection string property to enable raising progress events during long-running queries.</li>
      <li>Add NoDefaultFlags connection string property to prevent the default connection flags from being used. Pursuant to <a href="https://system.data.sqlite.org/index.html/info/964063da16">[964063da16]</a>.</li>
      <li>Add VfsName connection string property to allow a non-default VFS to be used by the SQLite core library.</li>
      <li>Add BusyTimeout connection string property to set the busy timeout to be used by the SQLite core library.</li>
      <li>Add UnbindFunction method to the SQLiteConnection class.</li>
      <li>Enable integration with the <a href="http://www.hwaci.com/sw/sqlite/zipvfs.html">ZipVFS</a> extension.</li>
    </ul>
    <p><b>1.0.97.0 - May 26, 2015</b></p>
    <ul>
      <li>Updated to <a href="https://www.sqlite.org/releaselog/3_8_10_2.html">SQLite 3.8.10.2</a>.</li>
      <li>Updated to <a href="https://www.nuget.org/packages/EntityFramework/6.1.3">Entity Framework 6.1.3</a>.</li>
      <li>Improve ADO.NET conformance of the SQLiteDataReader.RecordsAffected property. Fix for <a href="https://system.data.sqlite.org/index.html/info/74542e702e">[74542e702e]</a>.&nbsp;<b>** Potentially Incompatible Change **</b></li>
Changes to System.Data.SQLite/SQLite3.cs.
73
74
75
76
77
78
79
80

81
82
83
84
85
86
87
73
74
75
76
77
78
79

80
81
82
83
84
85
86
87







-
+







#if (NET_35 || NET_40 || NET_45 || NET_451) && !PLATFORM_COMPACTFRAMEWORK
    private bool _buildingSchema;
#endif

    /// <summary>
    /// The user-defined functions registered on this connection
    /// </summary>
    protected List<SQLiteFunction> _functions;
    protected Dictionary<SQLiteFunctionAttribute, SQLiteFunction> _functions;

#if INTEROP_VIRTUAL_TABLE
    /// <summary>
    /// The modules created using this connection.
    /// </summary>
    protected Dictionary<string, SQLiteModule> _modules;
#endif
343
344
345
346
347
348
349






350
351
352



























353

354




355







356
357
358
359
360
361
362
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385

386
387
388
389
390
391

392
393
394
395
396
397
398
399
400
401
402
403
404
405







+
+
+
+
+
+



+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+

+
+
+
+
-
+
+
+
+
+
+
+







    /// </param>
    internal override void BindFunction(
        SQLiteFunctionAttribute functionAttribute,
        SQLiteFunction function,
        SQLiteConnectionFlags flags
        )
    {
        if (functionAttribute == null)
            throw new ArgumentNullException("functionAttribute");

        if (function == null)
            throw new ArgumentNullException("function");

        SQLiteFunction.BindFunction(this, functionAttribute, function, flags);

        if (_functions == null)
            _functions = new Dictionary<SQLiteFunctionAttribute, SQLiteFunction>();

        _functions[functionAttribute] = function;
    }

    /// <summary>
    /// This function binds a user-defined function to the connection.
    /// </summary>
    /// <param name="functionAttribute">
    /// The <see cref="SQLiteFunctionAttribute"/> object instance containing
    /// the metadata for the function to be unbound.
    /// </param>
    /// <param name="flags">
    /// The flags associated with the parent connection object.
    /// </param>
    /// <returns>Non-zero if the function was unbound and removed.</returns>
    internal override bool UnbindFunction(
        SQLiteFunctionAttribute functionAttribute,
        SQLiteConnectionFlags flags
        )
    {
        if (functionAttribute == null)
            throw new ArgumentNullException("functionAttribute");

        if (_functions == null)
            return false;

            _functions = new List<SQLiteFunction>();
        SQLiteFunction function;

        if (_functions.TryGetValue(functionAttribute, out function))
        {
            if (SQLiteFunction.UnbindFunction(
                    this, functionAttribute, function, flags) &&
        _functions.Add(function);
                _functions.Remove(functionAttribute))
            {
                return true;
            }
        }

        return false;
    }

    internal override string Version
    {
      get
      {
        return SQLiteVersion;
584
585
586
587
588
589
590








591
592
593
594
595
596
597
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648







+
+
+
+
+
+
+
+







        {
            if (_sql == null)
                throw new SQLiteException("no connection handle available");

            return _sql.OwnHandle;
        }
    }

    /// <summary>
    /// Returns the logical list of functions associated with this connection.
    /// </summary>
    internal override IDictionary<SQLiteFunctionAttribute, SQLiteFunction> Functions
    {
        get { return _functions; }
    }

    internal override SQLiteErrorCode SetMemoryStatus(bool value)
    {
        return StaticSetMemoryStatus(value);
    }

    internal static SQLiteErrorCode StaticSetMemoryStatus(bool value)
816
817
818
819
820
821
822
823

824

825




826
827
828
829
830
831
832
867
868
869
870
871
872
873

874
875
876

877
878
879
880
881
882
883
884
885
886
887







-
+

+
-
+
+
+
+







      }

      // Bind functions to this connection.  If any previous functions of the same name
      // were already bound, then the new bindings replace the old.
      if ((connectionFlags & SQLiteConnectionFlags.NoBindFunctions) != SQLiteConnectionFlags.NoBindFunctions)
      {
          if (_functions == null)
              _functions = new List<SQLiteFunction>();
              _functions = new Dictionary<SQLiteFunctionAttribute, SQLiteFunction>();

          foreach (KeyValuePair<SQLiteFunctionAttribute, SQLiteFunction> pair
          _functions.AddRange(new List<SQLiteFunction>(SQLiteFunction.BindFunctions(this, connectionFlags)));
                  in SQLiteFunction.BindFunctions(this, connectionFlags))
          {
              _functions[pair.Key] = pair.Value;
          }
      }

      SetTimeout(0);
      GC.KeepAlive(_sql);
    }

    internal override void ClearPool()
1992
1993
1994
1995
1996
1997
1998
1999

2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010


2011
2012
2013

2014
2015
2016
2017


2018
2019
2020
2021
2022
2023
2024
2047
2048
2049
2050
2051
2052
2053

2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064

2065
2066
2067
2068

2069
2070
2071
2072

2073
2074
2075
2076
2077
2078
2079
2080
2081







-
+










-
+
+


-
+



-
+
+







    }

    internal override int AggregateCount(IntPtr context)
    {
      return UnsafeNativeMethods.sqlite3_aggregate_count(context);
    }

    internal override void CreateFunction(string strFunction, int nArgs, bool needCollSeq, SQLiteCallback func, SQLiteCallback funcstep, SQLiteFinalCallback funcfinal)
    internal override SQLiteErrorCode CreateFunction(string strFunction, int nArgs, bool needCollSeq, SQLiteCallback func, SQLiteCallback funcstep, SQLiteFinalCallback funcfinal, bool canThrow)
    {
      SQLiteErrorCode n;

#if !SQLITE_STANDARD
      n = UnsafeNativeMethods.sqlite3_create_function_interop(_sql, ToUTF8(strFunction), nArgs, 4, IntPtr.Zero, func, funcstep, funcfinal, (needCollSeq == true) ? 1 : 0);
      if (n == SQLiteErrorCode.Ok) n = UnsafeNativeMethods.sqlite3_create_function_interop(_sql, ToUTF8(strFunction), nArgs, 1, IntPtr.Zero, func, funcstep, funcfinal, (needCollSeq == true) ? 1 : 0);
#else
      n = UnsafeNativeMethods.sqlite3_create_function(_sql, ToUTF8(strFunction), nArgs, 4, IntPtr.Zero, func, funcstep, funcfinal);
      if (n == SQLiteErrorCode.Ok) n = UnsafeNativeMethods.sqlite3_create_function(_sql, ToUTF8(strFunction), nArgs, 1, IntPtr.Zero, func, funcstep, funcfinal);
#endif
      if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError());
      if (canThrow && (n != SQLiteErrorCode.Ok)) throw new SQLiteException(n, GetLastError());
      return n;
    }

    internal override void CreateCollation(string strCollation, SQLiteCollation func, SQLiteCollation func16)
    internal override SQLiteErrorCode CreateCollation(string strCollation, SQLiteCollation func, SQLiteCollation func16, bool canThrow)
    {
      SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_create_collation(_sql, ToUTF8(strCollation), 2, IntPtr.Zero, func16);
      if (n == SQLiteErrorCode.Ok) n = UnsafeNativeMethods.sqlite3_create_collation(_sql, ToUTF8(strCollation), 1, IntPtr.Zero, func);
      if (n != SQLiteErrorCode.Ok) throw new SQLiteException(n, GetLastError());
      if (canThrow && (n != SQLiteErrorCode.Ok)) throw new SQLiteException(n, GetLastError());
      return n;
    }

    internal override int ContextCollateCompare(CollationEncodingEnum enc, IntPtr context, string s1, string s2)
    {
#if !SQLITE_STANDARD
      byte[] b1;
      byte[] b2;
Changes to System.Data.SQLite/SQLite3_UTF16.cs.
220
221
222
223
224
225
226
227

228

229




230
231
232
233
234
235
236
220
221
222
223
224
225
226

227
228
229

230
231
232
233
234
235
236
237
238
239
240







-
+

+
-
+
+
+
+







      }

      // Bind functions to this connection.  If any previous functions of the same name
      // were already bound, then the new bindings replace the old.
      if ((connectionFlags & SQLiteConnectionFlags.NoBindFunctions) != SQLiteConnectionFlags.NoBindFunctions)
      {
          if (_functions == null)
              _functions = new List<SQLiteFunction>();
              _functions = new Dictionary<SQLiteFunctionAttribute, SQLiteFunction>();

          foreach (KeyValuePair<SQLiteFunctionAttribute, SQLiteFunction> pair
          _functions.AddRange(new List<SQLiteFunction>(SQLiteFunction.BindFunctions(this, connectionFlags)));
                  in SQLiteFunction.BindFunctions(this, connectionFlags))
          {
              _functions[pair.Key] = pair.Value;
          }
      }

      SetTimeout(0);
      GC.KeepAlive(_sql);
    }

    internal override void Bind_DateTime(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, DateTime dt)
Changes to System.Data.SQLite/SQLiteBase.cs.
1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18










+







/********************************************************
 * ADO.NET 2.0 Data Provider for SQLite Version 3.X
 * Written by Robert Simpson (robert@blackcastlesoft.com)
 *
 * Released to the public domain, use at your own risk!
 ********************************************************/

namespace System.Data.SQLite
{
  using System;
  using System.Collections.Generic;

#if !PLATFORM_COMPACTFRAMEWORK
  using System.Runtime.InteropServices;
#endif

  /// <summary>
  /// This internal class provides the foundation of SQLite support.  It defines all the abstract members needed to implement
59
60
61
62
63
64
65




66
67
68
69
70
71
72
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77







+
+
+
+







    /// </summary>
    internal abstract long MemoryHighwater { get; }
    /// <summary>
    /// Returns non-zero if the underlying native connection handle is owned by this instance.
    /// </summary>
    internal abstract bool OwnHandle { get; }
    /// <summary>
    /// Returns the logical list of functions associated with this connection.
    /// </summary>
    internal abstract IDictionary<SQLiteFunctionAttribute, SQLiteFunction> Functions { get; }
    /// <summary>
    /// Sets the status of the memory usage tracking subsystem in the SQLite core library.  By default, this is enabled.
    /// If this is disabled, memory usage tracking will not be performed.  This is not really a per-connection value, it is
    /// global to the process.
    /// </summary>
    /// <param name="value">Non-zero to enable memory usage tracking, zero otherwise.</param>
    /// <returns>A standard SQLite return code (i.e. zero for success and non-zero for failure).</returns>
    internal abstract SQLiteErrorCode SetMemoryStatus(bool value);
179
180
181
182
183
184
185
186

187
188
189
190
191
192
193
194
195
196
197
198
199
200













201
202
203
204
205
206
207
184
185
186
187
188
189
190

191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225







-
+














+
+
+
+
+
+
+
+
+
+
+
+
+







    /// <summary>
    /// Attempts to interrupt the query currently executing on the associated
    /// native database connection.
    /// </summary>
    internal abstract void Cancel();

    /// <summary>
    /// This function binds a user-defined functions to the connection.
    /// This function binds a user-defined function to the connection.
    /// </summary>
    /// <param name="functionAttribute">
    /// The <see cref="SQLiteFunctionAttribute"/> object instance containing
    /// the metadata for the function to be bound.
    /// </param>
    /// <param name="function">
    /// The <see cref="SQLiteFunction"/> object instance that implements the
    /// function to be bound.
    /// </param>
    /// <param name="flags">
    /// The flags associated with the parent connection object.
    /// </param>
    internal abstract void BindFunction(SQLiteFunctionAttribute functionAttribute, SQLiteFunction function, SQLiteConnectionFlags flags);

    /// <summary>
    /// This function unbinds a user-defined function from the connection.
    /// </summary>
    /// <param name="functionAttribute">
    /// The <see cref="SQLiteFunctionAttribute"/> object instance containing
    /// the metadata for the function to be unbound.
    /// </param>
    /// <param name="flags">
    /// The flags associated with the parent connection object.
    /// </param>
    /// <returns>Non-zero if the function was unbound.</returns>
    internal abstract bool UnbindFunction(SQLiteFunctionAttribute functionAttribute, SQLiteConnectionFlags flags);

    internal abstract void Bind_Double(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, double value);
    internal abstract void Bind_Int32(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, Int32 value);
    internal abstract void Bind_UInt32(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, UInt32 value);
    internal abstract void Bind_Int64(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, Int64 value);
    internal abstract void Bind_UInt64(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, UInt64 value);
    internal abstract void Bind_Text(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, string value);
    internal abstract void Bind_Blob(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, byte[] blobData);
234
235
236
237
238
239
240
241
242


243
244
245
246
247
248
249
252
253
254
255
256
257
258


259
260
261
262
263
264
265
266
267







-
-
+
+







    internal abstract UInt64 GetUInt64(SQLiteStatement stmt, int index);
    internal abstract string GetText(SQLiteStatement stmt, int index);
    internal abstract long GetBytes(SQLiteStatement stmt, int index, int nDataoffset, byte[] bDest, int nStart, int nLength);
    internal abstract long GetChars(SQLiteStatement stmt, int index, int nDataoffset, char[] bDest, int nStart, int nLength);
    internal abstract DateTime GetDateTime(SQLiteStatement stmt, int index);
    internal abstract bool IsNull(SQLiteStatement stmt, int index);

    internal abstract void CreateCollation(string strCollation, SQLiteCollation func, SQLiteCollation func16);
    internal abstract void CreateFunction(string strFunction, int nArgs, bool needCollSeq, SQLiteCallback func, SQLiteCallback funcstep, SQLiteFinalCallback funcfinal);
    internal abstract SQLiteErrorCode CreateCollation(string strCollation, SQLiteCollation func, SQLiteCollation func16, bool @throw);
    internal abstract SQLiteErrorCode CreateFunction(string strFunction, int nArgs, bool needCollSeq, SQLiteCallback func, SQLiteCallback funcstep, SQLiteFinalCallback funcfinal, bool @throw);
    internal abstract CollationSequence GetCollationSequence(SQLiteFunction func, IntPtr context);
    internal abstract int ContextCollateCompare(CollationEncodingEnum enc, IntPtr context, string s1, string s2);
    internal abstract int ContextCollateCompare(CollationEncodingEnum enc, IntPtr context, char[] c1, char[] c2);

    internal abstract int AggregateCount(IntPtr context);
    internal abstract IntPtr AggregateContext(IntPtr context);

Changes to System.Data.SQLite/SQLiteConnection.cs.
1316
1317
1318
1319
1320
1321
1322
























1323
1324
1325
1326
1327
1328
1329
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+








        if (_sql == null)
            throw new InvalidOperationException(
                "Database connection not valid for binding functions.");

        _sql.BindFunction(functionAttribute, function, _flags);
    }

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

    /// <summary>
    /// Attempts to unbind the specified <see cref="SQLiteFunction" /> object
    /// instance to this connection.
    /// </summary>
    /// <param name="functionAttribute">
    /// The <see cref="SQLiteFunctionAttribute"/> object instance containing
    /// the metadata for the function to be unbound.
    /// </param>
    /// <returns>Non-zero if the function was unbound.</returns>
    public bool UnbindFunction(
        SQLiteFunctionAttribute functionAttribute
        )
    {
        CheckDisposed();

        if (_sql == null)
            throw new InvalidOperationException(
                "Database connection not valid for unbinding functions.");

        return _sql.UnbindFunction(functionAttribute, _flags);
    }

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

    [Conditional("CHECK_STATE")]
    internal static void Check(SQLiteConnection connection)
    {
        if (connection == null)
Changes to System.Data.SQLite/SQLiteFunction.cs.
75
76
77
78
79
80
81
82



83
84

85
86
87
88
89
90
91
75
76
77
78
79
80
81

82
83
84
85

86
87
88
89
90
91
92
93







-
+
+
+

-
+








    /// <summary>
    /// Current context of the current callback.  Only valid during a callback
    /// </summary>
    internal IntPtr _context;

    /// <summary>
    /// This static list contains all the user-defined functions declared using the proper attributes.
    /// This static dictionary contains all the user-defined functions declared
    /// using the proper attributes.  The contained dictionary values are always
    /// null and are not currently used.
    /// </summary>
    private static List<SQLiteFunctionAttribute> _registeredFunctions;
    private static IDictionary<SQLiteFunctionAttribute, object> _registeredFunctions;

    /// <summary>
    /// Internal constructor, initializes the function's internal variables.
    /// </summary>
    protected SQLiteFunction()
    {
      _contextDataList = new Dictionary<IntPtr, AggregateData>();
645
646
647
648
649
650
651
652

653
654
655
656
657
658
659
647
648
649
650
651
652
653

654
655
656
657
658
659
660
661







-
+







    /// have a SQLiteFunctionAttribute attribute, and registering them accordingly.
    /// </summary>
#if !PLATFORM_COMPACTFRAMEWORK
    [Security.Permissions.FileIOPermission(Security.Permissions.SecurityAction.Assert, AllFiles = Security.Permissions.FileIOPermissionAccess.PathDiscovery)]
#endif
    static SQLiteFunction()
    {
      _registeredFunctions = new List<SQLiteFunctionAttribute>();
      _registeredFunctions = new Dictionary<SQLiteFunctionAttribute, object>();
      try
      {
#if !PLATFORM_COMPACTFRAMEWORK
        //
        // NOTE: If the "No_SQLiteFunctions" environment variable is set,
        //       skip all our special code and simply return.
        //
703
704
705
706
707
708
709
710

711
712
713
714
715
716
717
705
706
707
708
709
710
711

712
713
714
715
716
717
718
719







-
+







            int u = arAtt.Length;
            for (int y = 0; y < u; y++)
            {
              at = arAtt[y] as SQLiteFunctionAttribute;
              if (at != null)
              {
                at.InstanceType = arTypes[x];
                _registeredFunctions.Add(at);
                _registeredFunctions.Add(at, null);
              }
            }
          }
        }
#endif
      }
      catch // SQLite provider can continue without being able to find built-in functions
732
733
734
735
736
737
738
739

740
741
742
743
744
745

746
747
748
749
750
751
752
753
754


755


756


757


758
759
760
761
762












763
764

765
766
767
768












































769
770
771
772
773
774
775
734
735
736
737
738
739
740

741
742
743
744
745
746

747
748
749
750
751
752
753
754


755
756
757
758
759

760
761
762
763
764





765
766
767
768
769
770
771
772
773
774
775
776
777

778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833







-
+





-
+







-
-
+
+

+
+
-
+
+

+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+

-
+




+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+








      for (int y = 0; y < u; y++)
      {
        at = arAtt[y] as SQLiteFunctionAttribute;
        if (at != null)
        {
          at.InstanceType = typ;
          _registeredFunctions.Add(at);
          _registeredFunctions.Add(at, null);
        }
      }
    }

    /// <summary>
    /// Called by SQLiteBase derived classes, this function binds all user-defined functions to a connection.
    /// Called by SQLiteBase derived classes, this function binds all registered user-defined functions to a connection.
    /// It is done this way so that all user-defined functions will access the database using the same encoding scheme
    /// as the connection (UTF-8 or UTF-16).
    /// </summary>
    /// <remarks>
    /// The wrapper functions that interop with SQLite will create a unique cookie value, which internally is a pointer to
    /// all the wrapped callback functions.  The interop function uses it to map CDecl callbacks to StdCall callbacks.
    /// </remarks>
    /// <param name="sqlbase">The base object on which the functions are to bind</param>
    /// <param name="flags">The flags associated with the parent connection object</param>
    /// <param name="sqlbase">The base object on which the functions are to bind.</param>
    /// <param name="flags">The flags associated with the parent connection object.</param>
    /// <returns>Returns a logical list of functions which the connection should retain until it is closed.</returns>
    internal static IDictionary<SQLiteFunctionAttribute, SQLiteFunction> BindFunctions(
        SQLiteBase sqlbase,
    internal static IEnumerable<SQLiteFunction> BindFunctions(SQLiteBase sqlbase, SQLiteConnectionFlags flags)
        SQLiteConnectionFlags flags
        )
    {
        IDictionary<SQLiteFunctionAttribute, SQLiteFunction> lFunctions =
            new Dictionary<SQLiteFunctionAttribute, SQLiteFunction>();
        List<SQLiteFunction> lFunctions = new List<SQLiteFunction>();

        foreach (SQLiteFunctionAttribute pr in _registeredFunctions)
        {
            SQLiteFunction f = (SQLiteFunction)Activator.CreateInstance(pr.InstanceType);

        foreach (KeyValuePair<SQLiteFunctionAttribute, object> pair
                in _registeredFunctions)
        {
            SQLiteFunctionAttribute pr = pair.Key;

            if (pr == null)
                continue;

            SQLiteFunction f = (SQLiteFunction)Activator.CreateInstance(
                pr.InstanceType);

            BindFunction(sqlbase, pr, f, flags);
            lFunctions.Add(f);
            lFunctions[pr] = f;
        }

        return lFunctions;
    }

    /// <summary>
    /// Called by SQLiteBase derived classes, this function unbinds all previously bound
    /// user-defined functions from a connection.
    /// </summary>
    /// <param name="sqlbase">The base object from which the functions are to be unbound.</param>
    /// <param name="flags">The flags associated with the parent connection object.</param>
    /// <returns>Non-zero if all previously bound user-defined functions were unbound.</returns>
    internal static bool UnbindFunctions(
        SQLiteBase sqlbase,
        SQLiteConnectionFlags flags
        )
    {
        if (sqlbase == null)
            return false;

        IDictionary<SQLiteFunctionAttribute, SQLiteFunction> lFunctions =
            sqlbase.Functions;

        if (lFunctions == null)
            return false;

        bool result = true;

        foreach (KeyValuePair<SQLiteFunctionAttribute, object> pair
                in _registeredFunctions)
        {
            SQLiteFunctionAttribute pr = pair.Key;

            if (pr == null)
                continue;

            SQLiteFunction f;

            if (!lFunctions.TryGetValue(pr, out f) ||
                (f == null) ||
                !UnbindFunction(sqlbase, pr, f, flags))
            {
                result = false;
            }
        }

        return result;
    }

    /// <summary>
    /// This function binds a user-defined functions to a connection.
    /// </summary>
    /// <param name="sqliteBase">
    /// The <see cref="SQLiteBase" /> object instance associated with the
    /// <see cref="SQLiteConnection" /> that the function should be bound to.
826
827
828
829
830
831
832
833

834
835
836
837
838


839
840
841

























































842
843
844
845
846
847
848
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
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
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963







-
+




-
+
+


-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







        if (functionType != FunctionType.Collation)
        {
            bool needCollSeq = (function is SQLiteFunctionEx);

            sqliteBase.CreateFunction(
                name, functionAttribute.Arguments, needCollSeq,
                function._InvokeFunc, function._StepFunc,
                function._FinalFunc);
                function._FinalFunc, true);
        }
        else
        {
            sqliteBase.CreateCollation(
                name, function._CompareFunc, function._CompareFunc16);
                name, function._CompareFunc, function._CompareFunc16,
                true);
        }
    }
  }

    /// <summary>
    /// This function unbinds a user-defined functions from a connection.
    /// </summary>
    /// <param name="sqliteBase">
    /// The <see cref="SQLiteBase" /> object instance associated with the
    /// <see cref="SQLiteConnection" /> that the function should be bound to.
    /// </param>
    /// <param name="functionAttribute">
    /// The <see cref="SQLiteFunctionAttribute"/> object instance containing
    /// the metadata for the function to be bound.
    /// </param>
    /// <param name="function">
    /// The <see cref="SQLiteFunction"/> object instance that implements the
    /// function to be bound.
    /// </param>
    /// <param name="flags">
    /// The flags associated with the parent connection object.
    /// </param>
    /// <returns>Non-zero if the function was unbound.</returns>
    internal static bool UnbindFunction(
        SQLiteBase sqliteBase,
        SQLiteFunctionAttribute functionAttribute,
        SQLiteFunction function,
        SQLiteConnectionFlags flags /* NOT USED */
        )
    {
        if (sqliteBase == null)
            throw new ArgumentNullException("sqliteBase");

        if (functionAttribute == null)
            throw new ArgumentNullException("functionAttribute");

        if (function == null)
            throw new ArgumentNullException("function");

        FunctionType functionType = functionAttribute.FuncType;
        string name = functionAttribute.Name;

        if (functionType != FunctionType.Collation)
        {
            bool needCollSeq = (function is SQLiteFunctionEx);

            return sqliteBase.CreateFunction(
                name, functionAttribute.Arguments, needCollSeq,
                null, null, null, false) == SQLiteErrorCode.Ok;
        }
        else
        {
            return sqliteBase.CreateCollation(
                name, null, null, false) == SQLiteErrorCode.Ok;
        }
    }
  }




  /// <summary>
  /// Extends SQLiteFunction and allows an inherited class to obtain the collating sequence associated with a function call.
  /// </summary>
  /// <remarks>
  /// User-defined functions can call the GetCollationSequence() method in this class and use it to compare strings and char arrays.
  /// </remarks>
Changes to Tests/basic.eagle.
2528
2529
2530
2531
2532
2533
2534
2535

2536
2537
2538
2539
2540
2541
2542
2528
2529
2530
2531
2532
2533
2534

2535
2536
2537
2538
2539
2540
2541
2542







-
+








  unset -nocomplain dateTime db fileName
} -constraints {eagle command.object monoBug28 command.sql compile.DATA SQLite\
System.Data.SQLite} -result {1 630874007980000000}}

###############################################################################

runTest {test data-1.54 {bind SQLiteFunction to one SQLiteConnection} -setup {
runTest {test data-1.54 {bind function to a SQLiteConnection} -setup {
  set fileName data-1.54.db
} -body {
  set id [object invoke Interpreter.GetActive NextId]
  set dataSource [file join [getDatabaseDirectory] $fileName]

  set sql { \
    SELECT MyRandom(); \
3277
3278
3279
3280
3281
3282
3283
























































































































































3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+










  cleanupDb $fileName

  unset -nocomplain db fileName
} -constraints {eagle command.object monoBug28 command.sql compile.DATA SQLite\
System.Data.SQLite} -match regexp -result {^\{fts5: \d{4}-\d{2}-\d{2}\
\d{2}:\d{2}:\d{2} [0-9a-f]{40}\} \{\} \{\} \{\} \{\} \{\} \{rowid 3 x horse\
rowid 4 x house\}$}}

###############################################################################

runTest {test data-1.72 {unbind function from a SQLiteConnection} -setup {
  set fileName data-1.72.db
} -body {
  set id [object invoke Interpreter.GetActive NextId]
  set dataSource [file join [getDatabaseDirectory] $fileName]

  set sql { \
    SELECT MyRandom(); \
  }

  unset -nocomplain results errors

  set code [compileCSharpWith [subst {
    using System;
    using System.Data.SQLite;

    namespace _Dynamic${id}
    {
      public class Test${id} : SQLiteFunction
      {
        private Random random;
        private static SQLiteFunctionAttribute functionAttribute;
        private static SQLiteConnection connection;

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

        public Test${id}()
        {
          random = new Random();
        }

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

        public override object Invoke(
          object\[\] args
          )
        {
          return random.Next();
        }

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

        private static void Initialize()
        {
          if (functionAttribute == null)
          {
            functionAttribute = new SQLiteFunctionAttribute(
                "MyRandom", 0, FunctionType.Scalar);
          }

          if (connection == null)
          {
            connection = new SQLiteConnection(
                "Data Source=${dataSource};[getFlagsProperty]");

            connection.Open();
          }
        }

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

        public static void BindFunction()
        {
          Initialize();

          connection.BindFunction(functionAttribute, new Test${id}());
        }

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

        public static object CallFunction()
        {
          Initialize();

          using (SQLiteCommand command = new SQLiteCommand("${sql}",
              connection))
          {
            return command.ExecuteScalar();
          }
        }

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

        public static bool UnbindFunction()
        {
          Initialize();

          return connection.UnbindFunction(functionAttribute);
        }

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

        public static void Uninitialize()
        {
          if (connection != null)
          {
            connection.Close();
            connection = null;
          }

          if (functionAttribute != null)
            functionAttribute = null;
        }

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

        public static void Main()
        {
          // do nothing.
        }
      }
    }
  }] true true true results errors System.Data.SQLite.dll]

  list $code $results \
      [expr {[info exists errors] ? $errors : ""}] \
      [expr {$code eq "Ok" ? [catch {
        object invoke _Dynamic${id}.Test${id} BindFunction
      } result] : [set result ""]}] $result \
      [expr {$code eq "Ok" ? [catch {
        object invoke _Dynamic${id}.Test${id} CallFunction
      } result] : [set result ""]}] $result \
      [expr {$code eq "Ok" ? [catch {
        object invoke _Dynamic${id}.Test${id} UnbindFunction
      } result] : [set result ""]}] $result \
      [expr {$code eq "Ok" ? [catch {
        object invoke _Dynamic${id}.Test${id} CallFunction
      } result] : [set result ""]}] $result \
      [expr {$code eq "Ok" ? [catch {
        object invoke _Dynamic${id}.Test${id} BindFunction
      } result] : [set result ""]}] $result \
      [expr {$code eq "Ok" ? [catch {
        object invoke _Dynamic${id}.Test${id} CallFunction
      } result] : [set result ""]}] $result \
      [expr {$code eq "Ok" ? [catch {
        object invoke _Dynamic${id}.Test${id} Uninitialize
      } result] : [set result ""]}] $result
} -cleanup {
  cleanupDb $fileName

  unset -nocomplain result code results errors sql dataSource id fileName
} -constraints {eagle command.object monoBug28 command.sql compile.DATA SQLite\
System.Data.SQLite compileCSharp} -match regexp -result \
[string map [list \n \r\n] {^Ok System#CodeDom#Compiler#CompilerResults#\d+\
\{\} 0 \{\} 0 (?:-)?\d+ 0 True 1\
\{System\.Reflection\.TargetInvocationException: Exception has been thrown by\
the target of an invocation\. ---> System\.Data\.SQLite\.SQLiteException: SQL\
logic error or missing database
no such function: MyRandom.*\} 0 \{\} 0 (?:-)?\d+ 0 \{\}$}]}

###############################################################################

reportSQLiteResources $test_channel

###############################################################################

runSQLiteTestFilesEpilogue
runSQLiteTestEpilogue
runTestEpilogue
Changes to readme.htm.
219
220
221
222
223
224
225

226
227
228
229
230
231
232
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233







+







    <li>Change the base type for the SQLiteConnectionFlags enumeration to long integer.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>Add extended return codes to the SQLiteErrorCode enumeration. Pursuant to [71bedaca19].&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>Improve exception handling in all native callbacks implemented in the SQLiteConnection class.</li>
    <li>Add Progress event and ProgressOps connection string property to enable raising progress events during long-running queries.</li>
    <li>Add NoDefaultFlags connection string property to prevent the default connection flags from being used. Pursuant to [964063da16].</li>
    <li>Add VfsName connection string property to allow a non-default VFS to be used by the SQLite core library.</li>
    <li>Add BusyTimeout connection string property to set the busy timeout to be used by the SQLite core library.</li>
    <li>Add UnbindFunction method to the SQLiteConnection class.</li>
    <li>Enable integration with the <a href="http://www.hwaci.com/sw/sqlite/zipvfs.html">ZipVFS</a> extension.</li>
</ul>
<p>
    <b>1.0.97.0 - May 26, 2015</b>
</p>
<ul>
    <li>Updated to <a href="https://www.sqlite.org/releaselog/3_8_10_2.html">SQLite 3.8.10.2</a>.</li>
Changes to www/news.wiki.
13
14
15
16
17
18
19

20
21
22
23
24
25
26
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27







+







    <li>Change the base type for the SQLiteConnectionFlags enumeration to long integer.&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>Add extended return codes to the SQLiteErrorCode enumeration. Pursuant to [71bedaca19].&nbsp;<b>** Potentially Incompatible Change **</b></li>
    <li>Improve exception handling in all native callbacks implemented in the SQLiteConnection class.</li>
    <li>Add Progress event and ProgressOps connection string property to enable raising progress events during long-running queries.</li>
    <li>Add NoDefaultFlags connection string property to prevent the default connection flags from being used. Pursuant to [964063da16].</li>
    <li>Add VfsName connection string property to allow a non-default VFS to be used by the SQLite core library.</li>
    <li>Add BusyTimeout connection string property to set the busy timeout to be used by the SQLite core library.</li>
    <li>Add UnbindFunction method to the SQLiteConnection class.</li>
    <li>Enable integration with the [http://www.hwaci.com/sw/sqlite/zipvfs.html|ZipVFS] extension.</li>
</ul>
<p>
    <b>1.0.97.0 - May 26, 2015</b>
</p>
<ul>
    <li>Updated to [https://www.sqlite.org/releaselog/3_8_10_2.html|SQLite 3.8.10.2].</li>