System.Data.SQLite

Check-in [67f779810e]
Login

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

Overview
Comment:In the SQLite3.Close method, be sure to null out of the _sql field when _ownHandle is false. Centralize the SQLite3 instance creation logic used by the SQLiteConnection class. Restrict the ConnectionStringBuilder test to run only when SQLite is in use.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | virtualTables
Files: files | file ages | folders
SHA1: 67f779810e605ed88c9dac6d58ec72f777aa9745
User & Date: mistachkin 2013-06-21 23:44:34.746
Context
2013-06-22
00:52
Improve diagnostics for test data-1.1. Fix connection handle leak by removing superfluous _ownHandle fields and add properties instead. check-in: 0e4ebe697a user: mistachkin tags: virtualTables
2013-06-21
23:44
In the SQLite3.Close method, be sure to null out of the _sql field when _ownHandle is false. Centralize the SQLite3 instance creation logic used by the SQLiteConnection class. Restrict the ConnectionStringBuilder test to run only when SQLite is in use. check-in: 67f779810e user: mistachkin tags: virtualTables
21:01
Fix vtshim error message handling. Adjust the data-1.28 test to account for the new SQLite3 constructor parameters. Fix delegate declaration for the xFilter method. check-in: ee4c57e435 user: mistachkin tags: virtualTables
Changes
Unified Diff Ignore Whitespace Patch
Changes to System.Data.SQLite/SQLite3.cs.
98
99
100
101
102
103
104

105
106
107
108
109
110
111
112
113
114
        string fileName,
        bool ownHandle
        )
      : base(fmt, kind, fmtString)
    {
        if (db != IntPtr.Zero)
        {

            _sql = new SQLiteConnectionHandle(db, ownHandle);
            _fileName = fileName;
            _ownHandle = ownHandle;
        }
    }

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

    #region IDisposable "Pattern" Members
    private bool disposed;







>
|

<







98
99
100
101
102
103
104
105
106
107

108
109
110
111
112
113
114
        string fileName,
        bool ownHandle
        )
      : base(fmt, kind, fmtString)
    {
        if (db != IntPtr.Zero)
        {
            _ownHandle = ownHandle;
            _sql = new SQLiteConnectionHandle(db, _ownHandle);
            _fileName = fileName;

        }
    }

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

    #region IDisposable "Pattern" Members
    private bool disposed;
169
170
171
172
173
174
175


176

