System.Data.SQLite
Changes On Branch tkt-996d13cd87
Not logged in

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

Changes In Branch tkt-996d13cd87 Excluding Merge-Ins

This is equivalent to a diff from d846d5cd0b to 0fb2e3848f

2012-05-02
18:38
Merge all connection pool fixes and other changes to trunk. Fix for ticket [996d13cd87]. check-in: ae1f4354e4 user: mistachkin tags: trunk
18:28
Update test case for ticket [996d13cd87]. The test case can now reproduce the issue reported. Closed-Leaf check-in: 0fb2e3848f user: mistachkin tags: tkt-996d13cd87
16:52
Adjustments to the test case for ticket [996d13cd87]. However, this still does not reproduce the issue reported. check-in: 04c8756a93 user: mistachkin tags: tkt-996d13cd87
2012-04-28
12:22
Add missing call to SetTimeout. check-in: 33696a56cc user: mistachkin tags: trunk
09:50
First attempt to reproduce the possible issue described in ticket [996d13cd87]. check-in: adad8e2f33 user: mistachkin tags: tkt-996d13cd87
09:45
Add another connection pool related diagnostic. check-in: d846d5cd0b user: mistachkin tags: trunk
08:57
Enhance diagnostics for dealing with handle disposal issues when the connection pool is in use. check-in: e0dc37c779 user: mistachkin tags: trunk

Changes to Externals/Eagle/bin/EagleShell.exe.config.

    14     14   <configuration>
    15     15     <startup useLegacyV2RuntimeActivationPolicy="true">
    16     16       <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
    17     17     </startup>
    18     18   
    19     19     <runtime>
    20     20       <!--
           21  +    <legacyCorruptedStateExceptionsPolicy enabled="true" />
    21     22       <NetFx40_LegacySecurityPolicy enabled="true" />
    22     23       <generatePublisherEvidence enabled="false" />
    23     24       -->
    24     25   
    25     26       <!--
    26     27       <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    27     28         <dependentAssembly>

