Files
checker/ios/Pods/FMDB/src/fmdb/FMDatabasePool.m
2017-10-23 20:25:04 +03:00

284 lines
7.2 KiB
Objective-C

//
// FMDatabasePool.m
// fmdb
//
// Created by August Mueller on 6/22/11.
// Copyright 2011 Flying Meat Inc. All rights reserved.
//
#if FMDB_SQLITE_STANDALONE
#import <sqlite3/sqlite3.h>
#else
#import <sqlite3.h>
#endif
#import "FMDatabasePool.h"
#import "FMDatabase.h"
@interface FMDatabasePool()
- (void)pushDatabaseBackInPool:(FMDatabase*)db;
- (FMDatabase*)db;
@end
@implementation FMDatabasePool
@synthesize path=_path;
@synthesize delegate=_delegate;
@synthesize maximumNumberOfDatabasesToCreate=_maximumNumberOfDatabasesToCreate;
@synthesize openFlags=_openFlags;
+ (instancetype)databasePoolWithPath:(NSString*)aPath {
return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath]);
}
+ (instancetype)databasePoolWithPath:(NSString*)aPath flags:(int)openFlags {
return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath flags:openFlags]);
}
- (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags {
self = [super init];
if (self != nil) {
_path = [aPath copy];
_lockQueue = dispatch_queue_create([[NSString stringWithFormat:@"fmdb.%@", self] UTF8String], NULL);
_databaseInPool = FMDBReturnRetained([NSMutableArray array]);
_databaseOutPool = FMDBReturnRetained([NSMutableArray array]);
_openFlags = openFlags;
}
return self;
}
- (instancetype)initWithPath:(NSString*)aPath
{
// default flags for sqlite3_open
return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE];
}
- (instancetype)init {
return [self initWithPath:nil];
}
- (void)dealloc {
_delegate = 0x00;
FMDBRelease(_path);
FMDBRelease(_databaseInPool);
FMDBRelease(_databaseOutPool);
if (_lockQueue) {
FMDBDispatchQueueRelease(_lockQueue);
_lockQueue = 0x00;
}
#if ! __has_feature(objc_arc)
[super dealloc];
#endif
}
- (void)executeLocked:(void (^)(void))aBlock {
dispatch_sync(_lockQueue, aBlock);
}
- (void)pushDatabaseBackInPool:(FMDatabase*)db {
if (!db) { // db can be null if we set an upper bound on the # of databases to create.
return;
}
[self executeLocked:^() {
if ([self->_databaseInPool containsObject:db]) {
[[NSException exceptionWithName:@"Database already in pool" reason:@"The FMDatabase being put back into the pool is already present in the pool" userInfo:nil] raise];
}
[self->_databaseInPool addObject:db];
[self->_databaseOutPool removeObject:db];
}];
}
- (FMDatabase*)db {
__block FMDatabase *db;
[self executeLocked:^() {
db = [self->_databaseInPool lastObject];
BOOL shouldNotifyDelegate = NO;
if (db) {
[self->_databaseOutPool addObject:db];
[self->_databaseInPool removeLastObject];
}
else {
if (self->_maximumNumberOfDatabasesToCreate) {
NSUInteger currentCount = [self->_databaseOutPool count] + [self->_databaseInPool count];
if (currentCount >= self->_maximumNumberOfDatabasesToCreate) {
NSLog(@"Maximum number of databases (%ld) has already been reached!", (long)currentCount);
return;
}
}
db = [FMDatabase databaseWithPath:self->_path];
shouldNotifyDelegate = YES;
}
//This ensures that the db is opened before returning
#if SQLITE_VERSION_NUMBER >= 3005000
BOOL success = [db openWithFlags:self->_openFlags];
#else
BOOL success = [db open];
#endif
if (success) {
if ([self->_delegate respondsToSelector:@selector(databasePool:shouldAddDatabaseToPool:)] && ![self->_delegate databasePool:self shouldAddDatabaseToPool:db]) {
[db close];
db = 0x00;
}
else {
//It should not get added in the pool twice if lastObject was found
if (![self->_databaseOutPool containsObject:db]) {
[self->_databaseOutPool addObject:db];
if (shouldNotifyDelegate && [self->_delegate respondsToSelector:@selector(databasePool:didAddDatabase:)]) {
[self->_delegate databasePool:self didAddDatabase:db];
}
}
}
}
else {
NSLog(@"Could not open up the database at path %@", self->_path);
db = 0x00;
}
}];
return db;
}
- (NSUInteger)countOfCheckedInDatabases {
__block NSUInteger count;
[self executeLocked:^() {
count = [self->_databaseInPool count];
}];
return count;
}
- (NSUInteger)countOfCheckedOutDatabases {
__block NSUInteger count;
[self executeLocked:^() {
count = [self->_databaseOutPool count];
}];
return count;
}
- (NSUInteger)countOfOpenDatabases {
__block NSUInteger count;
[self executeLocked:^() {
count = [self->_databaseOutPool count] + [self->_databaseInPool count];
}];
return count;
}
- (void)releaseAllDatabases {
[self executeLocked:^() {
[self->_databaseOutPool removeAllObjects];
[self->_databaseInPool removeAllObjects];
}];
}
- (void)inDatabase:(void (^)(FMDatabase *db))block {
FMDatabase *db = [self db];
block(db);
[self pushDatabaseBackInPool:db];
}
- (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(FMDatabase *db, BOOL *rollback))block {
BOOL shouldRollback = NO;
FMDatabase *db = [self db];
if (useDeferred) {
[db beginDeferredTransaction];
}
else {
[db beginTransaction];
}
block(db, &shouldRollback);
if (shouldRollback) {
[db rollback];
}
else {
[db commit];
}
[self pushDatabaseBackInPool:db];
}
- (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {
[self beginTransaction:YES withBlock:block];
}
- (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {
[self beginTransaction:NO withBlock:block];
}
- (NSError*)inSavePoint:(void (^)(FMDatabase *db, BOOL *rollback))block {
#if SQLITE_VERSION_NUMBER >= 3007000
static unsigned long savePointIdx = 0;
NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++];
BOOL shouldRollback = NO;
FMDatabase *db = [self db];
NSError *err = 0x00;
if (![db startSavePointWithName:name error:&err]) {
[self pushDatabaseBackInPool:db];
return err;
}
block(db, &shouldRollback);
if (shouldRollback) {
// We need to rollback and release this savepoint to remove it
[db rollbackToSavePointWithName:name error:&err];
}
[db releaseSavePointWithName:name error:&err];
[self pushDatabaseBackInPool:db];
return err;
#else
NSString *errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil);
if (self.logsErrors) NSLog(@"%@", errorMessage);
return [NSError errorWithDomain:@"FMDatabase" code:0 userInfo:@{NSLocalizedDescriptionKey : errorMessage}];
#endif
}
@end