Browse Source

Merge pull request #621 from robertmryan/master

Fix isOpen logic
August "Gus" Mueller 8 years ago
parent
commit
efcfb3cc79
3 changed files with 73 additions and 5 deletions
  1. 44 0
      Tests/FMDatabaseTests.m
  2. 4 0
      src/fmdb/FMDatabase.h
  3. 25 5
      src/fmdb/FMDatabase.m

+ 44 - 0
Tests/FMDatabaseTests.m

@@ -1486,4 +1486,48 @@ - (void)testImmediateTransaction {
     XCTAssertEqualObjects([db lastError].localizedDescription, @"cannot start a transaction within a transaction");
 }
 
+- (void)testOpenFailure {
+    NSURL *tempURL = [NSURL fileURLWithPath:NSTemporaryDirectory()];
+    NSURL *fileURL1 = [tempURL URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
+    NSURL *fileURL2 = [tempURL URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
+    NSFileManager *manager = [NSFileManager defaultManager];
+    
+    // ok, first create one database
+    
+    FMDatabase *db = [FMDatabase databaseWithURL:fileURL1];
+    BOOL success = [db open];
+    XCTAssert(success, @"Database not created correctly for purposes of test");
+    success = [db executeUpdate:@"create table if not exists foo (bar text)"];
+    XCTAssert(success, @"Table created correctly for purposes of test");
+    [db close];
+    
+    // now, try to create open second database even though it doesn't exist
+    
+    db = [FMDatabase databaseWithURL:fileURL2];
+    success = [db openWithFlags:SQLITE_OPEN_READWRITE];
+    XCTAssert(!success, @"Opening second database file that doesn't exist should not have succeeded");
+    
+    // OK, everything so far is fine, opening a db without CREATE option above should have failed,
+    // but so fix the missing file issue and re-opening
+    
+    success = [manager copyItemAtURL:fileURL1 toURL:fileURL2 error:nil];
+    XCTAssert(success, @"Copying of db should have succeeded");
+    
+    // now let's try opening it again
+    
+    success = [db openWithFlags:SQLITE_OPEN_READWRITE];
+    XCTAssert(success, @"Opening second database should now succeed");
+
+    // now let's try using it
+    FMResultSet *rs = [db executeQuery:@"select * from foo"];
+    XCTAssertNotNil(rs, @"Should successfully be able to use re-opened database");
+    
+    // let's clean up
+    
+    [rs close];
+    [db close];
+    [manager removeItemAtURL:fileURL1 error:nil];
+    [manager removeItemAtURL:fileURL2 error:nil];
+}
+
 @end

+ 4 - 0
src/fmdb/FMDatabase.h

@@ -221,6 +221,10 @@ typedef NS_ENUM(int, FMDBCheckpointMode) {
 /// @name Opening and closing database
 ///-----------------------------------
 
+/// Is the database open or not?
+
+@property (nonatomic) BOOL isOpen;
+
 /** Opening a new database connection
  
  The database is opened for reading and writing, and is created if it does not already exist.

+ 25 - 5
src/fmdb/FMDatabase.m

@@ -68,6 +68,7 @@ - (instancetype)initWithPath:(NSString *)path {
         _logsErrors                 = YES;
         _crashOnErrors              = NO;
         _maxBusyRetryTimeInterval   = 2;
+        _isOpen                     = NO;
     }
     
     return self;
@@ -160,10 +161,18 @@ - (const char*)sqlitePath {
 #pragma mark Open and close database
 
 - (BOOL)open {
-    if (_db) {
+    if (_isOpen) {
         return YES;
     }
     
+    // if we previously tried to open and it failed, make sure to close it before we try again
+    
+    if (_db) {
+        [self close];
+    }
+    
+    // now open database
+
     int err = sqlite3_open([self sqlitePath], (sqlite3**)&_db );
     if(err != SQLITE_OK) {
         NSLog(@"error opening!: %d", err);
@@ -175,6 +184,7 @@ - (BOOL)open {
         [self setMaxBusyRetryTimeInterval:_maxBusyRetryTimeInterval];
     }
     
+    _isOpen = YES;
     
     return YES;
 }
@@ -182,12 +192,21 @@ - (BOOL)open {
 - (BOOL)openWithFlags:(int)flags {
     return [self openWithFlags:flags vfs:nil];
 }
+
 - (BOOL)openWithFlags:(int)flags vfs:(NSString *)vfsName {
 #if SQLITE_VERSION_NUMBER >= 3005000
-    if (_db) {
+    if (_isOpen) {
         return YES;
     }
     
+    // if we previously tried to open and it failed, make sure to close it before we try again
+    
+    if (_db) {
+        [self close];
+    }
+    
+    // now open database
+    
     int err = sqlite3_open_v2([self sqlitePath], (sqlite3**)&_db, flags, [vfsName UTF8String]);
     if(err != SQLITE_OK) {
         NSLog(@"error opening!: %d", err);
@@ -199,6 +218,8 @@ - (BOOL)openWithFlags:(int)flags vfs:(NSString *)vfsName {
         [self setMaxBusyRetryTimeInterval:_maxBusyRetryTimeInterval];
     }
     
+    _isOpen = YES;
+    
     return YES;
 #else
     NSLog(@"openWithFlags requires SQLite 3.5");
@@ -206,7 +227,6 @@ - (BOOL)openWithFlags:(int)flags vfs:(NSString *)vfsName {
 #endif
 }
 
-
 - (BOOL)close {
     
     [self clearCachedStatements];
@@ -466,7 +486,7 @@ - (NSString *)stringFromDate:(NSDate *)date {
 
 - (BOOL)goodConnection {
     
-    if (!_db) {
+    if (!_isOpen) {
         return NO;
     }
     
@@ -493,7 +513,7 @@ - (void)warnInUse {
 
 - (BOOL)databaseExists {
     
-    if (!_db) {
+    if (!_isOpen) {
         
         NSLog(@"The FMDatabase %@ is not open.", self);