Changes to Externals/Eagle/lib/Eagle1.0/test.eagle.

   122    122             lappend result $name
   123    123           }
   124    124         }
   125    125       }
   126    126   
   127    127       return $result
   128    128     }
          129  +
          130  +  proc removeConstraint { name } {
          131  +    if {[isEagle]} then {
          132  +      if {[info exists ::eagle_tests(constraints)]} then {
          133  +        set index [lsearch -exact $::eagle_tests(constraints) $name]
          134  +
          135  +        if {$index != -1} then {
          136  +          set ::eagle_tests(constraints) [lreplace \
          137  +              $::eagle_tests(constraints) $index $index]
          138  +        }
          139  +      }
          140  +    } else {
          141  +      if {[info exists ::tcltest::testConstraints($name)]} then {
          142  +        unset ::tcltest::testConstraints($name)
          143  +      }
          144  +    }
          145  +
          146  +    return ""
          147  +  }
   129    148   
   130    149     proc fixConstraints { constraints } {
   131    150       set result [string trim $constraints]
   132    151   
   133    152       if {[string length $result] > 0} then {
   134    153         #
   135    154         # HACK: Fixup for the semi-magical expression (via [expr]) test
................................................................................
  1812   1831       exportAndImportPackageCommands [namespace current] [list addConstraint \
  1813   1832           calculateRelativePerformance haveConstraint haveOrAddConstraint \
  1814   1833           processTestArguments getTemporaryPath getTestLog getTestLogId getFiles \
  1815   1834           getConstraints getTestFiles getTestRunId execTestShell runTestPrologue \
  1816   1835           runTestEpilogue runTest runAllTests fixConstraints sourceIfValid \
  1817   1836           isExitOnComplete getPassPercentage getSkipPercentage testExec tlog \
  1818   1837           returnInfoScript tputs formatDecimal formatList configureTcltest \
  1819         -        machineToPlatform tsource testShim] false false
         1838  +        removeConstraint machineToPlatform tsource testShim] false false
  1820   1839   
  1821   1840       ###########################################################################
  1822   1841       ############################## END Tcl ONLY ###############################
  1823   1842       ###########################################################################
  1824   1843     }
  1825   1844   
  1826   1845     #
  1827   1846     # NOTE: Provide the Eagle test package to the interpreter.
  1828   1847     #
  1829   1848     package provide Eagle.Test \
  1830   1849       [expr {[isEagle] ? [info engine PatchLevel] : "1.0"}]
  1831   1850   }
  1832   1851   

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

   113    113       // resources belonging to the previously-registered functions.
   114    114       internal override void Close()
   115    115       {
   116    116         if (_sql != null)
   117    117         {
   118    118             if (_usePool)
   119    119             {
   120         -              SQLiteBase.ResetConnection(_sql);
          120  +              SQLiteBase.ResetConnection(_sql, _sql);
   121    121                 SQLiteConnectionPool.Add(_fileName, _sql, _poolVersion);
   122    122   
   123    123   #if DEBUG && !NET_COMPACT_20
   124    124                 Trace.WriteLine(String.Format("Close (Pool): {0}", _sql));
   125    125   #endif
   126    126             }
   127    127             else
................................................................................
   284    284         SetTimeout(0);
   285    285       }
   286    286   
   287    287       internal override void ClearPool()
   288    288       {
   289    289         SQLiteConnectionPool.ClearPool(_fileName);
   290    290       }
          291  +
          292  +    internal override int CountPool()
          293  +    {
          294  +        Dictionary<string, int> counts = null;
          295  +        int totalCount = 0;
          296  +
          297  +        SQLiteConnectionPool.GetCounts(_fileName,
          298  +            ref counts, ref totalCount);
          299  +
          300  +        return totalCount;
          301  +    }
   291    302   
   292    303       internal override void SetTimeout(int nTimeoutMS)
   293    304       {
   294    305         int n = UnsafeNativeMethods.sqlite3_busy_timeout(_sql, nTimeoutMS);
   295         -      if (n > 0) throw new SQLiteException(n, SQLiteLastError());
          306  +      if (n > 0) throw new SQLiteException(n, GetLastError());
   296    307       }
   297    308   
   298    309       internal override bool Step(SQLiteStatement stmt)
   299    310       {
   300    311         int n;
   301    312         Random rnd = null;
   302    313         uint starttick = (uint)Environment.TickCount;
................................................................................
   315    326   
   316    327             // An error occurred, attempt to reset the statement.  If the reset worked because the
   317    328             // schema has changed, re-try the step again.  If it errored our because the database
   318    329             // is locked, then keep retrying until the command timeout occurs.
   319    330             r = Reset(stmt);
   320    331   
   321    332             if (r == 0)
   322         -            throw new SQLiteException(n, SQLiteLastError());
          333  +            throw new SQLiteException(n, GetLastError());
   323    334   
   324    335             else if ((r == 6 || r == 5) && stmt._command != null) // SQLITE_LOCKED || SQLITE_BUSY
   325    336             {
   326    337               // Keep trying
   327    338               if (rnd == null) // First time we've encountered the lock
   328    339                 rnd = new Random();
   329    340   
   330    341               // If we've exceeded the command's timeout, give up and throw an error
   331    342               if ((uint)Environment.TickCount - starttick > timeout)
   332    343               {
   333         -              throw new SQLiteException(r, SQLiteLastError());
          344  +              throw new SQLiteException(r, GetLastError());
   334    345               }
   335    346               else
   336    347               {
   337    348                 // Otherwise sleep for a random amount of time up to 150ms
   338    349                 System.Threading.Thread.Sleep(rnd.Next(1, 150));
   339    350               }
   340    351             }
................................................................................
   370    381           }
   371    382           return -1; // Reset was OK, with schema change
   372    383         }
   373    384         else if (n == 6 || n == 5) // SQLITE_LOCKED || SQLITE_BUSY
   374    385           return n;
   375    386   
   376    387         if (n > 0)
   377         -        throw new SQLiteException(n, SQLiteLastError());
          388  +        throw new SQLiteException(n, GetLastError());
   378    389   
   379    390         return 0; // We reset OK, no schema changes
   380    391       }
   381    392   
   382         -    internal override string SQLiteLastError()
          393  +    internal override string GetLastError()
   383    394       {
   384         -      return SQLiteBase.SQLiteLastError(_sql);
          395  +      return SQLiteBase.GetLastError(_sql, _sql);
   385    396       }
   386    397   
   387    398       internal override SQLiteStatement Prepare(SQLiteConnection cnn, string strSql, SQLiteStatement previous, uint timeoutMS, out string strRemain)
   388    399       {
   389    400         if (!String.IsNullOrEmpty(strSql))
   390    401         {
   391    402           //
................................................................................
   447    458             Trace.WriteLine(String.Format("Prepare: {0}", stmt));
   448    459   #endif
   449    460   
   450    461             if (n == 17)
   451    462               retries++;
   452    463             else if (n == 1)
   453    464             {
   454         -            if (String.Compare(SQLiteLastError(), "near \"TYPES\": syntax error", StringComparison.OrdinalIgnoreCase) == 0)
          465  +            if (String.Compare(GetLastError(), "near \"TYPES\": syntax error", StringComparison.OrdinalIgnoreCase) == 0)
   455    466               {
   456    467                 int pos = strSql.IndexOf(';');
   457    468                 if (pos == -1) pos = strSql.Length - 1;
   458    469   
   459    470                 typedefs = strSql.Substring(0, pos + 1);
   460    471                 strSql = strSql.Substring(pos + 1);
   461    472   
................................................................................
   469    480   
   470    481                 if (cmd != null)
   471    482                   cmd.SetTypes(typedefs);
   472    483   
   473    484                 return cmd;
   474    485               }
   475    486   #if !PLATFORM_COMPACTFRAMEWORK
   476         -            else if (_buildingSchema == false && String.Compare(SQLiteLastError(), 0, "no such table: TEMP.SCHEMA", 0, 26, StringComparison.OrdinalIgnoreCase) == 0)
          487  +            else if (_buildingSchema == false && String.Compare(GetLastError(), 0, "no such table: TEMP.SCHEMA", 0, 26, StringComparison.OrdinalIgnoreCase) == 0)
   477    488               {
   478    489                 strRemain = "";
   479    490                 _buildingSchema = true;
   480    491                 try
   481    492                 {
   482    493                   ISQLiteSchemaExtensions ext = ((IServiceProvider)SQLiteFactory.Instance).GetService(typeof(ISQLiteSchemaExtensions)) as ISQLiteSchemaExtensions;
   483    494   
................................................................................
   504    515               // Keep trying
   505    516               if (rnd == null) // First time we've encountered the lock
   506    517                 rnd = new Random();
   507    518   
   508    519               // If we've exceeded the command's timeout, give up and throw an error
   509    520               if ((uint)Environment.TickCount - starttick > timeoutMS)
   510    521               {
   511         -              throw new SQLiteException(n, SQLiteLastError());
          522  +              throw new SQLiteException(n, GetLastError());
   512    523               }
   513    524               else
   514    525               {
   515    526                 // Otherwise sleep for a random amount of time up to 150ms
   516    527                 System.Threading.Thread.Sleep(rnd.Next(1, 150));
   517    528               }
   518    529             }
   519    530           }
   520    531   
   521         -        if (n > 0) throw new SQLiteException(n, SQLiteLastError());
          532  +        if (n > 0) throw new SQLiteException(n, GetLastError());
   522    533   
   523    534           strRemain = UTF8ToString(ptr, len);
   524    535   
   525    536           if (stmt != IntPtr.Zero) cmd = new SQLiteStatement(this, flags, stmt, strSql.Substring(0, strSql.Length - strRemain.Length), previous);
   526    537   
   527    538           return cmd;
   528    539         }
................................................................................
   619    630               LogBind(handle, index, value);
   620    631           }
   621    632   
   622    633           int n = UnsafeNativeMethods.sqlite3_bind_double(handle, index, value);
   623    634   #else
   624    635           int n = UnsafeNativeMethods.sqlite3_bind_double_interop(handle, index, ref value);
   625    636   #endif
   626         -        if (n > 0) throw new SQLiteException(n, SQLiteLastError());
          637  +        if (n > 0) throw new SQLiteException(n, GetLastError());
   627    638       }
   628    639   
   629    640       internal override void Bind_Int32(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, int value)
   630    641       {
   631    642           SQLiteStatementHandle handle = stmt._sqlite_stmt;
   632    643   
   633    644   #if !PLATFORM_COMPACTFRAMEWORK
................................................................................
   634    645           if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind)
   635    646           {
   636    647               LogBind(handle, index, value);
   637    648           }
   638    649   #endif
   639    650   
   640    651           int n = UnsafeNativeMethods.sqlite3_bind_int(handle, index, value);
   641         -        if (n > 0) throw new SQLiteException(n, SQLiteLastError());
          652  +        if (n > 0) throw new SQLiteException(n, GetLastError());
   642    653       }
   643    654   
   644    655       internal override void Bind_UInt32(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, uint value)
   645    656       {
   646    657           SQLiteStatementHandle handle = stmt._sqlite_stmt;
   647    658   
   648    659   #if !PLATFORM_COMPACTFRAMEWORK
................................................................................
   649    660           if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind)
   650    661           {
   651    662               LogBind(handle, index, value);
   652    663           }
   653    664   #endif
   654    665   
   655    666           int n = UnsafeNativeMethods.sqlite3_bind_uint(handle, index, value);
   656         -        if (n > 0) throw new SQLiteException(n, SQLiteLastError());
          667  +        if (n > 0) throw new SQLiteException(n, GetLastError());
   657    668       }
   658    669   
   659    670       internal override void Bind_Int64(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, long value)
   660    671       {
   661    672           SQLiteStatementHandle handle = stmt._sqlite_stmt;
   662    673   
   663    674   #if !PLATFORM_COMPACTFRAMEWORK
................................................................................
   666    677               LogBind(handle, index, value);
   667    678           }
   668    679   
   669    680           int n = UnsafeNativeMethods.sqlite3_bind_int64(handle, index, value);
   670    681   #else
   671    682           int n = UnsafeNativeMethods.sqlite3_bind_int64_interop(handle, index, ref value);
   672    683   #endif
   673         -        if (n > 0) throw new SQLiteException(n, SQLiteLastError());
          684  +        if (n > 0) throw new SQLiteException(n, GetLastError());
   674    685       }
   675    686   
   676    687       internal override void Bind_UInt64(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, ulong value)
   677    688       {
   678    689           SQLiteStatementHandle handle = stmt._sqlite_stmt;
   679    690   
   680    691   #if !PLATFORM_COMPACTFRAMEWORK
................................................................................
   683    694               LogBind(handle, index, value);
   684    695           }
   685    696   
   686    697           int n = UnsafeNativeMethods.sqlite3_bind_uint64(handle, index, value);
   687    698   #else
   688    699           int n = UnsafeNativeMethods.sqlite3_bind_uint64_interop(handle, index, ref value);
   689    700   #endif
   690         -        if (n > 0) throw new SQLiteException(n, SQLiteLastError());
          701  +        if (n > 0) throw new SQLiteException(n, GetLastError());
   691    702       }
   692    703   
   693    704       internal override void Bind_Text(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, string value)
   694    705       {
   695    706           SQLiteStatementHandle handle = stmt._sqlite_stmt;
   696    707   
   697    708   #if !PLATFORM_COMPACTFRAMEWORK
................................................................................
   707    718           if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind)
   708    719           {
   709    720               LogBind(handle, index, b);
   710    721           }
   711    722   #endif
   712    723   
   713    724           int n = UnsafeNativeMethods.sqlite3_bind_text(handle, index, b, b.Length - 1, (IntPtr)(-1));
   714         -        if (n > 0) throw new SQLiteException(n, SQLiteLastError());
          725  +        if (n > 0) throw new SQLiteException(n, GetLastError());
   715    726       }
   716    727   
   717    728       internal override void Bind_DateTime(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, DateTime dt)
   718    729       {
   719    730           SQLiteStatementHandle handle = stmt._sqlite_stmt;
   720    731   
   721    732   #if !PLATFORM_COMPACTFRAMEWORK
................................................................................
   737    748                           LogBind(handle, index, value);
   738    749                       }
   739    750   
   740    751                       int n = UnsafeNativeMethods.sqlite3_bind_int64(handle, index, value);
   741    752   #else
   742    753                       int n = UnsafeNativeMethods.sqlite3_bind_int64_interop(handle, index, ref value);
   743    754   #endif
   744         -                    if (n > 0) throw new SQLiteException(n, SQLiteLastError());
          755  +                    if (n > 0) throw new SQLiteException(n, GetLastError());
   745    756                       break;
   746    757                   }
   747    758               case SQLiteDateFormats.JulianDay:
   748    759                   {
   749    760                       double value = ToJulianDay(dt);
   750    761   
   751    762   #if !PLATFORM_COMPACTFRAMEWORK
................................................................................
   754    765                           LogBind(handle, index, value);
   755    766                       }
   756    767   
   757    768                       int n = UnsafeNativeMethods.sqlite3_bind_double(handle, index, value);
   758    769   #else
   759    770                       int n = UnsafeNativeMethods.sqlite3_bind_double_interop(handle, index, ref value);
   760    771   #endif
   761         -                    if (n > 0) throw new SQLiteException(n, SQLiteLastError());
          772  +                    if (n > 0) throw new SQLiteException(n, GetLastError());
   762    773                       break;
   763    774                   }
   764    775               case SQLiteDateFormats.UnixEpoch:
   765    776                   {
   766    777                       long value = Convert.ToInt64(dt.Subtract(UnixEpoch).TotalSeconds);
   767    778   
   768    779   #if !PLATFORM_COMPACTFRAMEWORK
................................................................................
   771    782                           LogBind(handle, index, value);
   772    783                       }
   773    784   
   774    785                       int n = UnsafeNativeMethods.sqlite3_bind_int64(handle, index, value);
   775    786   #else
   776    787                       int n = UnsafeNativeMethods.sqlite3_bind_int64_interop(handle, index, ref value);
   777    788   #endif
   778         -                    if (n > 0) throw new SQLiteException(n, SQLiteLastError());
          789  +                    if (n > 0) throw new SQLiteException(n, GetLastError());
   779    790                       break;
   780    791                   }
   781    792               default:
   782    793                   {
   783    794                       byte[] b = ToUTF8(dt);
   784    795   
   785    796   #if !PLATFORM_COMPACTFRAMEWORK
................................................................................
   786    797                       if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind)
   787    798                       {
   788    799                           LogBind(handle, index, b);
   789    800                       }
   790    801   #endif
   791    802   
   792    803                       int n = UnsafeNativeMethods.sqlite3_bind_text(handle, index, b, b.Length - 1, (IntPtr)(-1));
   793         -                    if (n > 0) throw new SQLiteException(n, SQLiteLastError());
          804  +                    if (n > 0) throw new SQLiteException(n, GetLastError());
   794    805                       break;
   795    806                   }
   796    807           }
   797    808       }
   798    809   
   799    810       internal override void Bind_Blob(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, byte[] blobData)
   800    811       {
................................................................................
   804    815           if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind)
   805    816           {
   806    817               LogBind(handle, index, blobData);
   807    818           }
   808    819   #endif
   809    820   
   810    821           int n = UnsafeNativeMethods.sqlite3_bind_blob(handle, index, blobData, blobData.Length, (IntPtr)(-1));
   811         -        if (n > 0) throw new SQLiteException(n, SQLiteLastError());
          822  +        if (n > 0) throw new SQLiteException(n, GetLastError());
   812    823       }
   813    824   
   814    825       internal override void Bind_Null(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index)
   815    826       {
   816    827           SQLiteStatementHandle handle = stmt._sqlite_stmt;
   817    828   
   818    829   #if !PLATFORM_COMPACTFRAMEWORK
................................................................................
   819    830           if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind)
   820    831           {
   821    832               LogBind(handle, index);
   822    833           }
   823    834   #endif
   824    835   
   825    836           int n = UnsafeNativeMethods.sqlite3_bind_null(handle, index);
   826         -        if (n > 0) throw new SQLiteException(n, SQLiteLastError());
          837  +        if (n > 0) throw new SQLiteException(n, GetLastError());
   827    838       }
   828    839   
   829    840       internal override int Bind_ParamCount(SQLiteStatement stmt, SQLiteConnectionFlags flags)
   830    841       {
   831    842           SQLiteStatementHandle handle = stmt._sqlite_stmt;
   832    843           int value = UnsafeNativeMethods.sqlite3_bind_parameter_count(handle);
   833    844   
................................................................................
  1003   1014         n = UnsafeNativeMethods.sqlite3_table_column_metadata_interop(_sql, ToUTF8(dataBase), ToUTF8(table), ToUTF8(column), out dataTypePtr, out collSeqPtr, out nnotNull, out nprimaryKey, out nautoInc, out dtLen, out csLen);
  1004   1015   #else
  1005   1016         dtLen = -1;
  1006   1017         csLen = -1;
  1007   1018   
  1008   1019         n = UnsafeNativeMethods.sqlite3_table_column_metadata(_sql, ToUTF8(dataBase), ToUTF8(table), ToUTF8(column), out dataTypePtr, out collSeqPtr, out nnotNull, out nprimaryKey, out nautoInc);
  1009   1020   #endif
  1010         -      if (n > 0) throw new SQLiteException(n, SQLiteLastError());
         1021  +      if (n > 0) throw new SQLiteException(n, GetLastError());
  1011   1022   
  1012   1023         dataType = UTF8ToString(dataTypePtr, dtLen);
  1013   1024         collateSequence = UTF8ToString(collSeqPtr, csLen);
  1014   1025   
  1015   1026         notNull = (nnotNull == 1);
  1016   1027         primaryKey = (nprimaryKey == 1);
  1017   1028         autoIncrement = (nautoInc == 1);
................................................................................
  1127   1138   #if !SQLITE_STANDARD
  1128   1139         n = UnsafeNativeMethods.sqlite3_create_function_interop(_sql, ToUTF8(strFunction), nArgs, 4, IntPtr.Zero, func, funcstep, funcfinal, (needCollSeq == true) ? 1 : 0);
  1129   1140         if (n == 0) n = UnsafeNativeMethods.sqlite3_create_function_interop(_sql, ToUTF8(strFunction), nArgs, 1, IntPtr.Zero, func, funcstep, funcfinal, (needCollSeq == true) ? 1 : 0);
  1130   1141   #else
  1131   1142         n = UnsafeNativeMethods.sqlite3_create_function(_sql, ToUTF8(strFunction), nArgs, 4, IntPtr.Zero, func, funcstep, funcfinal);
  1132   1143         if (n == 0) n = UnsafeNativeMethods.sqlite3_create_function(_sql, ToUTF8(strFunction), nArgs, 1, IntPtr.Zero, func, funcstep, funcfinal);
  1133   1144   #endif
  1134         -      if (n > 0) throw new SQLiteException(n, SQLiteLastError());
         1145  +      if (n > 0) throw new SQLiteException(n, GetLastError());
  1135   1146       }
  1136   1147   
  1137   1148       internal override void CreateCollation(string strCollation, SQLiteCollation func, SQLiteCollation func16)
  1138   1149       {
  1139   1150         int n = UnsafeNativeMethods.sqlite3_create_collation(_sql, ToUTF8(strCollation), 2, IntPtr.Zero, func16);
  1140   1151         if (n == 0) n = UnsafeNativeMethods.sqlite3_create_collation(_sql, ToUTF8(strCollation), 1, IntPtr.Zero, func);
  1141         -      if (n > 0) throw new SQLiteException(n, SQLiteLastError());
         1152  +      if (n > 0) throw new SQLiteException(n, GetLastError());
  1142   1153       }
  1143   1154   
  1144   1155       internal override int ContextCollateCompare(CollationEncodingEnum enc, IntPtr context, string s1, string s2)
  1145   1156       {
  1146   1157   #if !SQLITE_STANDARD
  1147   1158         byte[] b1;
  1148   1159         byte[] b2;
................................................................................
  1358   1369         UnsafeNativeMethods.sqlite3_log(iErrCode, ToUTF8(zMessage));
  1359   1370       }
  1360   1371   
  1361   1372   #if INTEROP_CODEC
  1362   1373       internal override void SetPassword(byte[] passwordBytes)
  1363   1374       {
  1364   1375         int n = UnsafeNativeMethods.sqlite3_key(_sql, passwordBytes, passwordBytes.Length);
  1365         -      if (n > 0) throw new SQLiteException(n, SQLiteLastError());
         1376  +      if (n > 0) throw new SQLiteException(n, GetLastError());
  1366   1377       }
  1367   1378   
  1368   1379       internal override void ChangePassword(byte[] newPasswordBytes)
  1369   1380       {
  1370   1381         int n = UnsafeNativeMethods.sqlite3_rekey(_sql, newPasswordBytes, (newPasswordBytes == null) ? 0 : newPasswordBytes.Length);
  1371         -      if (n > 0) throw new SQLiteException(n, SQLiteLastError());
         1382  +      if (n > 0) throw new SQLiteException(n, GetLastError());
  1372   1383       }
  1373   1384   #endif
  1374   1385   
  1375   1386       internal override void SetUpdateHook(SQLiteUpdateCallback func)
  1376   1387       {
  1377   1388         UnsafeNativeMethods.sqlite3_update_hook(_sql, func, IntPtr.Zero);
  1378   1389       }
