From 61df568fc43e8d57943b77eaf5bccfb8bd5fa338 Mon Sep 17 00:00:00 2001 From: Sergei Dryganets Date: Wed, 22 Feb 2017 13:25:47 -0800 Subject: [PATCH 1/2] access to MutableDictonary openDBs properly synchronized --- src/ios/SQLite.m | 171 ++++++++++++++++++++++++----------------------- 1 file changed, 86 insertions(+), 85 deletions(-) diff --git a/src/ios/SQLite.m b/src/ios/SQLite.m index c8748769..6854bbef 100644 --- a/src/ios/SQLite.m +++ b/src/ios/SQLite.m @@ -267,42 +267,41 @@ -(void)createFromResource:(NSString *)prepopulatedDb withDbname:(NSString *)dbna RCT_EXPORT_METHOD(close: (NSDictionary *) options success:(RCTResponseSenderBlock)success error:(RCTResponseSenderBlock)error) { SQLiteResult* pluginResult = nil; - - NSString *dbFileName = options[@"path"]; - - if (dbFileName == NULL) { - // Should not happen: - NSLog(@"No db name specified for close"); - pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_ERROR messageAsString:@"You must specify database path"]; - } else { - NSDictionary *dbInfo = openDBs[dbFileName]; - if (dbInfo == NULL || dbInfo[@"dbPointer"] == NULL){ - NSLog(@"close: db name was not found in open databases: %@", dbFileName); - pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_ERROR messageAsString:@"Specified db was not open"]; + @synchronized (self) { + NSString *dbFileName = options[@"path"]; + if (dbFileName == NULL) { + // Should not happen: + NSLog(@"No db name specified for close"); + pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_ERROR messageAsString:@"You must specify database path"]; } else { - sqlite3 *db = [((NSValue *) dbInfo[@"dbPointer"]) pointerValue]; - NSString *dbPath = dbInfo[@"dbPath"]; - - if ([[NSFileManager defaultManager] fileExistsAtPath:dbPath]) { - NSLog(@"close: database still exists at path %@, proceeding to close it.",dbPath); - } - - if (db == NULL) { - // Should not happen: - NSLog(@"close: db name was not open: %@", dbFileName); + NSDictionary *dbInfo = openDBs[dbFileName]; + if (dbInfo == NULL || dbInfo[@"dbPointer"] == NULL) { + NSLog(@"close: db name was not found in open databases: %@", dbFileName); pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_ERROR messageAsString:@"Specified db was not open"]; - } - else { - NSLog(@"close: closing db: %@", dbFileName); - - sqlite3_close (db); - [openDBs removeObjectForKey:dbFileName]; - pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_OK messageAsString:@"DB closed"]; - } - if ([[NSFileManager defaultManager]fileExistsAtPath:dbPath]) { - NSLog(@"database file still exists after close"); } else { - NSLog(@"database file doesn't exists after close"); + sqlite3 *db = [((NSValue *) dbInfo[@"dbPointer"]) pointerValue]; + NSString *dbPath = dbInfo[@"dbPath"]; + + if ([[NSFileManager defaultManager] fileExistsAtPath:dbPath]) { + NSLog(@"close: database still exists at path %@, proceeding to close it.",dbPath); + } + + if (db == NULL) { + // Should not happen: + NSLog(@"close: db name was not open: %@", dbFileName); + pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_ERROR messageAsString:@"Specified db was not open"]; + } else { + NSLog(@"close: closing db: %@", dbFileName); + sqlite3_close (db); + [openDBs removeObjectForKey:dbFileName]; + pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_OK messageAsString:@"DB closed"]; + } + + if ([[NSFileManager defaultManager]fileExistsAtPath:dbPath]) { + NSLog(@"database file still exists after close"); + } else { + NSLog(@"database file doesn't exists after close"); + } } } } @@ -324,30 +323,29 @@ -(void)createFromResource:(NSString *)prepopulatedDb withDbname:(NSString *)dbna NSLog(@"No dbName or dbAlias specified for attach"); pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_ERROR messageAsString:@"You must specify dbName and dbAlias"]; } else { - NSLog(@"Will attach %@ with alias %@", dbName, dbAlias); - - NSDictionary *dbInfo = openDBs[dbFileName]; - NSDictionary *dbInfoToAttach = openDBs[dbName]; - - if (dbInfo == NULL || dbInfo[@"dbPointer"] == NULL){ - NSLog(@"attach: db name was not found in open databases: %@", dbFileName); - pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_ERROR messageAsString:@"Specified db was not open"]; - } - else if (dbInfoToAttach == NULL || dbInfoToAttach[@"dbPointer"] == NULL){ - NSLog(@"attach: db name was not found in open databases: %@", dbName); - pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_ERROR messageAsString:@"Specified db for ALIAS was not open"]; - } - else { - sqlite3 *db = [((NSValue *) dbInfo[@"dbPointer"]) pointerValue]; - NSString *dbPathToAttach = dbInfoToAttach[@"dbPath"]; - - NSString* sql = [NSString stringWithFormat:@"ATTACH DATABASE '%@' AS %@", dbPathToAttach, dbAlias]; + @synchronized (self) { + NSDictionary *dbInfo = openDBs[dbFileName]; + NSDictionary *dbInfoToAttach = openDBs[dbName]; - if(sqlite3_exec(db, [sql UTF8String], NULL, NULL, NULL) == SQLITE_OK) { - pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_OK messageAsString:@"Database attached successfully."]; + if (dbInfo == NULL || dbInfo[@"dbPointer"] == NULL) { + NSLog(@"attach: db name was not found in open databases: %@", dbFileName); + pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_ERROR messageAsString:@"Specified db was not open"]; + } + else if (dbInfoToAttach == NULL || dbInfoToAttach[@"dbPointer"] == NULL) { + NSLog(@"attach: db name was not found in open databases: %@", dbName); + pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_ERROR messageAsString:@"Specified db for ALIAS was not open"]; } else { - pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_ERROR messageAsString:@"Unable to attach DB"]; + sqlite3 *db = [((NSValue *) dbInfo[@"dbPointer"]) pointerValue]; + NSString *dbPathToAttach = dbInfoToAttach[@"dbPath"]; + + NSString* sql = [NSString stringWithFormat:@"ATTACH DATABASE '%@' AS %@", dbPathToAttach, dbAlias]; + + if(sqlite3_exec(db, [sql UTF8String], NULL, NULL, NULL) == SQLITE_OK) { + pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_OK messageAsString:@"Database attached successfully."]; + } else { + pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_ERROR messageAsString:@"Unable to attach DB"]; + } } } } @@ -355,29 +353,30 @@ -(void)createFromResource:(NSString *)prepopulatedDb withDbname:(NSString *)dbna [pluginResult.status intValue] == SQLiteStatus_OK ? success(@[pluginResult.message]) : error(@[pluginResult.message]); } - RCT_EXPORT_METHOD(delete: (NSDictionary *) options success:(RCTResponseSenderBlock)success error:(RCTResponseSenderBlock)error) { SQLiteResult* pluginResult = nil; NSString *dbfilename = options[@"path"]; NSString *dblocation = options[@"dblocation"]; - - if (dbfilename == NULL) { - // Should not happen: - NSLog(@"No db name specified for delete"); - pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_ERROR messageAsString:@"You must specify database path"]; - } else { - if (dblocation == NULL) dblocation = @"nosync"; - NSString *dbPath = [self getDBPath:dbfilename at:dblocation]; - if ([[NSFileManager defaultManager] fileExistsAtPath:dbPath]) { - NSLog(@"delete full db path: %@", dbPath); - [[NSFileManager defaultManager]removeItemAtPath:dbPath error:nil]; - [openDBs removeObjectForKey:dbfilename]; - pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_OK messageAsString:@"DB deleted"]; + @synchronized (self) { + if (dbfilename == NULL) { + // Should not happen: + NSLog(@"No db name specified for delete"); + pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_ERROR messageAsString:@"You must specify database path"]; } else { - NSLog(@"delete: db was not found: %@", dbPath); - pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_ERROR messageAsString:@"The database does not exist on that path"]; + if (dblocation == NULL) dblocation = @"nosync"; + NSString *dbPath = [self getDBPath:dbfilename at:dblocation]; + + if ([[NSFileManager defaultManager] fileExistsAtPath:dbPath]) { + NSLog(@"delete full db path: %@", dbPath); + [[NSFileManager defaultManager]removeItemAtPath:dbPath error:nil]; + [openDBs removeObjectForKey:dbfilename]; + pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_OK messageAsString:@"DB deleted"]; + } else { + NSLog(@"delete: db was not found: %@", dbPath); + pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_ERROR messageAsString:@"The database does not exist on that path"]; + } } } @@ -634,24 +633,26 @@ -(void)bindStatement:(sqlite3_stmt *)statement withArg:(NSObject *)arg atIndex:( -(void)dealloc { int i; - NSArray *keys = [openDBs allKeys]; - NSDictionary *dbInfo; - NSString *key; - sqlite3 *db; - - /* close db the user forgot */ - for (i=0; i<[keys count]; i++) { - key = [keys objectAtIndex:i]; - dbInfo = openDBs[key]; - db = [((NSValue *) dbInfo[@"dbPointer"]) pointerValue]; - sqlite3_close (db); - } + @synchronized (self) { + NSArray *keys = [openDBs allKeys]; + NSDictionary *dbInfo; + NSString *key; + sqlite3 *db; + + /* close db the user forgot */ + for (i=0; i<[keys count]; i++) { + key = [keys objectAtIndex:i]; + dbInfo = openDBs[key]; + db = [((NSValue *) dbInfo[@"dbPointer"]) pointerValue]; + sqlite3_close (db); + } #if !__has_feature(objc_arc) - [openDBs release]; - [appDBPaths release]; - [super dealloc]; + [openDBs release]; + [appDBPaths release]; + [super dealloc]; #endif + } } +(NSDictionary *)captureSQLiteErrorFromDb:(struct sqlite3 *)db From 151cd729baa979445ed9298a7aec71d7f1d308be Mon Sep 17 00:00:00 2001 From: Sergei Dryganets Date: Wed, 22 Feb 2017 17:56:30 -0800 Subject: [PATCH 2/2] fix for other under synchronized parts. TODO replaced with actual close and remove of the database --- src/ios/SQLite.m | 138 +++++++++++++++++++++++------------------------ 1 file changed, 69 insertions(+), 69 deletions(-) diff --git a/src/ios/SQLite.m b/src/ios/SQLite.m index 6854bbef..418da284 100644 --- a/src/ios/SQLite.m +++ b/src/ios/SQLite.m @@ -153,84 +153,86 @@ -(id) getDBPath:(NSString *)dbFile at:(NSString *)atkey { NSString *dbname; int sqlOpenFlags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; - NSString *dbfilename = options[@"name"]; - if (dbfilename == NULL) { - NSLog(@"No db name specified for open"); - pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_OK messageAsString:@"You must specify database name"]; - } - else { - NSDictionary *dbInfo = openDBs[dbfilename]; - if (dbInfo != NULL && dbInfo[@"dbPointer"] != NULL) { - NSLog(@"Reusing existing database connection for db name %@", dbfilename); - pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_OK messageAsString:@"Database opened"]; + @synchronized (self) { + NSString *dbfilename = options[@"name"]; + if (dbfilename == NULL) { + NSLog(@"No db name specified for open"); + pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_OK messageAsString:@"You must specify database name"]; } else { - NSString *assetFilePath = options[@"assetFilename"]; - if (assetFilePath != NULL && assetFilePath.length > 0) { - @try { - if ([assetFilePath isEqualToString:@"1"]){ - NSString *targetBundleDirPath = [[NSBundle mainBundle] resourcePath]; - targetBundleDirPath = [targetBundleDirPath stringByAppendingPathComponent: @"www"]; - assetFilePath = [targetBundleDirPath stringByAppendingPathComponent: dbfilename]; - NSLog(@"Built path to pre-populated DB asset from app bundle www subdirectory: %@",assetFilePath); - } else if ([assetFilePath characterAtIndex:0] == '~') { - assetFilePath = [assetFilePath substringFromIndex:1]; - NSString *targetBundleDirPath = [[NSBundle mainBundle] resourcePath]; - assetFilePath = [targetBundleDirPath stringByAppendingPathComponent: assetFilePath]; - NSLog(@"Built path to pre-populated DB asset from app bundle subdirectory: %@",assetFilePath); - } else { - NSURL * documentsDirUrl = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory - inDomains:NSUserDomainMask] lastObject]; - assetFilePath = [documentsDirUrl.path stringByAppendingPathComponent:assetFilePath]; - NSLog(@"Built path to pre-populated DB asset from app sandbox documents directory: %@",assetFilePath); + NSDictionary *dbInfo = openDBs[dbfilename]; + if (dbInfo != NULL && dbInfo[@"dbPointer"] != NULL) { + NSLog(@"Reusing existing database connection for db name %@", dbfilename); + pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_OK messageAsString:@"Database opened"]; + } else { + NSString *assetFilePath = options[@"assetFilename"]; + if (assetFilePath != NULL && assetFilePath.length > 0) { + @try { + if ([assetFilePath isEqualToString:@"1"]){ + NSString *targetBundleDirPath = [[NSBundle mainBundle] resourcePath]; + targetBundleDirPath = [targetBundleDirPath stringByAppendingPathComponent: @"www"]; + assetFilePath = [targetBundleDirPath stringByAppendingPathComponent: dbfilename]; + NSLog(@"Built path to pre-populated DB asset from app bundle www subdirectory: %@",assetFilePath); + } else if ([assetFilePath characterAtIndex:0 == '~']) { + assetFilePath = [assetFilePath substringFromIndex:1]; + NSString *targetBundleDirPath = [[NSBundle mainBundle] resourcePath]; + assetFilePath = [targetBundleDirPath stringByAppendingPathComponent: assetFilePath]; + NSLog(@"Built path to pre-populated DB asset from app bundle subdirectory: %@",assetFilePath); + } else { + NSURL * documentsDirUrl = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory + inDomains:NSUserDomainMask] lastObject]; + assetFilePath = [documentsDirUrl.path stringByAppendingPathComponent:assetFilePath]; + NSLog(@"Built path to pre-populated DB asset from app sandbox documents directory: %@",assetFilePath); + } + } @catch(NSException *ex){ + NSLog(@"Error building path for pre-populated DB asset %@",ex.reason); } - } @catch(NSException *ex){ - NSLog(@"Error building path for pre-populated DB asset %@",ex.reason); } - } - - if (options[@"readOnly"] && assetFilePath != NULL){ - sqlOpenFlags = SQLITE_OPEN_READONLY; - dbname = assetFilePath; - } else { - NSString *dblocation = options[@"dblocation"]; - if (dblocation == NULL) dblocation = @"nosync"; - NSLog(@"target database location: %@", dblocation); + if (options[@"readOnly"] && assetFilePath != NULL){ + sqlOpenFlags = SQLITE_OPEN_READONLY; + dbname = assetFilePath; + } else { + NSString *dblocation = options[@"dblocation"]; + if (dblocation == NULL) dblocation = @"nosync"; + NSLog(@"target database location: %@", dblocation); - dbname = [self getDBPath:dbfilename at:dblocation]; + dbname = [self getDBPath:dbfilename at:dblocation]; - /* Option to create from resource (pre-populated) if db does not exist: */ - if (![[NSFileManager defaultManager] fileExistsAtPath:dbname] && assetFilePath != NULL) { - NSLog(@"Copying pre-populated asset to the destination directory"); - [self createFromResource:assetFilePath withDbname:dbname]; + /* Option to create from resource (pre-populated) if db does not exist: */ + if (![[NSFileManager defaultManager] fileExistsAtPath:dbname] && assetFilePath != NULL) { + NSLog(@"Copying pre-populated asset to the destination directory"); + [self createFromResource:assetFilePath withDbname:dbname]; + } } - } - NSLog(@"Opening db in mode %@, full path: %@", (sqlOpenFlags == SQLITE_OPEN_READONLY) ? @"READ ONLY" : @"READ_WRITE",dbname); + NSLog(@"Opening db in mode %@, full path: %@", (sqlOpenFlags == SQLITE_OPEN_READONLY) ? @"READ ONLY" : @"READ_WRITE",dbname); - const char *name = [dbname UTF8String]; - sqlite3 *db; + const char *name = [dbname UTF8String]; + sqlite3 *db; - if (sqlite3_open_v2(name, &db,sqlOpenFlags, NULL) != SQLITE_OK) { - pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_ERROR messageAsString:@"Unable to open DB"]; - return; - } else { - sqlite3_create_function(db, "regexp", 2, SQLITE_ANY, NULL, &sqlite_regexp, NULL, NULL); + if (sqlite3_open_v2(name, &db,sqlOpenFlags, NULL) != SQLITE_OK) { + pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_ERROR messageAsString:@"Unable to open DB"]; + return; + } else { + sqlite3_create_function(db, "regexp", 2, SQLITE_ANY, NULL, &sqlite_regexp, NULL, NULL); - // for SQLCipher version: - // NSString *dbkey = options[@"key"]; - // const char *key = NULL; - // if (dbkey != NULL) key = [dbkey UTF8String]; - // if (key != NULL) sqlite3_key(db, key, strlen(key)); + // for SQLCipher version: + NSString *dbkey = options[@"key"]; + const char *key = NULL; + if (dbkey != NULL) key = [dbkey UTF8String]; + if (key != NULL) sqlite3_key(db, key, strlen(key)); - // Attempt to read the SQLite master table [to support SQLCipher version]: - if(sqlite3_exec(db, (const char*)"SELECT count(*) FROM sqlite_master;", NULL, NULL, NULL) == SQLITE_OK) { - NSValue *dbPointer = [NSValue valueWithPointer:db]; - openDBs[dbfilename] = @{ @"dbPointer": dbPointer, @"dbPath" : dbname}; - pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_OK messageAsString:@"Database opened"]; - } else { - pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_ERROR messageAsString:@"Unable to open DB with key"]; - // XXX TODO: close the db handle & [perhaps] remove from openDBs!! + // Attempt to read the SQLite master table [to support SQLCipher version]: + if(sqlite3_exec(db, (const char*)"SELECT count(*) FROM sqlite_master;", NULL, NULL, NULL) == SQLITE_OK) { + NSValue *dbPointer = [NSValue valueWithPointer:db]; + openDBs[dbfilename] = @{ @"dbPointer": dbPointer, @"dbPath" : dbname}; + pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_OK messageAsString:@"Database opened"]; + } else { + pluginResult = [SQLiteResult resultWithStatus:SQLiteStatus_ERROR messageAsString:@"Unable to open DB with key"]; + NSLog(@"Unable to open db with key"); + sqlite3_close (db); + [openDBs removeObjectForKey:dbfilename]; + } } } } @@ -238,13 +240,11 @@ -(id) getDBPath:(NSString *)dbFile at:(NSString *)atkey { if (sqlite3_threadsafe()) { NSLog(@"Good news: SQLite is thread safe!"); - } - else { + } else { NSLog(@"Warning: SQLite is not thread safe."); } [pluginResult.status intValue] == SQLiteStatus_OK ? success(@[pluginResult.message]) : error(@[pluginResult.message]); - NSLog(@"open cb finished ok"); }