177
178
179
180
181
182
183
    // It isn't necessary to cleanup any functions we've registered.  If the connection
    // goes to the pool and is resurrected later, re-registered functions will overwrite the
    // previous functions.  The SQLiteFunctionCookieHandle will take care of freeing unmanaged
    // resources belonging to the previously-registered functions.
    internal override void Close(bool canThrow)
    {
      if (!_ownHandle)


        return;


      if (_sql != null)
      {
          if (_usePool)
          {
              if (SQLiteBase.ResetConnection(_sql, _sql, canThrow))
              {







>
>

>







169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
    // It isn't necessary to cleanup any functions we've registered.  If the connection
    // goes to the pool and is resurrected later, re-registered functions will overwrite the
    // previous functions.  The SQLiteFunctionCookieHandle will take care of freeing unmanaged
    // resources belonging to the previously-registered functions.
    internal override void Close(bool canThrow)
    {
      if (!_ownHandle)
      {
        _sql = null;
        return;
      }

      if (_sql != null)
      {
          if (_usePool)
          {
              if (SQLiteBase.ResetConnection(_sql, _sql, canThrow))
              {
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
      }
      else if (n == SQLiteErrorCode.Locked || n == SQLiteErrorCode.Busy)
        return n;

      if (n != SQLiteErrorCode.Ok)
        throw new SQLiteException(n, GetLastError());

      return SQLiteErrorCode.Ok; // We reset OK, no schema changes
    }

    internal override string GetLastError()
    {
      return SQLiteBase.GetLastError(_sql, _sql);
    }








|







531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
      }
      else if (n == SQLiteErrorCode.Locked || n == SQLiteErrorCode.Busy)
        return n;

      if (n != SQLiteErrorCode.Ok)
        throw new SQLiteException(n, GetLastError());

      return n; // We reset OK, no schema changes
    }

    internal override string GetLastError()
    {
      return SQLiteBase.GetLastError(_sql, _sql);
    }

Changes to System.Data.SQLite/SQLiteConnection.cs.
512
513
514
515
516
517
518







519
520
521
522
523
524
525
        : this()
    {
        _ownHandle = ownHandle;

        _sql = new SQLite3(
            SQLiteDateFormats.Default, DateTimeKind.Unspecified, null,
            db, fileName, _ownHandle);







    }

    /// <summary>
    /// Initializes the connection with the specified connection string.
    /// </summary>
    /// <param name="connectionString">
    /// The connection string to use.







>
>
>
>
>
>
>







512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
        : this()
    {
        _ownHandle = ownHandle;

        _sql = new SQLite3(
            SQLiteDateFormats.Default, DateTimeKind.Unspecified, null,
            db, fileName, _ownHandle);

        _flags = SQLiteConnectionFlags.None;

        _connectionState = (db != IntPtr.Zero) ?
            ConnectionState.Open : ConnectionState.Closed;

        _connectionString = null; /* unknown */
    }

    /// <summary>
    /// Initializes the connection with the specified connection string.
    /// </summary>
    /// <param name="connectionString">
    /// The connection string to use.
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
      {
          UnsafeNativeMethods.sqlite3_log(
              SQLiteErrorCode.Ok, SQLiteConvert.ToUTF8("logging initialized."));
      }
#endif

      _parseViaFramework = parseViaFramework;
      _ownHandle = true;
      _flags = SQLiteConnectionFlags.Default;
      _connectionState = ConnectionState.Closed;
      _connectionString = null;

      if (connectionString != null)
        ConnectionString = connectionString;
    }

    /// <summary>
    /// Clones the settings and connection string from an existing connection.  If the existing connection is already open, this
    /// function will open its own connection, enumerate any attached databases of the original connection, and automatically
    /// attach to them.
    /// </summary>
    /// <param name="connection">The connection to copy the settings from.</param>
    public SQLiteConnection(SQLiteConnection connection)
      : this(connection.ConnectionString, connection.ParseViaFramework)
    {
      string str;

      if (connection.State == ConnectionState.Open)
      {
        Open();

        // Reattach all attached databases from the existing connection
        using (DataTable tbl = connection.GetSchema("Catalogs"))
        {
          foreach (DataRow row in tbl.Rows)
          {
            str = row[0].ToString();
            if (String.Compare(str, "main", StringComparison.OrdinalIgnoreCase) != 0
              && String.Compare(str, "temp", StringComparison.OrdinalIgnoreCase) != 0)
            {
              using (SQLiteCommand cmd = CreateCommand())
              {
                cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "ATTACH DATABASE '{0}' AS [{1}]", row[1], row[0]);
                cmd.ExecuteNonQuery();







<

















<
<









|







574
575
576
577
578
579
580

581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597


598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
      {
          UnsafeNativeMethods.sqlite3_log(
              SQLiteErrorCode.Ok, SQLiteConvert.ToUTF8("logging initialized."));
      }
#endif

      _parseViaFramework = parseViaFramework;

      _flags = SQLiteConnectionFlags.Default;
      _connectionState = ConnectionState.Closed;
      _connectionString = null;

      if (connectionString != null)
        ConnectionString = connectionString;
    }

    /// <summary>
    /// Clones the settings and connection string from an existing connection.  If the existing connection is already open, this
    /// function will open its own connection, enumerate any attached databases of the original connection, and automatically
    /// attach to them.
    /// </summary>
    /// <param name="connection">The connection to copy the settings from.</param>
    public SQLiteConnection(SQLiteConnection connection)
      : this(connection.ConnectionString, connection.ParseViaFramework)
    {


      if (connection.State == ConnectionState.Open)
      {
        Open();

        // Reattach all attached databases from the existing connection
        using (DataTable tbl = connection.GetSchema("Catalogs"))
        {
          foreach (DataRow row in tbl.Rows)
          {
            string str = row[0].ToString();
            if (String.Compare(str, "main", StringComparison.OrdinalIgnoreCase) != 0
              && String.Compare(str, "temp", StringComparison.OrdinalIgnoreCase) != 0)
            {
              using (SQLiteCommand cmd = CreateCommand())
              {
                cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "ATTACH DATABASE '{0}' AS [{1}]", row[1], row[0]);
                cmd.ExecuteNonQuery();
861
862
863
864
865
866
867
























































868
869
870
871
872
873
874

        if (handle.IsInvalid)
            throw new InvalidOperationException("The connection handle is invalid.");

        if (handle.IsClosed)
            throw new InvalidOperationException("The connection handle is closed.");
    }

























































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

    #region IDisposable "Pattern" Members
    private bool disposed;
    private void CheckDisposed() /* throw */
    {







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







865
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
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934

        if (handle.IsInvalid)
            throw new InvalidOperationException("The connection handle is invalid.");

        if (handle.IsClosed)
            throw new InvalidOperationException("The connection handle is closed.");
    }

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

    private static SortedList<string, string> ParseConnectionString(
        string connectionString,
        bool parseViaFramework
        )
    {
        return parseViaFramework ?
            ParseConnectionStringViaFramework(connectionString, false) :
            ParseConnectionString(connectionString);
    }

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

    private void SetupSQLiteBase(SortedList<string, string> opts)
    {
        object enumValue;

        enumValue = TryParseEnum(
            typeof(SQLiteDateFormats), FindKey(opts, "DateTimeFormat",
            DefaultDateTimeFormat.ToString()), true);

        SQLiteDateFormats dateFormat = (enumValue is SQLiteDateFormats) ?
            (SQLiteDateFormats)enumValue : DefaultDateTimeFormat;

        enumValue = TryParseEnum(
            typeof(DateTimeKind), FindKey(opts, "DateTimeKind",
            DefaultDateTimeKind.ToString()), true);

        DateTimeKind kind = (enumValue is DateTimeKind) ?
            (DateTimeKind)enumValue : DefaultDateTimeKind;

        string dateTimeFormat = FindKey(opts, "DateTimeFormatString",
            DefaultDateTimeFormatString);

        //
        // NOTE: SQLite automatically sets the encoding of the database
        //       to UTF16 if called from sqlite3_open16().
        //
        _ownHandle = true;

        if (SQLiteConvert.ToBoolean(FindKey(opts, "UseUTF16Encoding",
                  DefaultUseUTF16Encoding.ToString())))
        {
            _sql = new SQLite3_UTF16(
                dateFormat, kind, dateTimeFormat, IntPtr.Zero, null,
                _ownHandle);
        }
        else
        {
            _sql = new SQLite3(
                dateFormat, kind, dateTimeFormat, IntPtr.Zero, null,
                _ownHandle);
        }
    }

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

    #region IDisposable "Pattern" Members
    private bool disposed;
    private void CheckDisposed() /* throw */
    {
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
          SQLiteConnectionEventType.Opening, null, null, null, null, null));

      if (_connectionState != ConnectionState.Closed)
        throw new InvalidOperationException();

      Close();

      SortedList<string, string> opts = _parseViaFramework ?
          ParseConnectionStringViaFramework(_connectionString, false) :
          ParseConnectionString(_connectionString);

      OnChanged(this, new ConnectionEventArgs(
          SQLiteConnectionEventType.ConnectionString, null, null, null, _connectionString, opts));

      object enumValue;

      enumValue = TryParseEnum(typeof(SQLiteConnectionFlags), FindKey(opts, "Flags", DefaultFlags.ToString()), true);







|
<
|







1923
1924
1925
1926
1927
1928
1929
1930

1931
1932
1933
1934
1935
1936
1937
1938
          SQLiteConnectionEventType.Opening, null, null, null, null, null));

      if (_connectionState != ConnectionState.Closed)
        throw new InvalidOperationException();

      Close();

      SortedList<string, string> opts = ParseConnectionString(

          _connectionString, _parseViaFramework);

      OnChanged(this, new ConnectionEventArgs(
          SQLiteConnectionEventType.ConnectionString, null, null, null, _connectionString, opts));

      object enumValue;

      enumValue = TryParseEnum(typeof(SQLiteConnectionFlags), FindKey(opts, "Flags", DefaultFlags.ToString()), true);
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
        if (_defaultIsolation != IsolationLevel.Serializable && _defaultIsolation != IsolationLevel.ReadCommitted)
          throw new NotSupportedException("Invalid Default IsolationLevel specified");

        _baseSchemaName = FindKey(opts, "BaseSchemaName", DefaultBaseSchemaName);

        if (_sql == null)
        {
            enumValue = TryParseEnum(typeof(SQLiteDateFormats), FindKey(opts,
                "DateTimeFormat", DefaultDateTimeFormat.ToString()), true);

            SQLiteDateFormats dateFormat = (enumValue is SQLiteDateFormats) ?
                (SQLiteDateFormats)enumValue : DefaultDateTimeFormat;

            enumValue = TryParseEnum(typeof(DateTimeKind), FindKey(opts,
                "DateTimeKind", DefaultDateTimeKind.ToString()), true);

            DateTimeKind kind = (enumValue is DateTimeKind) ?
                (DateTimeKind)enumValue : DefaultDateTimeKind;

            string dateTimeFormat = FindKey(opts, "DateTimeFormatString",
                DefaultDateTimeFormatString);

            //
            // NOTE: SQLite automatically sets the encoding of the database to
            //       UTF16 if called from sqlite3_open16().
            //
            _ownHandle = true;

            if (SQLiteConvert.ToBoolean(FindKey(opts, "UseUTF16Encoding",
                      DefaultUseUTF16Encoding.ToString())))
            {
                _sql = new SQLite3_UTF16(dateFormat, kind, dateTimeFormat, IntPtr.Zero, null, _ownHandle);
            }
            else
            {
                _sql = new SQLite3(dateFormat, kind, dateTimeFormat, IntPtr.Zero, null, _ownHandle);
            }
        }

        SQLiteOpenFlagsEnum flags = SQLiteOpenFlagsEnum.None;

        if (!SQLiteConvert.ToBoolean(FindKey(opts, "FailIfMissing", DefaultFailIfMissing.ToString())))
          flags |= SQLiteOpenFlagsEnum.Create;








<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







1991
1992
1993
1994
1995
1996
1997


1998



























1999
2000
2001
2002
2003
2004
2005
        if (_defaultIsolation != IsolationLevel.Serializable && _defaultIsolation != IsolationLevel.ReadCommitted)
          throw new NotSupportedException("Invalid Default IsolationLevel specified");

        _baseSchemaName = FindKey(opts, "BaseSchemaName", DefaultBaseSchemaName);

        if (_sql == null)
        {


            SetupSQLiteBase(opts);



























        }

        SQLiteOpenFlagsEnum flags = SQLiteOpenFlagsEnum.None;

        if (!SQLiteConvert.ToBoolean(FindKey(opts, "FailIfMissing", DefaultFailIfMissing.ToString())))
          flags |= SQLiteOpenFlagsEnum.Create;

2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
    public SQLiteErrorCode Shutdown()
    {
        CheckDisposed();

        // make sure we have an instance of the base class
        if (_sql == null)
        {
            SortedList<string, string> opts = _parseViaFramework ?
                ParseConnectionStringViaFramework(_connectionString, false) :
                ParseConnectionString(_connectionString);

            object enumValue;

            enumValue = TryParseEnum(typeof(SQLiteDateFormats), FindKey(opts,
                "DateTimeFormat", DefaultDateTimeFormat.ToString()), true);

            SQLiteDateFormats dateFormat = (enumValue is SQLiteDateFormats) ?
                (SQLiteDateFormats)enumValue : DefaultDateTimeFormat;

            enumValue = TryParseEnum(typeof(DateTimeKind), FindKey(opts,
                "DateTimeKind", DefaultDateTimeKind.ToString()), true);

            DateTimeKind kind = (enumValue is DateTimeKind) ?
                (DateTimeKind)enumValue : DefaultDateTimeKind;

            string dateTimeFormat = FindKey(opts, "DateTimeFormatString",
                DefaultDateTimeFormatString);

            //
            // NOTE: SQLite automatically sets the encoding of the database to
            //       UTF16 if called from sqlite3_open16().
            //
            if (SQLiteConvert.ToBoolean(FindKey(opts,
                    "UseUTF16Encoding", DefaultUseUTF16Encoding.ToString())))
            {
                _sql = new SQLite3_UTF16(dateFormat, kind, dateTimeFormat, IntPtr.Zero, null, _ownHandle);
            }
            else
            {
                _sql = new SQLite3(dateFormat, kind, dateTimeFormat, IntPtr.Zero, null, _ownHandle);
            }
        }
        if (_sql != null) return _sql.Shutdown();
        throw new InvalidOperationException("Database connection not active.");
    }

    /// Enables or disabled extended result codes returned by SQLite
    public void SetExtendedResultCodes(bool bOnOff)







|
<
|

<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







2391
2392
2393
2394
2395
2396
2397
2398

2399
2400

2401




























2402
2403
2404
2405
2406
2407
2408
    public SQLiteErrorCode Shutdown()
    {
        CheckDisposed();

        // make sure we have an instance of the base class
        if (_sql == null)
        {
            SortedList<string, string> opts = ParseConnectionString(

                _connectionString, _parseViaFramework);


            SetupSQLiteBase(opts);




























        }
        if (_sql != null) return _sql.Shutdown();
        throw new InvalidOperationException("Database connection not active.");
    }

    /// Enables or disabled extended result codes returned by SQLite
    public void SetExtendedResultCodes(bool bOnOff)
Changes to test/TestCases.cs.
1222
1223
1224
1225
1226
1227
1228


1229
1230
1231
1232

1233
1234
1235
1236
1237
1238
1239
        }
      }
    }

    [Test]
    internal void ConnectionStringBuilder()
    {


      DbConnectionStringBuilder builder = _fact.CreateConnectionStringBuilder();
      if (builder is SQLiteConnectionStringBuilder)
      {
        bool pool = ((SQLiteConnectionStringBuilder)builder).Pooling;

      }
    }

    [Test]
    internal void LeakyCommands()
    {
      for (int n = 0; n < 100000; n++)







>
>
|
|
|
|
>







1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
        }
      }
    }

    [Test]
    internal void ConnectionStringBuilder()
    {
      if (_fact.GetType().Name.IndexOf("SQLite", StringComparison.OrdinalIgnoreCase) > -1)
      {
        DbConnectionStringBuilder builder = _fact.CreateConnectionStringBuilder();
        if (builder is SQLiteConnectionStringBuilder)
        {
          bool pool = ((SQLiteConnectionStringBuilder)builder).Pooling;
        }
      }
    }

    [Test]
    internal void LeakyCommands()
    {
      for (int n = 0; n < 100000; n++)