................................................................................
  1457   1468           byte[] zDestName = ToUTF8(destName);
  1458   1469           byte[] zSourceName = ToUTF8(sourceName);
  1459   1470   
  1460   1471           IntPtr backup = UnsafeNativeMethods.sqlite3_backup_init(
  1461   1472               destHandle, zDestName, sourceHandle, zSourceName);
  1462   1473   
  1463   1474           if (backup == IntPtr.Zero)
  1464         -            throw new SQLiteException(ResultCode(), SQLiteLastError());
         1475  +            throw new SQLiteException(ResultCode(), GetLastError());
  1465   1476   
  1466   1477           return new SQLiteBackup(
  1467   1478               this, backup, destHandle, zDestName, sourceHandle, zSourceName);
  1468   1479       }
  1469   1480   
  1470   1481       /// <summary>
  1471   1482       /// Copies up to N pages from the source database to the destination
................................................................................
  1518   1529           }
  1519   1530           else if (n == (int)SQLiteErrorCode.Done)
  1520   1531           {
  1521   1532               return false;
  1522   1533           }
  1523   1534           else
  1524   1535           {
  1525         -            throw new SQLiteException(n, SQLiteLastError());
         1536  +            throw new SQLiteException(n, GetLastError());
  1526   1537           }
  1527   1538       }
  1528   1539   
  1529   1540       /// <summary>
  1530   1541       /// Returns the number of pages remaining to be copied from the source
  1531   1542       /// database to the destination database associated with the specified
  1532   1543       /// backup object.
