Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch safeHandle Excluding Merge-Ins
This is equivalent to a diff from c063096071 to cb270f5cd8
2012-05-03
| ||
13:04 | Stop creating the CriticalHandle derived classes via implicit operator conversions. Simplify test case for ticket [996d13cd87]. check-in: 29b506224a user: mistachkin tags: trunk | |
06:35 | Experimental code to use SafeHandle instead of CriticalHandle for connection handles because they should not be closed until their statements and backup objects are all finalized. Closed-Leaf check-in: cb270f5cd8 user: mistachkin tags: safeHandle | |
2012-05-02
| ||
22:29 | Update version history with all the latest changes. check-in: c063096071 user: mistachkin tags: trunk | |
18:52 | Update Eagle script library in externals to latest trunk. check-in: fd95f9dd1d user: mistachkin tags: trunk | |
Changes to System.Data.SQLite/SQLite3.cs.
188 188 } 189 189 } 190 190 191 191 internal override bool AutoCommit 192 192 { 193 193 get 194 194 { 195 - return IsAutocommit(_sql); 195 + return IsAutocommit(_sql, _sql); 196 196 } 197 197 } 198 198 199 199 internal override long LastInsertRowId 200 200 { 201 201 get 202 202 { ................................................................................ 272 272 273 273 #if DEBUG && !NET_COMPACT_20 274 274 Trace.WriteLine(String.Format("Open: {0}", db)); 275 275 #endif 276 276 277 277 if (n > 0) throw new SQLiteException(n, null); 278 278 279 - _sql = db; 279 + _sql = new SQLiteConnectionHandle(db); 280 + 281 + lock (_sql) 282 + { 283 + // do nothing. 284 + } 280 285 } 281 286 // Bind functions to this connection. If any previous functions of the same name 282 287 // were already bound, then the new bindings replace the old. 283 288 _functionsArray = SQLiteFunction.BindFunctions(this, connectionFlags); 284 289 SetTimeout(0); 285 290 } 286 291 ................................................................................ 529 534 } 530 535 } 531 536 532 537 if (n > 0) throw new SQLiteException(n, GetLastError()); 533 538 534 539 strRemain = UTF8ToString(ptr, len); 535 540 536 - if (stmt != IntPtr.Zero) cmd = new SQLiteStatement(this, flags, stmt, strSql.Substring(0, strSql.Length - strRemain.Length), previous); 541 + if (stmt != IntPtr.Zero) cmd = new SQLiteStatement(this, flags, new SQLiteStatementHandle(_sql, stmt), strSql.Substring(0, strSql.Length - strRemain.Length), previous); 537 542 538 543 return cmd; 539 544 } 540 545 finally 541 546 { 542 547 handle.Free(); 543 548 } ................................................................................ 1471 1476 IntPtr backup = UnsafeNativeMethods.sqlite3_backup_init( 1472 1477 destHandle, zDestName, sourceHandle, zSourceName); 1473 1478 1474 1479 if (backup == IntPtr.Zero) 1475 1480 throw new SQLiteException(ResultCode(), GetLastError()); 1476 1481 1477 1482 return new SQLiteBackup( 1478 - this, backup, destHandle, zDestName, sourceHandle, zSourceName); 1483 + this, new SQLiteBackupHandle(destHandle, backup), 1484 + destHandle, zDestName, sourceHandle, zSourceName); 1479 1485 } 1480 1486 1481 1487 /// <summary> 1482 1488 /// Copies up to N pages from the source database to the destination 1483 1489 /// database associated with the specified backup object. 1484 1490 /// </summary> 1485 1491 /// <param name="backup">The backup object to use.</param>
Changes to System.Data.SQLite/SQLite3_UTF16.cs.
119 119 120 120 #if DEBUG && !NET_COMPACT_20 121 121 Trace.WriteLine(String.Format("Open: {0}", db)); 122 122 #endif 123 123 124 124 if (n > 0) throw new SQLiteException(n, null); 125 125 126 - _sql = db; 126 + _sql = new SQLiteConnectionHandle(db); 127 + 128 + lock (_sql) 129 + { 130 + // do nothing. 131 + } 127 132 } 128 133 _functionsArray = SQLiteFunction.BindFunctions(this, connectionFlags); 129 134 SetTimeout(0); 130 135 } 131 136 132 137 internal override void Bind_DateTime(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, DateTime dt) 133 138 {
Changes to System.Data.SQLite/SQLiteBase.cs.
343 343 // They exist here because they are called during the finalization of 344 344 // a SQLiteStatementHandle, SQLiteConnectionHandle, and SQLiteFunctionCookieHandle. 345 345 // Therefore these functions have to be static, and have to be low-level. 346 346 347 347 internal static string GetLastError(SQLiteConnectionHandle hdl, IntPtr db) 348 348 { 349 349 if ((hdl == null) || (db == IntPtr.Zero)) 350 - return "invalid connection or database handle"; 350 + return "null connection or database handle"; 351 + 352 + if (hdl.IsClosed || hdl.IsInvalid) 353 + return "closed or invalid connection handle"; 351 354 352 355 lock (hdl) 353 356 { 354 357 #if !SQLITE_STANDARD 355 358 int len; 356 359 return UTF8ToString(UnsafeNativeMethods.sqlite3_errmsg_interop(db, out len), len); 357 360 #else 358 361 return UTF8ToString(UnsafeNativeMethods.sqlite3_errmsg(db), -1); 359 362 #endif 360 363 } 361 364 } 362 365 363 - internal static void FinishBackup(IntPtr backup) 366 + internal static void FinishBackup(SQLiteConnectionHandle hdl, IntPtr backup) 364 367 { 365 - if (backup == IntPtr.Zero) return; 366 - int n = UnsafeNativeMethods.sqlite3_backup_finish(backup); 367 - if (n > 0) throw new SQLiteException(n, null); 368 + if ((hdl == null) || (backup == IntPtr.Zero)) return; 369 + if (hdl.IsClosed || hdl.IsInvalid) return; 370 + lock (hdl) 371 + { 372 + int n = UnsafeNativeMethods.sqlite3_backup_finish(backup); 373 + if (n > 0) throw new SQLiteException(n, null); 374 + } 368 375 } 369 376 370 - internal static void FinalizeStatement(IntPtr stmt) 377 + internal static void FinalizeStatement(SQLiteConnectionHandle hdl, IntPtr stmt) 371 378 { 372 - if (stmt == IntPtr.Zero) return; 379 + if ((hdl == null) || (stmt == IntPtr.Zero)) return; 380 + if (hdl.IsClosed || hdl.IsInvalid) return; 381 + lock (hdl) 382 + { 373 383 #if !SQLITE_STANDARD 374 - int n = UnsafeNativeMethods.sqlite3_finalize_interop(stmt); 384 + int n = UnsafeNativeMethods.sqlite3_finalize_interop(stmt); 375 385 #else 376 - int n = UnsafeNativeMethods.sqlite3_finalize(stmt); 386 + int n = UnsafeNativeMethods.sqlite3_finalize(stmt); 377 387 #endif 378 - if (n > 0) throw new SQLiteException(n, null); 388 + if (n > 0) throw new SQLiteException(n, null); 389 + } 379 390 } 380 391 381 392 internal static void CloseConnection(SQLiteConnectionHandle hdl, IntPtr db) 382 393 { 383 394 if ((hdl == null) || (db == IntPtr.Zero)) return; 384 395 lock (hdl) 385 396 { ................................................................................ 392 403 if (n > 0) throw new SQLiteException(n, GetLastError(hdl, db)); 393 404 } 394 405 } 395 406 396 407 internal static void ResetConnection(SQLiteConnectionHandle hdl, IntPtr db) 397 408 { 398 409 if ((hdl == null) || (db == IntPtr.Zero)) return; 410 + if (hdl.IsClosed || hdl.IsInvalid) return; 399 411 lock (hdl) 400 412 { 401 413 IntPtr stmt = IntPtr.Zero; 402 414 int n; 403 415 do 404 416 { 405 417 stmt = UnsafeNativeMethods.sqlite3_next_stmt(db, stmt); ................................................................................ 409 421 n = UnsafeNativeMethods.sqlite3_reset_interop(stmt); 410 422 #else 411 423 n = UnsafeNativeMethods.sqlite3_reset(stmt); 412 424 #endif 413 425 } 414 426 } while (stmt != IntPtr.Zero); 415 427 416 - if (IsAutocommit(db) == false) // a transaction is pending on the connection 428 + if (IsAutocommit(hdl, db) == false) // a transaction is pending on the connection 417 429 { 418 430 n = UnsafeNativeMethods.sqlite3_exec(db, ToUTF8("ROLLBACK"), IntPtr.Zero, IntPtr.Zero, out stmt); 419 431 if (n > 0) throw new SQLiteException(n, GetLastError(hdl, db)); 420 432 } 421 433 } 422 434 } 423 435 424 - internal static bool IsAutocommit(IntPtr db) 436 + internal static bool IsAutocommit(SQLiteConnectionHandle hdl, IntPtr db) 425 437 { 426 - if (db == IntPtr.Zero) return false; 427 - return (UnsafeNativeMethods.sqlite3_get_autocommit(db) == 1); 438 + if ((hdl == null) || (db == IntPtr.Zero)) return false; 439 + if (hdl.IsClosed || hdl.IsInvalid) return false; 440 + lock (hdl) 441 + { 442 + return (UnsafeNativeMethods.sqlite3_get_autocommit(db) == 1); 443 + } 428 444 } 429 - 430 445 } 431 446 432 447 internal interface ISQLiteSchemaExtensions 433 448 { 434 449 void BuildTempSchema(SQLiteConnection cnn); 435 450 } 436 451
Changes to System.Data.SQLite/UnsafeNativeMethods.cs.
1351 1351 get { return _isClosed; } 1352 1352 } 1353 1353 1354 1354 public abstract bool IsInvalid 1355 1355 { 1356 1356 get; 1357 1357 } 1358 - 1359 1358 } 1360 - 1361 1359 #endif 1362 1360 1363 1361 // Handles the unmanaged database pointer, and provides finalization support for it. 1364 - internal class SQLiteConnectionHandle : CriticalHandle 1362 + internal class SQLiteConnectionHandle : SafeHandle 1365 1363 { 1366 1364 public static implicit operator IntPtr(SQLiteConnectionHandle db) 1367 1365 { 1368 1366 return (db != null) ? db.handle : IntPtr.Zero; 1369 1367 } 1370 1368 1371 - public static implicit operator SQLiteConnectionHandle(IntPtr db) 1369 + private SQLiteConnectionHandle() 1370 + : base(IntPtr.Zero, true) 1372 1371 { 1373 - return new SQLiteConnectionHandle(db); 1374 1372 } 1375 1373 1376 - private SQLiteConnectionHandle(IntPtr db) 1374 + internal SQLiteConnectionHandle(IntPtr db) 1377 1375 : this() 1378 1376 { 1379 1377 SetHandle(db); 1380 - } 1381 - 1382 - internal SQLiteConnectionHandle() 1383 - : base(IntPtr.Zero) 1384 - { 1385 1378 } 1386 1379 1387 1380 protected override bool ReleaseHandle() 1388 1381 { 1389 1382 try 1390 1383 { 1391 1384 #if !PLATFORM_COMPACTFRAMEWORK ................................................................................ 1458 1451 } 1459 1452 #endif 1460 1453 } 1461 1454 1462 1455 // Provides finalization support for unmanaged SQLite statements. 1463 1456 internal class SQLiteStatementHandle : CriticalHandle 1464 1457 { 1458 + internal SQLiteConnectionHandle cnn; 1459 + private bool releaseNeeded; 1460 + 1465 1461 public static implicit operator IntPtr(SQLiteStatementHandle stmt) 1466 1462 { 1467 1463 return (stmt != null) ? stmt.handle : IntPtr.Zero; 1468 1464 } 1469 1465 1470 - public static implicit operator SQLiteStatementHandle(IntPtr stmt) 1466 + private SQLiteStatementHandle() 1467 + : base(IntPtr.Zero) 1471 1468 { 1472 - return new SQLiteStatementHandle(stmt); 1473 1469 } 1474 1470 1475 1471 private SQLiteStatementHandle(IntPtr stmt) 1476 1472 : this() 1477 1473 { 1478 1474 SetHandle(stmt); 1479 1475 } 1480 1476 1481 - internal SQLiteStatementHandle() 1482 - : base(IntPtr.Zero) 1477 + internal SQLiteStatementHandle(SQLiteConnectionHandle cnn, IntPtr stmt) 1478 + : this(stmt) 1483 1479 { 1480 + if (cnn != null) 1481 + cnn.DangerousAddRef(ref releaseNeeded); 1482 + 1483 + this.cnn = cnn; 1484 1484 } 1485 1485 1486 1486 protected override bool ReleaseHandle() 1487 1487 { 1488 1488 try 1489 1489 { 1490 1490 #if !PLATFORM_COMPACTFRAMEWORK 1491 1491 IntPtr localHandle = Interlocked.Exchange( 1492 1492 ref handle, IntPtr.Zero); 1493 1493 1494 1494 if (localHandle != IntPtr.Zero) 1495 - SQLiteBase.FinalizeStatement(localHandle); 1495 + SQLiteBase.FinalizeStatement(cnn, localHandle); 1496 + 1497 + if ((cnn != null) && releaseNeeded) 1498 + cnn.DangerousRelease(); 1496 1499 1497 1500 #if DEBUG && !NET_COMPACT_20 1498 1501 try 1499 1502 { 1500 1503 Trace.WriteLine(String.Format( 1501 1504 "FinalizeStatement: {0}", localHandle)); 1502 1505 } ................................................................................ 1503 1506 catch 1504 1507 { 1505 1508 } 1506 1509 #endif 1507 1510 #else 1508 1511 if (handle != IntPtr.Zero) 1509 1512 { 1510 - SQLiteBase.FinalizeStatement(handle); 1513 + SQLiteBase.FinalizeStatement(cnn, handle); 1511 1514 SetHandle(IntPtr.Zero); 1512 1515 } 1513 1516 #endif 1514 1517 1515 1518 #if DEBUG 1516 1519 return true; 1517 1520 #endif ................................................................................ 1557 1560 } 1558 1561 #endif 1559 1562 } 1560 1563 1561 1564 // Provides finalization support for unmanaged SQLite backup objects. 1562 1565 internal class SQLiteBackupHandle : CriticalHandle 1563 1566 { 1567 + internal SQLiteConnectionHandle cnn; 1568 + private bool releaseNeeded; 1569 + 1564 1570 public static implicit operator IntPtr(SQLiteBackupHandle backup) 1565 1571 { 1566 1572 return (backup != null) ? backup.handle : IntPtr.Zero; 1567 1573 } 1568 1574 1569 - public static implicit operator SQLiteBackupHandle(IntPtr backup) 1575 + private SQLiteBackupHandle() 1576 + : base(IntPtr.Zero) 1570 1577 { 1571 - return new SQLiteBackupHandle(backup); 1572 1578 } 1573 1579 1574 1580 private SQLiteBackupHandle(IntPtr backup) 1575 1581 : this() 1576 1582 { 1577 1583 SetHandle(backup); 1578 1584 } 1579 1585 1580 - internal SQLiteBackupHandle() 1581 - : base(IntPtr.Zero) 1586 + internal SQLiteBackupHandle(SQLiteConnectionHandle cnn, IntPtr backup) 1587 + : this(backup) 1582 1588 { 1589 + if (cnn != null) 1590 + cnn.DangerousAddRef(ref releaseNeeded); 1591 + 1592 + this.cnn = cnn; 1583 1593 } 1584 1594 1585 1595 protected override bool ReleaseHandle() 1586 1596 { 1587 1597 try 1588 1598 { 1589 1599 #if !PLATFORM_COMPACTFRAMEWORK 1590 1600 IntPtr localHandle = Interlocked.Exchange( 1591 1601 ref handle, IntPtr.Zero); 1592 1602 1593 1603 if (localHandle != IntPtr.Zero) 1594 - SQLiteBase.FinishBackup(localHandle); 1604 + SQLiteBase.FinishBackup(cnn, localHandle); 1605 + 1606 + if ((cnn != null) && releaseNeeded) 1607 + cnn.DangerousRelease(); 1595 1608 1596 1609 #if DEBUG && !NET_COMPACT_20 1597 1610 try 1598 1611 { 1599 1612 Trace.WriteLine(String.Format( 1600 1613 "FinishBackup: {0}", localHandle)); 1601 1614 } ................................................................................ 1602 1615 catch 1603 1616 { 1604 1617 } 1605 1618 #endif 1606 1619 #else 1607 1620 if (handle != IntPtr.Zero) 1608 1621 { 1609 - SQLiteBase.FinishBackup(handle); 1622 + SQLiteBase.FinishBackup(cnn, handle); 1610 1623 SetHandle(IntPtr.Zero); 1611 1624 } 1612 1625 #endif 1613 1626 1614 1627 #if DEBUG 1615 1628 return true; 1616 1629 #endif