Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

access to MutableDictonary openDBs properly synchronized #130

Merged
merged 2 commits into from
Feb 23, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
309 changes: 155 additions & 154 deletions src/ios/SQLite.m
Original file line number Diff line number Diff line change
Expand Up @@ -153,98 +153,98 @@ -(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];
}
}
}
}
}

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");
}

Expand All @@ -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");
}
}
}
}
Expand All @@ -324,60 +323,60 @@ -(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"];
}
}
}
}

[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"];
}
}
}

Expand Down Expand Up @@ -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
Expand Down