................................................................................
  1589   1600               throw new InvalidOperationException(
  1590   1601                   "Backup object has an invalid handle.");
  1591   1602   
  1592   1603           int n = UnsafeNativeMethods.sqlite3_backup_finish(handle);
  1593   1604           handle.SetHandleAsInvalid();
  1594   1605   
  1595   1606           if ((n > 0) && (n != backup._stepResult))
  1596         -            throw new SQLiteException(n, SQLiteLastError());
         1607  +            throw new SQLiteException(n, GetLastError());
  1597   1608       }
  1598   1609   
  1599   1610       ///////////////////////////////////////////////////////////////////////////////////////////////
  1600   1611   
  1601   1612       /// <summary>
  1602   1613       /// Determines if the SQLite core library has been initialized for the
  1603   1614       /// current process.

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

   165    165           if ((flags & SQLiteConnectionFlags.LogBind) == SQLiteConnectionFlags.LogBind)
   166    166           {
   167    167               LogBind(handle, index, value);
   168    168           }
   169    169   #endif
   170    170   
   171    171           int n = UnsafeNativeMethods.sqlite3_bind_text16(handle, index, value, value.Length * 2, (IntPtr)(-1));
   172         -        if (n > 0) throw new SQLiteException(n, SQLiteLastError());
          172  +        if (n > 0) throw new SQLiteException(n, GetLastError());
   173    173       }
   174    174   
   175    175       internal override DateTime GetDateTime(SQLiteStatement stmt, int index)
   176    176       {
   177    177         return ToDateTime(GetText(stmt, index));
   178    178       }
   179    179   

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

    14     14     /// a SQLite data provider, and inherits from SQLiteConvert which allows for simple translations of string to and from SQLite.
    15     15     /// </summary>
    16     16     internal abstract class SQLiteBase : SQLiteConvert, IDisposable
    17     17     {
    18     18       internal SQLiteBase(SQLiteDateFormats fmt, DateTimeKind kind)
    19     19         : base(fmt, kind) { }
    20     20   
    21         -    static internal object _lock = new object();
    22         -
    23     21       /// <summary>
    24     22       /// Returns a string representing the active version of SQLite
    25     23       /// </summary>
    26     24       internal abstract string Version { get; }
    27     25       /// <summary>
    28     26       /// Returns the rowid of the most recent successful INSERT into the database from this connection.
    29     27       /// </summary>
................................................................................
    76     74       /// </summary>
    77     75       /// <param name="nTimeoutMS">The number of milliseconds to wait before returning SQLITE_BUSY</param>
    78     76       internal abstract void SetTimeout(int nTimeoutMS);
    79     77       /// <summary>
    80     78       /// Returns the text of the last error issued by SQLite
    81     79       /// </summary>
    82     80       /// <returns></returns>
    83         -    internal abstract string SQLiteLastError();
           81  +    internal abstract string GetLastError();
    84     82   
    85     83       /// <summary>
    86     84       /// When pooling is enabled, force this connection to be disposed rather than returned to the pool
    87     85       /// </summary>
    88     86       internal abstract void ClearPool();
    89     87   
           88  +    /// <summary>
           89  +    /// When pooling is enabled, returns the number of pool entries matching the current file name.
           90  +    /// </summary>
           91  +    /// <returns>The number of pool entries matching the current file name.</returns>
           92  +    internal abstract int CountPool();
           93  +
    90     94       /// <summary>
    91     95       /// Prepares a SQL statement for execution.
    92     96       /// </summary>
    93     97       /// <param name="cnn">The source connection preparing the command.  Can be null for any caller except LINQ</param>
    94     98       /// <param name="strSql">The SQL command text to prepare</param>
    95     99       /// <param name="previous">The previous statement in a multi-statement command, or null if no previous statement exists</param>
    96    100       /// <param name="timeoutMS">The timeout to wait before aborting the prepare</param>
................................................................................
   336    340       ///////////////////////////////////////////////////////////////////////////////////////////////
   337    341   
   338    342       // These statics are here for lack of a better place to put them.
   339    343       // They exist here because they are called during the finalization of
   340    344       // a SQLiteStatementHandle, SQLiteConnectionHandle, and SQLiteFunctionCookieHandle.
   341    345       // Therefore these functions have to be static, and have to be low-level.
   342    346   
   343         -    internal static string SQLiteLastError(SQLiteConnectionHandle db)
          347  +    internal static string GetLastError(SQLiteConnectionHandle hdl, IntPtr db)
   344    348       {
          349  +        if ((hdl == null) || (db == IntPtr.Zero))
          350  +            return "invalid connection or database handle";
          351  +
          352  +        lock (hdl)
          353  +        {
   345    354   #if !SQLITE_STANDARD
   346         -      int len;
   347         -      return UTF8ToString(UnsafeNativeMethods.sqlite3_errmsg_interop(db, out len), len);
          355  +            int len;
          356  +            return UTF8ToString(UnsafeNativeMethods.sqlite3_errmsg_interop(db, out len), len);
   348    357   #else
   349         -      return UTF8ToString(UnsafeNativeMethods.sqlite3_errmsg(db), -1);
          358  +            return UTF8ToString(UnsafeNativeMethods.sqlite3_errmsg(db), -1);
   350    359   #endif
   351         -    }
   352         -
   353         -    internal static void FinishBackup(SQLiteBackupHandle backup)
   354         -    {
   355         -        lock (_lock)
   356         -        {
   357         -            int n = UnsafeNativeMethods.sqlite3_backup_finish(backup);
   358         -            backup.SetHandleAsInvalid();
   359         -            if (n > 0) throw new SQLiteException(n, null);
   360    360           }
   361    361       }
   362    362   
   363         -    internal static void FinalizeStatement(SQLiteStatementHandle stmt)
          363  +    internal static void FinishBackup(IntPtr backup)
          364  +    {
          365  +        if (backup == IntPtr.Zero) return;
          366  +        int n = UnsafeNativeMethods.sqlite3_backup_finish(backup);
          367  +        if (n > 0) throw new SQLiteException(n, null);
          368  +    }
          369  +
          370  +    internal static void FinalizeStatement(IntPtr stmt)
   364    371       {
   365         -      lock (_lock)
   366         -      {
          372  +        if (stmt == IntPtr.Zero) return;
   367    373   #if !SQLITE_STANDARD
   368    374           int n = UnsafeNativeMethods.sqlite3_finalize_interop(stmt);
   369    375   #else
   370         -      int n = UnsafeNativeMethods.sqlite3_finalize(stmt);
          376  +        int n = UnsafeNativeMethods.sqlite3_finalize(stmt);
   371    377   #endif
   372    378           if (n > 0) throw new SQLiteException(n, null);
   373         -      }
   374    379       }
   375    380   
   376         -    internal static void CloseConnection(SQLiteConnectionHandle db)
          381  +    internal static void CloseConnection(SQLiteConnectionHandle hdl, IntPtr db)
   377    382       {
   378         -      lock (_lock)
   379         -      {
          383  +        if ((hdl == null) || (db == IntPtr.Zero)) return;
          384  +        lock (hdl)
          385  +        {
   380    386   #if !SQLITE_STANDARD
   381         -        int n = UnsafeNativeMethods.sqlite3_close_interop(db);
          387  +            int n = UnsafeNativeMethods.sqlite3_close_interop(db);
   382    388   #else
   383         -      ResetConnection(db);
   384         -      int n = UnsafeNativeMethods.sqlite3_close(db);
          389  +            ResetConnection(hdl, db);
          390  +            int n = UnsafeNativeMethods.sqlite3_close(db);
   385    391   #endif
   386         -        if (n > 0) throw new SQLiteException(n, SQLiteLastError(db));
   387         -      }
          392  +            if (n > 0) throw new SQLiteException(n, GetLastError(hdl, db));
          393  +        }
   388    394       }
   389    395   
   390         -    internal static void ResetConnection(SQLiteConnectionHandle db)
          396  +    internal static void ResetConnection(SQLiteConnectionHandle hdl, IntPtr db)
   391    397       {
   392         -      lock (_lock)
   393         -      {
   394         -        IntPtr stmt = IntPtr.Zero;
   395         -        int n;
   396         -        do
          398  +        if ((hdl == null) || (db == IntPtr.Zero)) return;
          399  +        lock (hdl)
   397    400           {
   398         -          stmt = UnsafeNativeMethods.sqlite3_next_stmt(db, stmt);
   399         -          if (stmt != IntPtr.Zero)
   400         -          {
          401  +            IntPtr stmt = IntPtr.Zero;
          402  +            int n;
          403  +            do
          404  +            {
          405  +                stmt = UnsafeNativeMethods.sqlite3_next_stmt(db, stmt);
          406  +                if (stmt != IntPtr.Zero)
          407  +                {
   401    408   #if !SQLITE_STANDARD
   402         -            n = UnsafeNativeMethods.sqlite3_reset_interop(stmt);
          409  +                    n = UnsafeNativeMethods.sqlite3_reset_interop(stmt);
   403    410   #else
   404         -            n = UnsafeNativeMethods.sqlite3_reset(stmt);
          411  +                    n = UnsafeNativeMethods.sqlite3_reset(stmt);
   405    412   #endif
   406         -          }
   407         -        } while (stmt != IntPtr.Zero);
          413  +                }
          414  +            } while (stmt != IntPtr.Zero);
   408    415   
   409         -        if (IsAutocommit(db) == false) // a transaction is pending on the connection
   410         -        {
   411         -          n = UnsafeNativeMethods.sqlite3_exec(db, ToUTF8("ROLLBACK"), IntPtr.Zero, IntPtr.Zero, out stmt);
   412         -          if (n > 0) throw new SQLiteException(n, SQLiteLastError(db));
          416  +            if (IsAutocommit(db) == false) // a transaction is pending on the connection
          417  +            {
          418  +                n = UnsafeNativeMethods.sqlite3_exec(db, ToUTF8("ROLLBACK"), IntPtr.Zero, IntPtr.Zero, out stmt);
          419  +                if (n > 0) throw new SQLiteException(n, GetLastError(hdl, db));
          420  +            }
   413    421           }
   414         -      }
   415    422       }
   416    423   
   417         -    internal static bool IsAutocommit(SQLiteConnectionHandle hdl)
          424  +    internal static bool IsAutocommit(IntPtr db)
   418    425       {
   419         -      return (UnsafeNativeMethods.sqlite3_get_autocommit(hdl) == 1);
          426  +      if (db == IntPtr.Zero) return false;
          427  +      return (UnsafeNativeMethods.sqlite3_get_autocommit(db) == 1);
   420    428       }
   421    429   
   422    430     }
   423    431   
   424    432     internal interface ISQLiteSchemaExtensions
   425    433     {
   426    434       void BuildTempSchema(SQLiteConnection cnn);

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

   668    668             _sql.Close();
   669    669             _sql = null;
   670    670           }
   671    671           _transactionLevel = 0;
   672    672         }
   673    673         OnStateChange(ConnectionState.Closed);
   674    674       }
          675  +
          676  +    /// <summary>
          677  +    /// Returns the number of pool entries for the file name associated with this connection.
          678  +    /// </summary>
          679  +    public int PoolCount
          680  +    {
          681  +        get
          682  +        {
          683  +            if (_sql == null) return 0;
          684  +            return _sql.CountPool();
          685  +        }
          686  +    }
   675    687   
   676    688       /// <summary>
   677    689       /// Clears the connection pool associated with the connection.  Any other active connections using the same database file
   678    690       /// will be discarded instead of returned to the pool when they are closed.
   679    691       /// </summary>
   680    692       /// <param name="connection"></param>
   681    693       public static void ClearPool(SQLiteConnection connection)

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

    34     34       /// </summary>
    35     35       private static SortedList<string, Pool> _connections = new SortedList<string, Pool>(StringComparer.OrdinalIgnoreCase);
    36     36   
    37     37       /// <summary>
    38     38       /// The default version number new pools will get
    39     39       /// </summary>
    40     40       private static int _poolVersion = 1;
           41  +
           42  +    /// <summary>
           43  +    /// Counts the number of pool entries matching the specified file name.
           44  +    /// </summary>
           45  +    /// <param name="fileName">The file name to match or null to match all files.</param>
           46  +    /// <param name="counts">The pool entry counts for each matching file.</param>
           47  +    /// <param name="totalCount">The total number of pool entries for all matching files.</param>
           48  +    internal static void GetCounts(
           49  +        string fileName,
           50  +        ref Dictionary<string, int> counts,
           51  +        ref int totalCount
           52  +        )
           53  +    {
           54  +        lock (_connections)
           55  +        {
           56  +            if (counts == null)
           57  +            {
           58  +                counts = new Dictionary<string, int>(
           59  +                    StringComparer.OrdinalIgnoreCase);
           60  +            }
           61  +
           62  +            if (fileName != null)
           63  +            {
           64  +                Pool queue;
           65  +
           66  +                if (_connections.TryGetValue(fileName, out queue))
           67  +                {
           68  +                    Queue<WeakReference> poolQueue = queue.Queue;
           69  +                    int count = (poolQueue != null) ? poolQueue.Count : 0;
           70  +
           71  +                    counts.Add(fileName, count);
           72  +                    totalCount += count;
           73  +                }
           74  +            }
           75  +            else
           76  +            {
           77  +                foreach (KeyValuePair<string, Pool> pair in _connections)
           78  +                {
           79  +                    if (pair.Value == null)
           80  +                        continue;
           81  +
           82  +                    Queue<WeakReference> poolQueue = pair.Value.Queue;
           83  +                    int count = (poolQueue != null) ? poolQueue.Count : 0;
           84  +
           85  +                    counts.Add(pair.Key, count);
           86  +                    totalCount += count;
           87  +                }
           88  +            }
           89  +        }
           90  +    }
    41     91   
    42     92       /// <summary>
    43     93       /// Attempt to pull a pooled connection out of the queue for active duty
    44     94       /// </summary>
    45     95       /// <param name="fileName">The filename for a desired connection</param>
    46     96       /// <param name="maxPoolSize">The maximum size the connection pool for the filename can be</param>
    47     97       /// <param name="version">The pool version the returned connection will belong to</param>
................................................................................
    69    119           // We found a pool for this file, so use its version number
    70    120           version = queue.PoolVersion;
    71    121           queue.MaxPoolSize = maxPoolSize;
    72    122   
    73    123           ResizePool(queue, false);
    74    124   
    75    125           // Try and get a pooled connection from the queue
    76         -        while (queue.Queue.Count > 0)
          126  +        Queue<WeakReference> poolQueue = queue.Queue;
          127  +        if (poolQueue == null) return null;
          128  +
          129  +        while (poolQueue.Count > 0)
    77    130           {
    78         -          WeakReference cnn = queue.Queue.Dequeue();
          131  +          WeakReference cnn = poolQueue.Dequeue();
    79    132             SQLiteConnectionHandle hdl = cnn.Target as SQLiteConnectionHandle;
    80         -          if (hdl != null)
          133  +          if ((hdl != null) && !hdl.IsClosed && !hdl.IsInvalid)
    81    134             {
    82    135               return hdl;
    83    136             }
          137  +          GC.KeepAlive(hdl);
    84    138           }
    85    139           return null;
    86    140         }
    87    141       }
    88    142   
    89    143       /// <summary>
    90    144       /// Clears out all pooled connections and rev's up the default pool version to force all old active objects
................................................................................
   100    154             {
   101    155               WeakReference cnn = pair.Value.Queue.Dequeue();
   102    156               SQLiteConnectionHandle hdl = cnn.Target as SQLiteConnectionHandle;
   103    157               if (hdl != null)
   104    158               {
   105    159                 hdl.Dispose();
   106    160               }
          161  +            GC.KeepAlive(hdl);
   107    162             }
   108    163             
   109    164             // Keep track of the highest revision so we can go one higher when we're finished
   110    165             if (_poolVersion <= pair.Value.PoolVersion)
   111    166               _poolVersion = pair.Value.PoolVersion + 1;
   112    167           }
   113    168           // All pools are cleared and we have a new highest version number to force all old version active items to get discarded
................................................................................
   127    182       {
   128    183         lock (_connections)
   129    184         {
   130    185           Pool queue;
   131    186           if (_connections.TryGetValue(fileName, out queue) == true)
   132    187           {
   133    188             queue.PoolVersion++;
   134         -          while (queue.Queue.Count > 0)
          189  +
          190  +          Queue<WeakReference> poolQueue = queue.Queue;
          191  +          if (poolQueue == null) return;
          192  +
          193  +          while (poolQueue.Count > 0)
   135    194             {
   136         -            WeakReference cnn = queue.Queue.Dequeue();
          195  +            WeakReference cnn = poolQueue.Dequeue();
   137    196               SQLiteConnectionHandle hdl = cnn.Target as SQLiteConnectionHandle;
   138    197               if (hdl != null)
   139    198               {
   140    199                 hdl.Dispose();
   141    200               }
          201  +            GC.KeepAlive(hdl);
   142    202             }
   143    203           }
   144    204         }
   145    205       }
   146    206   
   147    207       /// <summary>
   148    208       /// Return a connection to the pool for someone else to use.
................................................................................
   158    218         lock (_connections)
   159    219         {
   160    220           // If the queue doesn't exist in the pool, then it must've been cleared sometime after the connection was created.
   161    221           Pool queue;
   162    222           if (_connections.TryGetValue(fileName, out queue) == true && version == queue.PoolVersion)
   163    223           {
   164    224             ResizePool(queue, true);
   165         -          queue.Queue.Enqueue(new WeakReference(hdl, false));
          225  +
          226  +          Queue<WeakReference> poolQueue = queue.Queue;
          227  +          if (poolQueue == null) return;
          228  +
          229  +          poolQueue.Enqueue(new WeakReference(hdl, false));
   166    230             GC.KeepAlive(hdl);
   167    231           }
   168    232           else
   169    233           {
   170    234             hdl.Close();
   171    235           }
   172    236         }
................................................................................
   181    245       /// to take one more than it needs from the pool</param>
   182    246       private static void ResizePool(Pool queue, bool forAdding)
   183    247       {
   184    248         int target = queue.MaxPoolSize;
   185    249   
   186    250         if (forAdding && target > 0) target--;
   187    251   
   188         -      while (queue.Queue.Count > target)
          252  +      Queue<WeakReference> poolQueue = queue.Queue;
          253  +      if (poolQueue == null) return;
          254  +
          255  +      while (poolQueue.Count > target)
   189    256         {
   190         -        WeakReference cnn = queue.Queue.Dequeue();
          257  +        WeakReference cnn = poolQueue.Dequeue();
   191    258           SQLiteConnectionHandle hdl = cnn.Target as SQLiteConnectionHandle;
   192    259           if (hdl != null)
   193    260           {
   194    261             hdl.Dispose();
   195    262           }
          263  +        GC.KeepAlive(hdl);
   196    264         }
   197    265       }
   198    266     }
   199    267   }

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

    19     19   #endif
    20     20   
    21     21   #if !PLATFORM_COMPACTFRAMEWORK && !DEBUG
    22     22     using System.Security;
    23     23   #endif
    24     24   
    25     25     using System.Runtime.InteropServices;
           26  +
           27  +#if !PLATFORM_COMPACTFRAMEWORK
           28  +  using System.Threading;
           29  +#endif
    26     30   
    27     31   #if !PLATFORM_COMPACTFRAMEWORK && !DEBUG
    28     32     [SuppressUnmanagedCodeSecurity]
    29     33   #endif
    30     34     internal static class UnsafeNativeMethods
    31     35     {
    32     36         #region Optional Native SQLite Library Pre-Loading Code
................................................................................
  1380   1384       {
  1381   1385       }
  1382   1386   
  1383   1387       protected override bool ReleaseHandle()
  1384   1388       {
  1385   1389         try
  1386   1390         {
  1387         -        SQLiteBase.CloseConnection(this);
         1391  +#if !PLATFORM_COMPACTFRAMEWORK
         1392  +        IntPtr localHandle = Interlocked.Exchange(
         1393  +          ref handle, IntPtr.Zero);
         1394  +
         1395  +        if (localHandle != IntPtr.Zero)
         1396  +          SQLiteBase.CloseConnection(this, localHandle);
  1388   1397   
  1389   1398   #if DEBUG && !NET_COMPACT_20
  1390   1399           try
  1391   1400           {
  1392   1401             Trace.WriteLine(String.Format(
  1393         -              "CloseConnection: {0}", handle));
         1402  +              "CloseConnection: {0}", localHandle));
  1394   1403           }
  1395   1404           catch
  1396   1405           {
  1397   1406           }
  1398   1407   #endif
         1408  +#else
         1409  +        if (handle != IntPtr.Zero)
         1410  +        {
         1411  +          SQLiteBase.CloseConnection(this, handle);
         1412  +          SetHandle(IntPtr.Zero);
         1413  +        }
         1414  +#endif
  1399   1415   
  1400   1416   #if DEBUG
  1401   1417           return true;
  1402   1418   #endif
  1403   1419         }
  1404   1420   #if DEBUG && !NET_COMPACT_20
  1405   1421         catch (SQLiteException e)
................................................................................
  1415   1431                 handle, e));
  1416   1432           }
  1417   1433           catch
  1418   1434           {
  1419   1435           }
  1420   1436   #endif
  1421   1437         }
         1438  +      finally
         1439  +      {
         1440  +        SetHandleAsInvalid();
         1441  +      }
  1422   1442   #if DEBUG
  1423   1443         return false;
  1424   1444   #else
  1425   1445         return true;
  1426   1446   #endif
  1427   1447       }
  1428   1448   
................................................................................
  1463   1483       {
  1464   1484       }
  1465   1485   
  1466   1486       protected override bool ReleaseHandle()
  1467   1487       {
  1468   1488         try
  1469   1489         {
  1470         -        SQLiteBase.FinalizeStatement(this);
         1490  +#if !PLATFORM_COMPACTFRAMEWORK
         1491  +        IntPtr localHandle = Interlocked.Exchange(
         1492  +          ref handle, IntPtr.Zero);
         1493  +
         1494  +        if (localHandle != IntPtr.Zero)
         1495  +          SQLiteBase.FinalizeStatement(localHandle);
  1471   1496   
  1472   1497   #if DEBUG && !NET_COMPACT_20
  1473   1498           try
  1474   1499           {
  1475   1500             Trace.WriteLine(String.Format(
  1476         -              "FinalizeStatement: {0}", handle));
         1501  +              "FinalizeStatement: {0}", localHandle));
  1477   1502           }
  1478   1503           catch
  1479   1504           {
  1480   1505           }
  1481   1506   #endif
         1507  +#else
         1508  +        if (handle != IntPtr.Zero)
         1509  +        {
         1510  +          SQLiteBase.FinalizeStatement(handle);
         1511  +          SetHandle(IntPtr.Zero);
         1512  +        }
         1513  +#endif
  1482   1514   
  1483   1515   #if DEBUG
  1484   1516           return true;
  1485   1517   #endif
  1486   1518         }
  1487   1519   #if DEBUG && !NET_COMPACT_20
  1488   1520         catch (SQLiteException e)
................................................................................
  1498   1530                 handle, e));
  1499   1531           }
  1500   1532           catch
  1501   1533           {
  1502   1534           }
  1503   1535   #endif
  1504   1536         }
         1537  +      finally
         1538  +      {
         1539  +        SetHandleAsInvalid();
         1540  +      }
  1505   1541   #if DEBUG
  1506   1542         return false;
  1507   1543   #else
  1508   1544         return true;
  1509   1545   #endif
  1510   1546       }
  1511   1547   
................................................................................
  1546   1582         {
  1547   1583         }
  1548   1584   
  1549   1585         protected override bool ReleaseHandle()
  1550   1586         {
  1551   1587             try
  1552   1588             {
  1553         -              SQLiteBase.FinishBackup(this);
         1589  +#if !PLATFORM_COMPACTFRAMEWORK
         1590  +              IntPtr localHandle = Interlocked.Exchange(
         1591  +                  ref handle, IntPtr.Zero);
         1592  +
         1593  +              if (localHandle != IntPtr.Zero)
         1594  +                  SQLiteBase.FinishBackup(localHandle);
  1554   1595   
  1555   1596   #if DEBUG && !NET_COMPACT_20
  1556   1597                 try
  1557   1598                 {
  1558   1599                     Trace.WriteLine(String.Format(
  1559         -                      "FinishBackup: {0}", handle));
         1600  +                      "FinishBackup: {0}", localHandle));
  1560   1601                 }
  1561   1602                 catch
  1562   1603                 {
  1563   1604                 }
  1564   1605   #endif
         1606  +#else
         1607  +              if (handle != IntPtr.Zero)
         1608  +              {
         1609  +                SQLiteBase.FinishBackup(handle);
         1610  +                SetHandle(IntPtr.Zero);
         1611  +              }
         1612  +#endif
  1565   1613   
  1566   1614   #if DEBUG
  1567   1615                 return true;
  1568   1616   #endif
  1569   1617             }
  1570   1618   #if DEBUG && !NET_COMPACT_20
  1571   1619             catch (SQLiteException e)
................................................................................
  1581   1629                         handle, e));
  1582   1630                 }
  1583   1631                 catch
  1584   1632                 {
  1585   1633                 }
  1586   1634   #endif
  1587   1635             }
         1636  +          finally
         1637  +          {
         1638  +              SetHandleAsInvalid();
         1639  +          }
  1588   1640   #if DEBUG
  1589   1641             return false;
  1590   1642   #else
  1591   1643             return true;
  1592   1644   #endif
  1593   1645         }
  1594   1646   

Changes to Tests/basic.eagle.

    20     20   
    21     21   ###############################################################################
    22     22   
    23     23   #
    24     24   # NOTE: Setup the variables that refer to the various files required by the
    25     25   #       tests in this file.
    26     26   #
           27  +set systemDataSQLiteDllFile [getBuildFileName System.Data.SQLite.dll]
           28  +set systemDataSQLiteLinqDllFile [getBuildFileName System.Data.SQLite.Linq.dll]
    27     29   set testExeFile [getBuildFileName test.exe]
    28     30   set testLinqExeFile [getBuildFileName testlinq.exe]
    29     31   set testLinqOutFile [file nativename [file join $path testlinq.out]]
    30     32   set northwindEfDbFile [file nativename [file join [file dirname $path] \
    31     33       testlinq northwindEF.db]]
    32     34   
    33     35   #
    34     36   # NOTE: Setup the test constraints specific to the tests in this file.
    35     37   #
           38  +if {![haveConstraint [appendArgs file_ \
           39  +    [file tail $systemDataSQLiteDllFile]]]} then {
           40  +  checkForFile $test_channel $systemDataSQLiteDllFile
           41  +}
           42  +
           43  +if {![haveConstraint [appendArgs file_ \
           44  +    [file tail $systemDataSQLiteLinqDllFile]]]} then {
           45  +  checkForFile $test_channel $systemDataSQLiteLinqDllFile
           46  +}
           47  +
    36     48   if {![haveConstraint [appendArgs file_ [file tail $testExeFile]]]} then {
    37     49     checkForFile $test_channel $testExeFile
    38     50   }
    39     51   
    40     52   if {![haveConstraint [appendArgs file_ [file tail $testLinqExeFile]]]} then {
    41     53     checkForFile $test_channel $testLinqExeFile
    42     54   }
................................................................................
    74     86     tlog "\n---- END STDOUT OUTPUT\n"
    75     87   
    76     88     list $code [expr {$code == 0 ? "" : $error}]
    77     89   } -cleanup {
    78     90     cleanupDb $fileName
    79     91   
    80     92     unset -nocomplain code output error fileName
    81         -} -constraints {eagle file_test.exe} -result {0 {}}}
           93  +} -constraints {eagle file_System.Data.SQLite.dll file_test.exe} -result {0 {}}}
    82     94   
    83     95   ###############################################################################
    84     96   
    85     97   runTest {test data-1.2 {unit tests from the 'testlinq' project} -setup {
    86     98     #
    87     99     # NOTE: Re-copy the reference database file used for this unit test to the
    88    100     #       build directory in case it has been changed by a previous test run.
................................................................................
   113    125     list $code [string equal $output [readFile $testLinqOutFile]] \
   114    126         [expr {$code == 0 ? "" : $error}]
   115    127   } -cleanup {
   116    128     catch {object invoke Console OutputEncoding $savedEncoding}
   117    129   
   118    130     unset -nocomplain code output error savedEncoding encoding
   119    131   } -constraints \
   120         -{eagle monoToDo file_testlinq.exe file_northwindEF.db file_testlinq.out} \
   121         --result {0 True {}}}
          132  +{eagle monoToDo file_System.Data.SQLite.dll file_System.Data.SQLite.Linq.dll\
          133  +file_testlinq.exe file_northwindEF.db file_testlinq.out} -result {0 True {}}}
   122    134   
   123    135   ###############################################################################
   124    136   
   125    137   runTest {test data-1.3 {SELECT scalar/reader, CREATE, INSERT} -setup {
   126    138     setupDb [set fileName data-1.3.db]
   127    139   } -body {
   128    140     set result [list]
................................................................................
  1378   1390         fileName
  1379   1391   } -constraints \
  1380   1392   {eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -result \
  1381   1393   {{26 26} {zebra zebra}}}
  1382   1394   
  1383   1395   ###############################################################################
  1384   1396   
  1385         -unset -nocomplain testExeFile testLinqExeFile northwindEfDbFile testLinqOutFile
         1397  +unset -nocomplain systemDataSQLiteDllFile systemDataSQLiteLinqDllFile \
         1398  +    testExeFile testLinqExeFile northwindEfDbFile testLinqOutFile
  1386   1399   
  1387   1400   ###############################################################################
  1388   1401   
  1389   1402   runSQLiteTestEpilogue
  1390   1403   runTestEpilogue

Changes to Tests/common.eagle.

   803    803           #
   804    804           if {![info exists ::no(sqliteFiles)]} then {
   805    805             #
   806    806             # NOTE: Skip trying to delete any files if we are so instructed.
   807    807             #
   808    808             if {![info exists ::no(deleteSqliteFiles)]} then {
   809    809               tryDeleteAssembly sqlite3.dll
          810  +            removeConstraint file_sqlite3.dll
          811  +
   810    812               tryDeleteAssembly SQLite.Interop.dll
          813  +            removeConstraint file_SQLite.Interop.dll
          814  +
   811    815               tryDeleteAssembly System.Data.SQLite.dll
          816  +            removeConstraint file_System.Data.SQLite.dll
          817  +
   812    818               tryDeleteAssembly System.Data.SQLite.Linq.dll
          819  +            removeConstraint file_System.Data.SQLite.Linq.dll
   813    820             }
   814    821   
   815    822             #
   816    823             # NOTE: Skip trying to copy any files if we are so instructed.
   817    824             #
   818    825             if {![info exists ::no(copySqliteFiles)]} then {
   819    826               tryCopyAssembly sqlite3.dll
................................................................................
   894    901           reportSQLiteResources $::test_channel
   895    902   
   896    903           #
   897    904           # NOTE: Show the active test constraints.
   898    905           #
   899    906           tputs $::test_channel [appendArgs "---- constraints: " \
   900    907               [formatList [lsort [getConstraints]]] \n]
          908  +
          909  +        #
          910  +        # NOTE: Show when our tests actually began (now).
          911  +        #
          912  +        tputs $::test_channel [appendArgs \
          913  +            "---- System.Data.SQLite tests began at " \
          914  +            [clock format [clock seconds]] \n]
   901    915         }
   902    916       }
   903    917   
   904    918       proc runSQLiteTestEpilogue {} {
   905    919         #
   906    920         # NOTE: Skip running our custom epilogue if the main one has been skipped.
   907    921         #
   908    922         if {![info exists ::no(epilogue.eagle)]} then {
          923  +        #
          924  +        # NOTE: Show when our tests actually ended (now).
          925  +        #
          926  +        tputs $::test_channel [appendArgs \
          927  +            "---- System.Data.SQLite tests ended at " \
          928  +            [clock format [clock seconds]] \n]
          929  +
   909    930           #
   910    931           # NOTE: Also report the resource usage after running the tests.
   911    932           #
   912    933           reportSQLiteResources $::test_channel
   913    934         }
   914    935       }
   915    936   

Changes to Tests/tkt-00f86f9739.eagle.

    20     20   
    21     21   ###############################################################################
    22     22   
    23     23   #
    24     24   # NOTE: Setup the variables that refer to the various files required by the
    25     25   #       tests in this file.
    26     26   #
           27  +set systemDataSQLiteDllFile [getBuildFileName System.Data.SQLite.dll]
           28  +set systemDataSQLiteLinqDllFile [getBuildFileName System.Data.SQLite.Linq.dll]
    27     29   set testLinqExeFile [getBuildFileName testlinq.exe]
    28     30   set northwindEfDbFile [file nativename [file join [file dirname $path] \
    29     31       testlinq northwindEF.db]]
    30     32   
    31     33   #
    32     34   # NOTE: Setup the test constraints specific to the tests in this file.
    33     35   #
           36  +if {![haveConstraint [appendArgs file_ \
           37  +    [file tail $systemDataSQLiteDllFile]]]} then {
           38  +  checkForFile $test_channel $systemDataSQLiteDllFile
           39  +}
           40  +
           41  +if {![haveConstraint [appendArgs file_ \
           42  +    [file tail $systemDataSQLiteLinqDllFile]]]} then {
           43  +  checkForFile $test_channel $systemDataSQLiteLinqDllFile
           44  +}
           45  +
    34     46   if {![haveConstraint [appendArgs file_ [file tail $testLinqExeFile]]]} then {
    35     47     checkForFile $test_channel $testLinqExeFile
    36     48   }
    37     49   
    38     50   if {![haveConstraint [appendArgs file_ [file tail $northwindEfDbFile]]]} then {
    39     51     checkForFile $test_channel $northwindEfDbFile
    40     52   }
................................................................................
    67     79     }
    68     80   
    69     81     set result
    70     82   } -cleanup {
    71     83     unset -nocomplain code output error result value
    72     84   } -constraints \
    73     85   {eagle monoToDo defineConstant.System.Data.SQLite.INTEROP_EXTENSION_FUNCTIONS\
    74         -file_testlinq.exe file_northwindEF.db} -result {0 {} 0 {DRACD OLDWO RATTC} 0\
    75         -{ALFKI CACTU CHOPS FOLKO GALED KOENE LILAS MAGAA MAISD OCEAN RANCH SAVEA THECR}\
    76         -0 {} 0 {} 0 {} 0 {}}}
           86  +file_System.Data.SQLite.dll file_System.Data.SQLite.Linq.dll file_testlinq.exe\
           87  +file_northwindEF.db} -result {0 {} 0 {DRACD OLDWO RATTC} 0 {ALFKI CACTU CHOPS\
           88  +FOLKO GALED KOENE LILAS MAGAA MAISD OCEAN RANCH SAVEA THECR} 0 {} 0 {} 0 {} 0\
           89  +{}}}
    77     90   
    78     91   ###############################################################################
    79     92   
    80         -unset -nocomplain testLinqExeFile northwindEfDbFile
           93  +unset -nocomplain systemDataSQLiteDllFile systemDataSQLiteLinqDllFile \
           94  +    testLinqExeFile northwindEfDbFile
    81     95   
    82     96   ###############################################################################
    83     97   
    84     98   runSQLiteTestEpilogue
    85     99   runTestEpilogue

Changes to Tests/tkt-59edc1018b.eagle.

    20     20   
    21     21   ###############################################################################
    22     22   
    23     23   #
    24     24   # NOTE: Setup the variables that refer to the various files required by the
    25     25   #       tests in this file.
    26     26   #
           27  +set systemDataSQLiteDllFile [getBuildFileName System.Data.SQLite.dll]
           28  +set systemDataSQLiteLinqDllFile [getBuildFileName System.Data.SQLite.Linq.dll]
    27     29   set testLinqExeFile [getBuildFileName testlinq.exe]
    28     30   set northwindEfDbFile [file nativename [file join [file dirname $path] \
    29     31       testlinq northwindEF.db]]
    30     32   
    31     33   #
    32     34   # NOTE: Setup the test constraints specific to the tests in this file.
    33     35   #
           36  +if {![haveConstraint [appendArgs file_ \
           37  +    [file tail $systemDataSQLiteDllFile]]]} then {
           38  +  checkForFile $test_channel $systemDataSQLiteDllFile
           39  +}
           40  +
           41  +if {![haveConstraint [appendArgs file_ \
           42  +    [file tail $systemDataSQLiteLinqDllFile]]]} then {
           43  +  checkForFile $test_channel $systemDataSQLiteLinqDllFile
           44  +}
           45  +
    34     46   if {![haveConstraint [appendArgs file_ [file tail $testLinqExeFile]]]} then {
    35     47     checkForFile $test_channel $testLinqExeFile
    36     48   }
    37     49   
    38     50   if {![haveConstraint [appendArgs file_ [file tail $northwindEfDbFile]]]} then {
    39     51     checkForFile $test_channel $northwindEfDbFile
    40     52   }
................................................................................
    67     79     }
    68     80   
    69     81     set result
    70     82   } -cleanup {
    71     83     unset -nocomplain code output error result value
    72     84   } -constraints \
    73     85   {eagle monoToDo defineConstant.System.Data.SQLite.INTEROP_EXTENSION_FUNCTIONS\
    74         -file_testlinq.exe file_northwindEF.db} -result {0 {} 0 {FURIB GALED GODOS LAZYK\
    75         -LINOD PRINI REGGC WOLZA} 0 {} 0 ERNSH 0 {} 0 {AROUT BSBEV CONSH EASTC NORTS\
    76         -SEVES} 0 {}}}
           86  +file_System.Data.SQLite.dll file_System.Data.SQLite.Linq.dll file_testlinq.exe\
           87  +file_northwindEF.db} -result {0 {} 0 {FURIB GALED GODOS LAZYK LINOD PRINI REGGC\
           88  +WOLZA} 0 {} 0 ERNSH 0 {} 0 {AROUT BSBEV CONSH EASTC NORTS SEVES} 0 {}}}
    77     89   
    78     90   ###############################################################################
    79     91   
    80         -unset -nocomplain testLinqExeFile northwindEfDbFile
           92  +unset -nocomplain systemDataSQLiteDllFile systemDataSQLiteLinqDllFile \
           93  +    testLinqExeFile northwindEfDbFile
    81     94   
    82     95   ###############################################################################
    83     96   
    84     97   runSQLiteTestEpilogue
    85     98   runTestEpilogue

Changes to Tests/tkt-8b7d179c3c.eagle.

    20     20   
    21     21   ###############################################################################
    22     22   
    23     23   #
    24     24   # NOTE: Setup the variables that refer to the various files required by the
    25     25   #       tests in this file.
    26     26   #
           27  +set systemDataSQLiteDllFile [getBuildFileName System.Data.SQLite.dll]
           28  +set systemDataSQLiteLinqDllFile [getBuildFileName System.Data.SQLite.Linq.dll]
    27     29   set testLinqExeFile [getBuildFileName testlinq.exe]
    28     30   set northwindEfDbFile [file nativename [file join [file dirname $path] \
    29     31       testlinq northwindEF.db]]
    30     32   
    31     33   #
    32     34   # NOTE: Setup the test constraints specific to the tests in this file.
    33     35   #
           36  +if {![haveConstraint [appendArgs file_ \
           37  +    [file tail $systemDataSQLiteDllFile]]]} then {
           38  +  checkForFile $test_channel $systemDataSQLiteDllFile
           39  +}
           40  +
           41  +if {![haveConstraint [appendArgs file_ \
           42  +    [file tail $systemDataSQLiteLinqDllFile]]]} then {
           43  +  checkForFile $test_channel $systemDataSQLiteLinqDllFile
           44  +}
           45  +
    34     46   if {![haveConstraint [appendArgs file_ [file tail $testLinqExeFile]]]} then {
    35     47     checkForFile $test_channel $testLinqExeFile
    36     48   }
    37     49   
    38     50   if {![haveConstraint [appendArgs file_ [file tail $northwindEfDbFile]]]} then {
    39     51     checkForFile $test_channel $northwindEfDbFile
    40     52   }
................................................................................
    65     77         lappend result [string trim $error]
    66     78       }
    67     79     }
    68     80   
    69     81     set result
    70     82   } -cleanup {
    71     83     unset -nocomplain code output error result pageSize
    72         -} -constraints {eagle monoToDo file_testlinq.exe file_northwindEF.db} -result \
    73         -{0 {} 0 {DRACD RATTC OLDWO GALED LILAS MAGAA ALFKI CHOPS SAVEA KOENE MAISD\
    74         -FOLKO CACTU OCEAN RANCH THECR GOURL GROSR SUPRD HUNGO ISLAT QUICK HUNGC GREAL\
    75         -LEHMS RICSU ERNSH WILMK LINOD TRAIH SIMOB OTTIK SPLIR MORGK FOLIG FURIB PRINI\
    76         -AROUT BSBEV CONSH EASTC NORTS SEVES BERGS VICTE BOLID FISSA ROMEY BLAUS BONAP\
    77         -MEREP ANATR ANTON CENTC PERIC TORTU FRANK TOMSP DUMON FRANR WARTH PARIS SPECD\
    78         -LONEP THEBI REGGC VINET WELLI HANAR QUEDE RICAR PICCO HILAA LETSS COMMI FAMIA\
    79         -QUEEN TRADH WHITC GODOS SANTG BLONP WANDK FRANS LAMAI BOTTM LAUGB LACOR LAZYK\
    80         -WOLZA VAFFE} 0 {DRACD RATTC OLDWO GALED LILAS MAGAA ALFKI CHOPS SAVEA KOENE\
           84  +} -constraints {eagle monoToDo file_System.Data.SQLite.dll\
           85  +file_System.Data.SQLite.Linq.dll file_testlinq.exe file_northwindEF.db} \
           86  +-result {0 {} 0 {DRACD RATTC OLDWO GALED LILAS MAGAA ALFKI CHOPS SAVEA KOENE\
    81     87   MAISD FOLKO CACTU OCEAN RANCH THECR GOURL GROSR SUPRD HUNGO ISLAT QUICK HUNGC\
    82     88   GREAL LEHMS RICSU ERNSH WILMK LINOD TRAIH SIMOB OTTIK SPLIR MORGK FOLIG FURIB\
    83     89   PRINI AROUT BSBEV CONSH EASTC NORTS SEVES BERGS VICTE BOLID FISSA ROMEY BLAUS\
    84     90   BONAP MEREP ANATR ANTON CENTC PERIC TORTU FRANK TOMSP DUMON FRANR WARTH PARIS\
    85     91   SPECD LONEP THEBI REGGC VINET WELLI HANAR QUEDE RICAR PICCO HILAA LETSS COMMI\
    86     92   FAMIA QUEEN TRADH WHITC GODOS SANTG BLONP WANDK FRANS LAMAI BOTTM LAUGB LACOR\
    87         -LAZYK WOLZA VAFFE}}}
           93  +LAZYK WOLZA VAFFE} 0 {DRACD RATTC OLDWO GALED LILAS MAGAA ALFKI CHOPS SAVEA\
           94  +KOENE MAISD FOLKO CACTU OCEAN RANCH THECR GOURL GROSR SUPRD HUNGO ISLAT QUICK\
           95  +HUNGC GREAL LEHMS RICSU ERNSH WILMK LINOD TRAIH SIMOB OTTIK SPLIR MORGK FOLIG\
           96  +FURIB PRINI AROUT BSBEV CONSH EASTC NORTS SEVES BERGS VICTE BOLID FISSA ROMEY\
           97  +BLAUS BONAP MEREP ANATR ANTON CENTC PERIC TORTU FRANK TOMSP DUMON FRANR WARTH\
           98  +PARIS SPECD LONEP THEBI REGGC VINET WELLI HANAR QUEDE RICAR PICCO HILAA LETSS\
           99  +COMMI FAMIA QUEEN TRADH WHITC GODOS SANTG BLONP WANDK FRANS LAMAI BOTTM LAUGB\
          100  +LACOR LAZYK WOLZA VAFFE}}}
    88    101   
    89    102   ###############################################################################
    90    103   
    91         -unset -nocomplain testLinqExeFile northwindEfDbFile
          104  +unset -nocomplain systemDataSQLiteDllFile systemDataSQLiteLinqDllFile \
          105  +    testLinqExeFile northwindEfDbFile
    92    106   
    93    107   ###############################################################################
    94    108   
    95    109   runSQLiteTestEpilogue
    96    110   runTestEpilogue

Added Tests/tkt-996d13cd87.eagle.

            1  +###############################################################################
            2  +#
            3  +# tkt-996d13cd87.eagle --
            4  +#
            5  +# Written by Joe Mistachkin.
            6  +# Released to the public domain, use at your own risk!
            7  +#
            8  +###############################################################################
            9  +
           10  +package require Eagle
           11  +package require Eagle.Library
           12  +package require Eagle.Test
           13  +
           14  +runTestPrologue
           15  +
           16  +###############################################################################
           17  +
           18  +package require System.Data.SQLite.Test
           19  +runSQLiteTestPrologue
           20  +
           21  +###############################################################################
           22  +
           23  +runTest {test tkt-996d13cd87-1.1 {SQLiteConnectionPool stress} -setup {
           24  +  set fileName tkt-996d13cd87-1.1.db
           25  +} -body {
           26  +  set id [object invoke Interpreter.GetActive NextId]
           27  +  set dataSource [file join [getDatabaseDirectory] $fileName]
           28  +
           29  +  set sql { \
           30  +    CREATE TABLE t1(x TEXT); \
           31  +    INSERT INTO t1 (x) VALUES(HEX(RANDOMBLOB(1000))); \
           32  +  }
           33  +
           34  +  unset -nocomplain results errors
           35  +
           36  +  set code [compileCSharpWith [subst {
           37  +    using System;
           38  +    using System.Data.SQLite;
           39  +    using System.Diagnostics;
           40  +    using System.Threading;
           41  +
           42  +    namespace _Dynamic${id}
           43  +    {
           44  +      public static class Test${id}
           45  +      {
           46  +        public static int Main()
           47  +        {
           48  +          //
           49  +          // NOTE: This is the total number of exceptions caught by all the
           50  +          //       test threads.
           51  +          //
           52  +          int errors = 0;
           53  +
           54  +          //
           55  +          // NOTE: This is the total number of test threads to create.
           56  +          //
           57  +          int count = 100;
           58  +
           59  +          //
           60  +          // NOTE: Create a random number generator suitable for waiting a
           61  +          //       random number of milliseconds between each attempt to
           62  +          //       cause the race condition on a given thread.
           63  +          //
           64  +          Random random = new Random();
           65  +
           66  +          //
           67  +          // NOTE: Create the event that will be used to synchronize all the
           68  +          //       created threads so that they start doing their actual test
           69  +          //       "work" at approximately the same time.
           70  +          //
           71  +          using (ManualResetEvent goEvent = new ManualResetEvent(false))
           72  +          {
           73  +            //
           74  +            // NOTE: Create a (reusable) delegate that will contain the code
           75  +            //       that half the created threads are to execute.  This code
           76  +            //       will repeatedly create, open, and close a single database
           77  +            //       connection with pool enabled.
           78  +            //
           79  +            ThreadStart threadStart1 = delegate()
           80  +            {
           81  +              try
           82  +              {
           83  +                //
           84  +                // NOTE: Wait forever for the "GO" signal so that all threads
           85  +                //       can start working at approximately the same time.
           86  +                //
           87  +                goEvent.WaitOne();
           88  +
           89  +                //
           90  +                // NOTE: Repeatedly try to create, open, and close a pooled
           91  +                //       database connection and then wait a random number of
           92  +                //       milliseconds before doing it again.
           93  +                //
           94  +                Thread.Sleep(random.Next(0, 500));
           95  +
           96  +                SQLiteConnection connection = new SQLiteConnection(
           97  +                    "Data Source=${dataSource};Pooling=True;");
           98  +
           99  +                connection.Open();
          100  +
          101  +                using (SQLiteCommand command = new SQLiteCommand("${sql}",
          102  +                    connection))
          103  +                {
          104  +                  command.ExecuteNonQuery();
          105  +                }
          106  +
          107  +                connection.Close();
          108  +                connection = null;
          109  +              }
          110  +              catch (Exception e)
          111  +              {
          112  +                Interlocked.Increment(ref errors);
          113  +                Trace.WriteLine(e);
          114  +              }
          115  +            };
          116  +
          117  +            //
          118  +            // NOTE: Create a (reusable) delegate that will contain the code
          119  +            //       that half the created threads are to execute.  This code
          120  +            //       will repeatedly force a full garbage collection.
          121  +            //
          122  +            ThreadStart threadStart2 = delegate()
          123  +            {
          124  +              try
          125  +              {
          126  +                //
          127  +                // NOTE: Wait forever for the "GO" signal so that all threads
          128  +                //       can start working at approximately the same time.
          129  +                //
          130  +                goEvent.WaitOne();
          131  +
          132  +                //
          133  +                // NOTE: Wait a random number of milliseconds before forcing a
          134  +                //       full garbage collection.
          135  +                //
          136  +                Thread.Sleep(random.Next(0, 1000));
          137  +                GC.GetTotalMemory(true);
          138  +              }
          139  +              catch (Exception e)
          140  +              {
          141  +                Interlocked.Increment(ref errors);
          142  +                Trace.WriteLine(e);
          143  +              }
          144  +            };
          145  +
          146  +            //
          147  +            // NOTE: Create the array of thread objects.
          148  +            //
          149  +            Thread\[\] thread = new Thread\[count\];
          150  +
          151  +            //
          152  +            // NOTE: Create each of the test threads with a suitable stack
          153  +            //       size.  We must specify a stack size here because the
          154  +            //       default one for the process would be the same as the
          155  +            //       parent executable (the Eagle shell), which is 16MB,
          156  +            //       too large to be useful.
          157  +            //
          158  +            for (int index = 0; index < count; index++)
          159  +            {
          160  +              //
          161  +              // NOTE: Figure out what kind of thread to create (i.e. one
          162  +              //       that uses a connection or one that calls the GC).
          163  +              //
          164  +              ThreadStart threadStart;
          165  +
          166  +              if (index == 0)
          167  +                threadStart = threadStart2;
          168  +              else
          169  +                threadStart = threadStart1;
          170  +
          171  +              thread\[index\] = new Thread(threadStart, 1048576);
          172  +
          173  +              //
          174  +              // NOTE: Name each thread for a better debugging experience.
          175  +              //
          176  +              thread\[index\].Name = String.Format(
          177  +                  "[file rootname ${fileName}] #{0}", index);
          178  +            }
          179  +
          180  +            //
          181  +            // NOTE: Start all the threads now.  They should not actually do
          182  +            //       any of the test "work" until we signal the event.
          183  +            //
          184  +            for (int index = 0; index < count; index++)
          185  +              thread\[index\].Start();
          186  +
          187  +            //
          188  +            // NOTE: Send the signal that all threads should start doing
          189  +            //       their test "work" now.
          190  +            //
          191  +            goEvent.Set(); /* GO */
          192  +
          193  +            //
          194  +            // NOTE: Wait forever for each thread to finish its test "work"
          195  +            //       and then die.
          196  +            //
          197  +            for (int index = 0; index < count; index++)
          198  +              thread\[index\].Join();
          199  +          }
          200  +
          201  +          //
          202  +          // NOTE: Return the total number of exceptions caught by the test
          203  +          //       threads.  For this test to pass, this number must be zero.
          204  +          //
          205  +          return errors;
          206  +        }
          207  +      }
          208  +    }
          209  +  }] true true true results errors System.Data.SQLite.dll]
          210  +
          211  +  list $code $results \
          212  +      [expr {[info exists errors] ? $errors : ""}] \
          213  +      [expr {$code eq "Ok" ? [catch {
          214  +        object invoke _Dynamic${id}.Test${id} Main
          215  +      } result] : [set result ""]}] $result
          216  +} -cleanup {
          217  +  object invoke System.Data.SQLite.SQLiteConnection ClearAllPools
          218  +  object invoke GC GetTotalMemory true
          219  +
          220  +  cleanupDb $fileName
          221  +
          222  +  unset -nocomplain result results errors code sql dataSource id db fileName
          223  +} -constraints \
          224  +{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite} -match \
          225  +regexp -result {^Ok System#CodeDom#Compiler#CompilerResults#\d+ \{\} 0 0$}}
          226  +
          227  +###############################################################################
          228  +
          229  +runSQLiteTestEpilogue
          230  +runTestEpilogue

Changes to Tests/tkt-ccfa69fc32.eagle.

    20     20   
    21     21   ###############################################################################
    22     22   
    23     23   #
    24     24   # NOTE: Setup the variables that refer to the various files required by the
    25     25   #       tests in this file.
    26     26   #
           27  +set systemDataSQLiteDllFile [getBuildFileName System.Data.SQLite.dll]
           28  +set systemDataSQLiteLinqDllFile [getBuildFileName System.Data.SQLite.Linq.dll]
    27     29   set testLinqExeFile [getBuildFileName testlinq.exe]
    28     30   set northwindEfDbFile [file nativename [file join [file dirname $path] \
    29     31       testlinq northwindEF.db]]
    30     32   
    31     33   #
    32     34   # NOTE: Setup the test constraints specific to the tests in this file.
    33     35   #
           36  +if {![haveConstraint [appendArgs file_ \
           37  +    [file tail $systemDataSQLiteDllFile]]]} then {
           38  +  checkForFile $test_channel $systemDataSQLiteDllFile
           39  +}
           40  +
           41  +if {![haveConstraint [appendArgs file_ \
           42  +    [file tail $systemDataSQLiteLinqDllFile]]]} then {
           43  +  checkForFile $test_channel $systemDataSQLiteLinqDllFile
           44  +}
           45  +
    34     46   if {![haveConstraint [appendArgs file_ [file tail $testLinqExeFile]]]} then {
    35     47     checkForFile $test_channel $testLinqExeFile
    36     48   }
    37     49   
    38     50   if {![haveConstraint [appendArgs file_ [file tail $northwindEfDbFile]]]} then {
    39     51     checkForFile $test_channel $northwindEfDbFile
    40     52   }
................................................................................
    65     77         lappend result [string trim $error]
    66     78       }
    67     79     }
    68     80   
    69     81     set result
    70     82   } -cleanup {
    71     83     unset -nocomplain code output error result add
    72         -} -constraints {eagle monoToDo file_testlinq.exe file_northwindEF.db} -match \
           84  +} -constraints {eagle monoToDo file_System.Data.SQLite.dll\
           85  +file_System.Data.SQLite.Linq.dll file_testlinq.exe file_northwindEF.db} -match \
    73     86   glob -result {0 {1581 1730 1833 2116 2139} 0 {System.Data.UpdateException: *\
    74     87   ---> System.Data.SQLite.SQLiteException: Abort due to constraint violation
    75     88   PRIMARY KEY must be unique
    76     89   *} 0 {1 2 3 4 5 6 7 8 9 10 1576 1577 1578 1579 1580 1581 1730 1833 2116 2139}}}
    77     90   
    78     91   ###############################################################################
    79     92   
    80         -unset -nocomplain testLinqExeFile northwindEfDbFile
           93  +unset -nocomplain systemDataSQLiteDllFile systemDataSQLiteLinqDllFile \
           94  +    testLinqExeFile northwindEfDbFile
    81     95   
    82     96   ###############################################################################
    83     97   
    84     98   runSQLiteTestEpilogue
    85     99   runTestEpilogue