From 69400b6b764f769829c5963c868b3163b00b209f Mon Sep 17 00:00:00 2001 From: CC Date: Fri, 15 Dec 2017 06:01:44 +0800 Subject: [PATCH] format --- CCSQLite/CCKeyValue.m | 117 +-- CCSQLite/CCOptions.m | 14 +- CCSQLite/CCResultSet.m | 248 +++-- CCSQLite/CCSQLite.m | 1914 ++++++++++++++++++-------------------- CCSQLite/CCSQLitePool.m | 290 +++--- CCSQLite/CCSQLiteQueue.m | 157 ++-- CCSQLite/CCStatement.m | 12 +- 7 files changed, 1315 insertions(+), 1437 deletions(-) diff --git a/CCSQLite/CCKeyValue.m b/CCSQLite/CCKeyValue.m index d3a985f..da2ee78 100644 --- a/CCSQLite/CCKeyValue.m +++ b/CCSQLite/CCKeyValue.m @@ -11,53 +11,54 @@ @interface CCKeyValue () -@property (atomic, copy) NSString *path; +@property (atomic, copy) NSString * path; @property (atomic, copy) CCSQLiteSerializer objectSerializer; @property (atomic, copy) CCSQLiteDeserializer objectDeserializer; -- (void) setObject: (id) object key : (NSString *) key; -- (id) objectForKey : (NSString *) key; +- (void) setObject:(id)object key:(NSString *)key; +- (id) objectForKey:(NSString *)key; @end @implementation CCKeyValue -+ (CCKeyValue *) defaultKeyValueWithPath : (NSString *)path { - static CCKeyValue *kv = nil; - ++ (CCKeyValue *) defaultKeyValueWithPath:(NSString *)path { + static CCKeyValue * kv = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ kv = [CCKeyValue new]; kv.valueType = CCKeyValueTypeDefault; }); - + kv.path = path; - + return kv; } -- (void) setObject: (id) object key : (NSString *) key inCollection: (NSString *) collection metadata: (NSData *)metadata { +- (void) setObject:(id)object key:(NSString *)key inCollection:(NSString *)collection metadata:(NSData *)metadata { if (!_path || ![_path isKindOfClass:[NSString class]]) { NSLog(@"The actual path of the database must be obtained!"); return; } - - NSString *c = nil; - + + NSString * c = nil; + if (!collection || ![collection isKindOfClass:[NSString class]]) { c = CCSQLiteCollection; } else { c = collection; } - + if (!key || ![key isKindOfClass:[NSString class]]) { NSLog(@"key is illegal"); return; } - + self.objectSerializer = [CCSQLite defaultSerializer]; - + switch (_valueType) { case CCKeyValueTypePropertyList: self.objectSerializer = [CCSQLite propertyListSerializer]; @@ -71,45 +72,45 @@ - (void) setObject: (id) object key : (NSString *) key inCollection: (NSString * default: break; } - - NSData *data = self.objectSerializer(c, key, object); - - CCSQLiteQueue *innerQueue = [CCSQLiteQueue databaseQueueWithPath: _path]; + + NSData * data = self.objectSerializer(c, key, object); + + CCSQLiteQueue * innerQueue = [CCSQLiteQueue databaseQueueWithPath:_path]; __block BOOL isOK = NO; - [innerQueue inTransaction:^(CCSQLite *db, BOOL *rollback) { - isOK = [db executeUpdate:@"insert into 'CCSQLite.Database2' (collection, key, data, metadata) values (?, ?, ?, ?);", c, key, data, metadata]; - - if (!isOK) { - isOK = [db executeUpdate:@"update 'CCSQLite.Database2' set data = ? , metadata = ? where collection = ? and key = ?;", data, metadata, c, key]; - } - - if (!isOK) { - NSLog(@"execute excpetion!"); - } - - *rollback = !isOK; - }]; -} + [innerQueue inTransaction:^(CCSQLite * db, BOOL * rollback) { + isOK = [db executeUpdate:@"insert into 'CCSQLite.Database2' (collection, key, data, metadata) values (?, ?, ?, ?);", c, key, data, metadata]; + + if (!isOK) { + isOK = [db executeUpdate:@"update 'CCSQLite.Database2' set data = ? , metadata = ? where collection = ? and key = ?;", data, metadata, c, key]; + } + if (!isOK) { + NSLog(@"execute excpetion!"); + } -- (id) objectForKey : (NSString *) key inCollection: (NSString *) collection { - NSString *c = nil; + *rollback = !isOK; + }]; +} /* setObject */ + + +- (id) objectForKey:(NSString *)key inCollection:(NSString *)collection { + NSString * c = nil; __block id object = nil; - + if (!collection || ![collection isKindOfClass:[NSString class]]) { c = CCSQLiteCollection; } else { c = collection; } - + if (!key || ![key isKindOfClass:[NSString class]]) { NSLog(@"key is illegal"); return object; } - + self.objectDeserializer = [CCSQLite defaultDeserializer]; - + switch (_valueType) { case CCKeyValueTypePropertyList: self.objectDeserializer = [CCSQLite propertyListDeserializer]; @@ -124,30 +125,30 @@ - (id) objectForKey : (NSString *) key inCollection: (NSString *) collection { break; } - CCSQLiteQueue *innerQueue = [CCSQLiteQueue databaseQueueWithPath: _path]; - - NSString *sql = [NSString stringWithFormat:@"select * from '%@' where key = '%@' and collection = '%@';", CCSQLiteDatabase2, key, c]; - - __block NSData *data = nil; - [innerQueue inDatabase:^(CCSQLite *db) { - CCResultSet *r = [db executeQuery:sql]; - while ([r next]) { - data = [r dataForColumn:CCKeyValueDataKey]; - object = self.objectDeserializer(c, key, data); - break; - } - - [r close]; - }]; - + CCSQLiteQueue * innerQueue = [CCSQLiteQueue databaseQueueWithPath:_path]; + + NSString * sql = [NSString stringWithFormat:@"select * from '%@' where key = '%@' and collection = '%@';", CCSQLiteDatabase2, key, c]; + + __block NSData * data = nil; + [innerQueue inDatabase:^(CCSQLite * db) { + CCResultSet * r = [db executeQuery:sql]; + while ([r next]) { + data = [r dataForColumn:CCKeyValueDataKey]; + object = self.objectDeserializer(c, key, data); + break; + } + + [r close]; + }]; + return object; -} +} /* objectForKey */ -- (void) setObject: (id) object key : (NSString *) key { +- (void) setObject:(id)object key:(NSString *)key { [self setObject:object key:key inCollection:nil metadata:nil]; } -- (id) objectForKey : (NSString *) key { +- (id) objectForKey:(NSString *)key { return [self objectForKey:key inCollection:nil]; } diff --git a/CCSQLite/CCOptions.m b/CCSQLite/CCOptions.m index 7d7ac43..f39d2eb 100644 --- a/CCSQLite/CCOptions.m +++ b/CCSQLite/CCOptions.m @@ -37,10 +37,8 @@ @implementation CCOptions @synthesize aggressiveWALTruncationSize = aggressiveWALTruncationSize; @synthesize enableMultiProcessSupport = enableMultiProcessSupport; -- (id)init -{ - if ((self = [super init])) - { +- (id) init { + if ((self = [super init])) { corruptAction = CCOptionsCorruptAction_Rename; pragmaSynchronous = CCOptionsPragmaSynchronous_Full; pragmaJournalSizeLimit = 0; @@ -52,9 +50,9 @@ - (id)init return self; } -- (id)copyWithZone:(NSZone __unused *)zone -{ - CCOptions *copy = [[[self class] alloc] init]; +- (id) copyWithZone:(NSZone __unused *)zone { + CCOptions * copy = [[[self class] alloc] init]; + copy->corruptAction = corruptAction; copy->pragmaSynchronous = pragmaSynchronous; copy->pragmaJournalSizeLimit = pragmaJournalSizeLimit; @@ -68,7 +66,7 @@ - (id)copyWithZone:(NSZone __unused *)zone #endif copy->aggressiveWALTruncationSize = aggressiveWALTruncationSize; copy->enableMultiProcessSupport = enableMultiProcessSupport; - + return copy; } diff --git a/CCSQLite/CCResultSet.m b/CCSQLite/CCResultSet.m index 399622e..3e37985 100644 --- a/CCSQLite/CCResultSet.m +++ b/CCSQLite/CCResultSet.m @@ -11,60 +11,60 @@ #import "unistd.h" @interface CCResultSet () { - CCSQLite *_parentDB; - NSMutableDictionary *_columnNameToIndexMap; + CCSQLite * _parentDB; + NSMutableDictionary * _columnNameToIndexMap; } @end @interface CCSQLite () -- (void)resultSetDidClose:(CCResultSet *)resultSet; +- (void) resultSetDidClose:(CCResultSet *)resultSet; @end @implementation CCResultSet -+ (instancetype)resultSetWithStatement:(CCStatement *)statement usingParentDatabase:(CCSQLite*)aDB { - - CCResultSet *rs = [[CCResultSet alloc] init]; - ++ (instancetype) resultSetWithStatement:(CCStatement *)statement usingParentDatabase:(CCSQLite *)aDB { + + CCResultSet * rs = [[CCResultSet alloc] init]; + [rs setStatement:statement]; [rs setParentDB:aDB]; - + NSParameterAssert(![statement inUse]); [statement setInUse:YES]; // weak reference - + return CCReturnAutoreleased(rs); } -- (void)dealloc { +- (void) dealloc { [self close]; - + CCRelease(_query); _query = nil; - + CCRelease(_columnNameToIndexMap); _columnNameToIndexMap = nil; } -- (void)close { +- (void) close { [_statement reset]; CCRelease(_statement); _statement = nil; - + // we don't need this anymore... (i think) - //[_parentDB setInUse:NO]; + // [_parentDB setInUse:NO]; [_parentDB resultSetDidClose:self]; _parentDB = nil; } -- (int)columnCount { +- (int) columnCount { return sqlite3_column_count([_statement statement]); } -- (NSMutableDictionary *)columnNameToIndexMap { +- (NSMutableDictionary *) columnNameToIndexMap { if (!_columnNameToIndexMap) { int columnCount = sqlite3_column_count([_statement statement]); _columnNameToIndexMap = [[NSMutableDictionary alloc] initWithCapacity:(NSUInteger)columnCount]; @@ -77,316 +77,308 @@ - (NSMutableDictionary *)columnNameToIndexMap { return _columnNameToIndexMap; } -- (void)kvcMagic:(id)object { - +- (void) kvcMagic:(id)object { + int columnCount = sqlite3_column_count([_statement statement]); - + int columnIdx = 0; + for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { - - const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx); - + + const char * c = (const char *)sqlite3_column_text([_statement statement], columnIdx); + // check for a null row if (c) { - NSString *s = [NSString stringWithUTF8String:c]; - + NSString * s = [NSString stringWithUTF8String:c]; + [object setValue:s forKey:[NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]]; } } } -- (NSDictionary*)resultDictionary { - +- (NSDictionary *) resultDictionary { + NSUInteger num_cols = (NSUInteger)sqlite3_data_count([_statement statement]); - + if (num_cols > 0) { - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:num_cols]; - + NSMutableDictionary * dict = [NSMutableDictionary dictionaryWithCapacity:num_cols]; + int columnCount = sqlite3_column_count([_statement statement]); - + int columnIdx = 0; for (columnIdx = 0; columnIdx < columnCount; columnIdx++) { - - NSString *columnName = [NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]; + + NSString * columnName = [NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]; id objectValue = [self objectForColumnIndex:columnIdx]; [dict setObject:objectValue forKey:columnName]; } - + return dict; - } - else { + } else { NSLog(@"Warning: There seem to be no columns in this set."); } - + return nil; -} +} /* resultDictionary */ -- (BOOL)next { +- (BOOL) next { return [self nextWithError:nil]; } -- (BOOL)nextWithError:(NSError **)outErr { - +- (BOOL) nextWithError:(NSError **)outErr { + int rc = sqlite3_step([_statement statement]); - + if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) { NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [_parentDB databasePath]); NSLog(@"Database busy"); if (outErr) { *outErr = [_parentDB lastError]; } - } - else if (SQLITE_DONE == rc || SQLITE_ROW == rc) { + } else if (SQLITE_DONE == rc || SQLITE_ROW == rc) { // all is well, let's return. - } - else if (SQLITE_ERROR == rc) { + } else if (SQLITE_ERROR == rc) { NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); if (outErr) { *outErr = [_parentDB lastError]; } - } - else if (SQLITE_MISUSE == rc) { + } else if (SQLITE_MISUSE == rc) { // uh oh. NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); if (outErr) { if (_parentDB) { *outErr = [_parentDB lastError]; - } - else { + } else { // If 'next' or 'nextWithError' is called after the result set is closed, // we need to return the appropriate error. - NSDictionary* errorMessage = [NSDictionary dictionaryWithObject:@"parentDB does not exist" forKey:NSLocalizedDescriptionKey]; + NSDictionary * errorMessage = [NSDictionary dictionaryWithObject:@"parentDB does not exist" forKey:NSLocalizedDescriptionKey]; *outErr = [NSError errorWithDomain:@"CCSQLite" code:SQLITE_MISUSE userInfo:errorMessage]; } - + } - } - else { + } else { // wtf? NSLog(@"Unknown error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); if (outErr) { *outErr = [_parentDB lastError]; } } - - + + if (rc != SQLITE_ROW) { [self close]; } - + return (rc == SQLITE_ROW); -} +} /* nextWithError */ -- (BOOL)hasAnotherRow { +- (BOOL) hasAnotherRow { return sqlite3_errcode([_parentDB sqliteHandle]) == SQLITE_ROW; } -- (int)columnIndexForName:(NSString*)columnName { +- (int) columnIndexForName:(NSString *)columnName { columnName = [columnName lowercaseString]; - - NSNumber *n = [[self columnNameToIndexMap] objectForKey:columnName]; - + + NSNumber * n = [[self columnNameToIndexMap] objectForKey:columnName]; + if (n) { return [n intValue]; } - + NSLog(@"Warning: I could not find the column named '%@'.", columnName); - + return -1; } -- (int)intForColumn:(NSString*)columnName { +- (int) intForColumn:(NSString *)columnName { return [self intForColumnIndex:[self columnIndexForName:columnName]]; } -- (int)intForColumnIndex:(int)columnIdx { +- (int) intForColumnIndex:(int)columnIdx { return sqlite3_column_int([_statement statement], columnIdx); } -- (long)longForColumn:(NSString*)columnName { +- (long) longForColumn:(NSString *)columnName { return [self longForColumnIndex:[self columnIndexForName:columnName]]; } -- (long)longForColumnIndex:(int)columnIdx { +- (long) longForColumnIndex:(int)columnIdx { return (long)sqlite3_column_int64([_statement statement], columnIdx); } -- (long long int)longLongIntForColumn:(NSString*)columnName { +- (long long int) longLongIntForColumn:(NSString *)columnName { return [self longLongIntForColumnIndex:[self columnIndexForName:columnName]]; } -- (long long int)longLongIntForColumnIndex:(int)columnIdx { +- (long long int) longLongIntForColumnIndex:(int)columnIdx { return sqlite3_column_int64([_statement statement], columnIdx); } -- (unsigned long long int)unsignedLongLongIntForColumn:(NSString*)columnName { +- (unsigned long long int) unsignedLongLongIntForColumn:(NSString *)columnName { return [self unsignedLongLongIntForColumnIndex:[self columnIndexForName:columnName]]; } -- (unsigned long long int)unsignedLongLongIntForColumnIndex:(int)columnIdx { +- (unsigned long long int) unsignedLongLongIntForColumnIndex:(int)columnIdx { return (unsigned long long int)[self longLongIntForColumnIndex:columnIdx]; } -- (BOOL)boolForColumn:(NSString*)columnName { +- (BOOL) boolForColumn:(NSString *)columnName { return [self boolForColumnIndex:[self columnIndexForName:columnName]]; } -- (BOOL)boolForColumnIndex:(int)columnIdx { +- (BOOL) boolForColumnIndex:(int)columnIdx { return ([self intForColumnIndex:columnIdx] != 0); } -- (double)doubleForColumn:(NSString*)columnName { +- (double) doubleForColumn:(NSString *)columnName { return [self doubleForColumnIndex:[self columnIndexForName:columnName]]; } -- (double)doubleForColumnIndex:(int)columnIdx { +- (double) doubleForColumnIndex:(int)columnIdx { return sqlite3_column_double([_statement statement], columnIdx); } -- (NSString*)stringForColumnIndex:(int)columnIdx { - +- (NSString *) stringForColumnIndex:(int)columnIdx { + if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { return nil; } - - const char *c = (const char *)sqlite3_column_text([_statement statement], columnIdx); - + + const char * c = (const char *)sqlite3_column_text([_statement statement], columnIdx); + if (!c) { // null row. return nil; } - + return [NSString stringWithUTF8String:c]; } -- (NSString*)stringForColumn:(NSString*)columnName { +- (NSString *) stringForColumn:(NSString *)columnName { return [self stringForColumnIndex:[self columnIndexForName:columnName]]; } -- (NSDate*)dateForColumn:(NSString*)columnName { +- (NSDate *) dateForColumn:(NSString *)columnName { return [self dateForColumnIndex:[self columnIndexForName:columnName]]; } -- (NSDate*)dateForColumnIndex:(int)columnIdx { - +- (NSDate *) dateForColumnIndex:(int)columnIdx { + if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { return nil; } - + return [_parentDB hasDateFormatter] ? [_parentDB dateFromString:[self stringForColumnIndex:columnIdx]] : [NSDate dateWithTimeIntervalSince1970:[self doubleForColumnIndex:columnIdx]]; } -- (NSData*)dataForColumn:(NSString*)columnName { +- (NSData *) dataForColumn:(NSString *)columnName { return [self dataForColumnIndex:[self columnIndexForName:columnName]]; } -- (NSData*)dataForColumnIndex:(int)columnIdx { - +- (NSData *) dataForColumnIndex:(int)columnIdx { + if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { return nil; } - - const char *dataBuffer = sqlite3_column_blob([_statement statement], columnIdx); + + const char * dataBuffer = sqlite3_column_blob([_statement statement], columnIdx); int dataSize = sqlite3_column_bytes([_statement statement], columnIdx); - + if (dataBuffer == NULL) { return nil; } - + return [NSData dataWithBytes:(const void *)dataBuffer length:(NSUInteger)dataSize]; } -- (NSData*)dataNoCopyForColumn:(NSString*)columnName { +- (NSData *) dataNoCopyForColumn:(NSString *)columnName { return [self dataNoCopyForColumnIndex:[self columnIndexForName:columnName]]; } -- (NSData*)dataNoCopyForColumnIndex:(int)columnIdx { - +- (NSData *) dataNoCopyForColumnIndex:(int)columnIdx { + if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { return nil; } - - const char *dataBuffer = sqlite3_column_blob([_statement statement], columnIdx); + + const char * dataBuffer = sqlite3_column_blob([_statement statement], columnIdx); int dataSize = sqlite3_column_bytes([_statement statement], columnIdx); - - NSData *data = [NSData dataWithBytesNoCopy:(void *)dataBuffer length:(NSUInteger)dataSize freeWhenDone:NO]; - + + NSData * data = [NSData dataWithBytesNoCopy:(void *)dataBuffer length:(NSUInteger)dataSize freeWhenDone:NO]; + return data; } -- (BOOL)columnIndexIsNull:(int)columnIdx { +- (BOOL) columnIndexIsNull:(int)columnIdx { return sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL; } -- (BOOL)columnIsNull:(NSString*)columnName { +- (BOOL) columnIsNull:(NSString *)columnName { return [self columnIndexIsNull:[self columnIndexForName:columnName]]; } -- (const unsigned char *)UTF8StringForColumnIndex:(int)columnIdx { - +- (const unsigned char *) UTF8StringForColumnIndex:(int)columnIdx { + if (sqlite3_column_type([_statement statement], columnIdx) == SQLITE_NULL || (columnIdx < 0)) { return nil; } - + return sqlite3_column_text([_statement statement], columnIdx); } -- (const unsigned char *)UTF8StringForColumnName:(NSString*)columnName { +- (const unsigned char *) UTF8StringForColumnName:(NSString *)columnName { return [self UTF8StringForColumnIndex:[self columnIndexForName:columnName]]; } -- (id)objectForColumnIndex:(int)columnIdx { +- (id) objectForColumnIndex:(int)columnIdx { int columnType = sqlite3_column_type([_statement statement], columnIdx); - + id returnValue = nil; - + if (columnType == SQLITE_INTEGER) { returnValue = [NSNumber numberWithLongLong:[self longLongIntForColumnIndex:columnIdx]]; - } - else if (columnType == SQLITE_FLOAT) { + } else if (columnType == SQLITE_FLOAT) { returnValue = [NSNumber numberWithDouble:[self doubleForColumnIndex:columnIdx]]; - } - else if (columnType == SQLITE_BLOB) { + } else if (columnType == SQLITE_BLOB) { returnValue = [self dataForColumnIndex:columnIdx]; - } - else { - //default to a string for everything else + } else { + // default to a string for everything else returnValue = [self stringForColumnIndex:columnIdx]; } - + if (returnValue == nil) { returnValue = [NSNull null]; } - + return returnValue; -} +} /* objectForColumnIndex */ -- (id)objectForColumnName:(NSString*)columnName { +- (id) objectForColumnName:(NSString *)columnName { return [self objectForColumnIndex:[self columnIndexForName:columnName]]; } // returns autoreleased NSString containing the name of the column in the result set -- (NSString*)columnNameForIndex:(int)columnIdx { - return [NSString stringWithUTF8String: sqlite3_column_name([_statement statement], columnIdx)]; +- (NSString *) columnNameForIndex:(int)columnIdx { + return [NSString stringWithUTF8String:sqlite3_column_name([_statement statement], columnIdx)]; } -- (void)setParentDB:(CCSQLite *)newDb { +- (void) setParentDB:(CCSQLite *)newDb { _parentDB = newDb; } -- (id)objectAtIndexedSubscript:(int)columnIdx { +- (id) objectAtIndexedSubscript:(int)columnIdx { return [self objectForColumnIndex:columnIdx]; } -- (id)objectForKeyedSubscript:(NSString *)columnName { +- (id) objectForKeyedSubscript:(NSString *)columnName { return [self objectForColumnName:columnName]; } diff --git a/CCSQLite/CCSQLite.m b/CCSQLite/CCSQLite.m index 1fa6c54..791c21f 100644 --- a/CCSQLite/CCSQLite.m +++ b/CCSQLite/CCSQLite.m @@ -18,51 +18,49 @@ * avoid Yapdatabase repeat | [Embeded CCSQLiteCollection] * new add [Embeded CCSQLiteCollection] */ -NSString *CCSQLiteDatabase2 = @"CCSQLite.Database2"; -NSString *CCSQLiteCollection = @"CCSQLite.Collection"; - -static int connectionBusyHandler(void *ptr, int count) { - CCSQLite * currentDatabase = (__bridge CCSQLite*)ptr; - - usleep(50*1000); // sleep 50ms - +NSString * CCSQLiteDatabase2 = @"CCSQLite.Database2"; +NSString * CCSQLiteCollection = @"CCSQLite.Collection"; + +static int connectionBusyHandler(void * ptr, int count) { + CCSQLite * currentDatabase = (__bridge CCSQLite *)ptr; + + usleep(50 * 1000); // sleep 50ms + if (count % 4 == 1) { // log every 4th attempt but not the first one NSLog(@"Cannot obtain busy lock on SQLite from database (%p), is another process locking the database? Retrying in 50ms...", currentDatabase); } - + return 1; } @interface CCSQLite () { - void* _db; - NSString* _databasePath; - - BOOL _shouldCacheStatements; - BOOL _isExecutingStatement; - BOOL _inTransaction; - NSTimeInterval _maxBusyRetryTimeInterval; - NSTimeInterval _startBusyRetryTime; - - NSMutableSet *_openResultSets; - NSMutableSet *_openFunctions; - - NSDateFormatter *_dateFormat; -} - -- (CCResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args; -- (BOOL)executeUpdate:(NSString*)sql error:(NSError**)outErr withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args; + void * _db; + NSString * _databasePath; + + BOOL _shouldCacheStatements; + BOOL _isExecutingStatement; + BOOL _inTransaction; + NSTimeInterval _maxBusyRetryTimeInterval; + NSTimeInterval _startBusyRetryTime; + + NSMutableSet * _openResultSets; + NSMutableSet * _openFunctions; + + NSDateFormatter * _dateFormat; +} + +- (CCResultSet *) executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args; +- (BOOL) executeUpdate:(NSString *)sql error:(NSError **)outErr withArgumentsInArray:(NSArray *)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args; @end @implementation CCSQLite -- (NSString *)databasePath_wal -{ +- (NSString *) databasePath_wal { return [[self databasePath] stringByAppendingString:@"-wal"]; } -- (NSString *)databasePath_shm -{ +- (NSString *) databasePath_shm { return [[self databasePath] stringByAppendingString:@"-shm"]; } @@ -70,10 +68,9 @@ - (NSString *)databasePath_shm * The default serializer & deserializer use NSCoding (NSKeyedArchiver & NSKeyedUnarchiver). * Thus the objects need only support the NSCoding protocol. **/ -+ (CCSQLiteSerializer)defaultSerializer -{ - return ^ NSData* (NSString __unused *collection, NSString __unused *key, id object){ - return [NSKeyedArchiver archivedDataWithRootObject:object]; ++ (CCSQLiteSerializer) defaultSerializer { + return ^NSData * (NSString __unused * collection, NSString __unused * key, id object){ + return [NSKeyedArchiver archivedDataWithRootObject:object]; }; } @@ -81,10 +78,9 @@ + (CCSQLiteSerializer)defaultSerializer * The default serializer & deserializer use NSCoding (NSKeyedArchiver & NSKeyedUnarchiver). * Thus the objects need only support the NSCoding protocol. **/ -+ (CCSQLiteDeserializer)defaultDeserializer -{ - return ^ id (NSString __unused *collection, NSString __unused *key, NSData *data){ - return data && data.length > 0 ? [NSKeyedUnarchiver unarchiveObjectWithData:data] : nil; ++ (CCSQLiteDeserializer) defaultDeserializer { + return ^id (NSString __unused * collection, NSString __unused * key, NSData * data){ + return data && data.length > 0 ? [NSKeyedUnarchiver unarchiveObjectWithData:data] : nil; }; } @@ -95,13 +91,12 @@ + (CCSQLiteDeserializer)defaultDeserializer * Property lists make a good fit when your existing code already uses them, * such as replacing NSUserDefaults with a database. **/ -+ (CCSQLiteSerializer)propertyListSerializer -{ - return ^ NSData* (NSString __unused *collection, NSString __unused *key, id object){ - return [NSPropertyListSerialization dataWithPropertyList:object - format:NSPropertyListBinaryFormat_v1_0 - options:NSPropertyListImmutable - error:NULL]; ++ (CCSQLiteSerializer) propertyListSerializer { + return ^NSData * (NSString __unused * collection, NSString __unused * key, id object){ + return [NSPropertyListSerialization dataWithPropertyList:object + format:NSPropertyListBinaryFormat_v1_0 + options:NSPropertyListImmutable + error:NULL]; }; } @@ -112,10 +107,9 @@ + (CCSQLiteSerializer)propertyListSerializer * Property lists make a good fit when your existing code already uses them, * such as replacing NSUserDefaults with a database. **/ -+ (CCSQLiteDeserializer)propertyListDeserializer -{ - return ^ id (NSString __unused *collection, NSString __unused *key, NSData *data){ - return [NSPropertyListSerialization propertyListWithData:data options:0 format:NULL error:NULL]; ++ (CCSQLiteDeserializer) propertyListDeserializer { + return ^id (NSString __unused * collection, NSString __unused * key, NSData * data){ + return [NSPropertyListSerialization propertyListWithData:data options:0 format:NULL error:NULL]; }; } @@ -123,20 +117,16 @@ + (CCSQLiteDeserializer)propertyListDeserializer * A FASTER serializer than the default, if serializing ONLY a NSDate object. * You may want to use timestampSerializer & timestampDeserializer if your metadata is simply an NSDate. **/ -+ (CCSQLiteSerializer)timestampSerializer -{ - return ^ NSData* (NSString __unused *collection, NSString __unused *key, id object) { - - if ([object isKindOfClass:[NSDate class]]) - { - NSTimeInterval timestamp = [(NSDate *)object timeIntervalSinceReferenceDate]; - - return [[NSData alloc] initWithBytes:(void *)×tamp length:sizeof(NSTimeInterval)]; - } - else - { - return [NSKeyedArchiver archivedDataWithRootObject:object]; - } ++ (CCSQLiteSerializer) timestampSerializer { + return ^NSData * (NSString __unused * collection, NSString __unused * key, id object) { + + if ([object isKindOfClass:[NSDate class]]) { + NSTimeInterval timestamp = [(NSDate *)object timeIntervalSinceReferenceDate]; + + return [[NSData alloc] initWithBytes:(void *)×tamp length:sizeof(NSTimeInterval)]; + } else { + return [NSKeyedArchiver archivedDataWithRootObject:object]; + } }; } @@ -144,48 +134,44 @@ + (CCSQLiteSerializer)timestampSerializer * A FASTER deserializer than the default, if deserializing data from timestampSerializer. * You may want to use timestampSerializer & timestampDeserializer if your metadata is simply an NSDate. **/ -+ (CCSQLiteDeserializer)timestampDeserializer -{ - return ^ id (NSString __unused *collection, NSString __unused *key, NSData *data) { - - if ([data length] == sizeof(NSTimeInterval)) - { - NSTimeInterval timestamp; - memcpy((void *)×tamp, [data bytes], sizeof(NSTimeInterval)); - - return [[NSDate alloc] initWithTimeIntervalSinceReferenceDate:timestamp]; - } - else - { - return [NSKeyedUnarchiver unarchiveObjectWithData:data]; - } ++ (CCSQLiteDeserializer) timestampDeserializer { + return ^id (NSString __unused * collection, NSString __unused * key, NSData * data) { + + if ([data length] == sizeof(NSTimeInterval)) { + NSTimeInterval timestamp; + memcpy((void *)×tamp, [data bytes], sizeof(NSTimeInterval)); + + return [[NSDate alloc] initWithTimeIntervalSinceReferenceDate:timestamp]; + } else { + return [NSKeyedUnarchiver unarchiveObjectWithData:data]; + } }; } + (CCSQLiteSerializer) jsonSerializer { - return ^NSData* (NSString *collection, NSString *key, id object) { - if ([object isKindOfClass:[NSString class]]) { - NSString *data = object; - return [data dataUsingEncoding:NSUTF8StringEncoding]; - } else if ([object isKindOfClass:[NSData class]]) { - return object; - } else { - NSLog(@"error args for object"); - return nil; - } + return ^NSData * (NSString * collection, NSString * key, id object) { + if ([object isKindOfClass:[NSString class]]) { + NSString * data = object; + return [data dataUsingEncoding:NSUTF8StringEncoding]; + } else if ([object isKindOfClass:[NSData class]]) { + return object; + } else { + NSLog(@"error args for object"); + return nil; + } }; } + (CCSQLiteDeserializer) jsonDeserializer { - return ^id (NSString *collection, NSString *key, NSData *data) { - NSError *error = nil; - id object = [NSJSONSerialization JSONObjectWithData: data options:NSJSONReadingMutableContainers error:&error]; - - if (error) { - NSLog(@"jsonDeserializer : %@", error);; - } - - return object; + return ^id (NSString * collection, NSString * key, NSData * data) { + NSError * error = nil; + id object = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error]; + + if (error) { + NSLog(@"jsonDeserializer : %@", error);; + } + + return object; }; } @@ -198,87 +184,78 @@ + (CCSQLiteDeserializer) jsonDeserializer { /** * Attempts to open (or create & open) the database connection. **/ -- (BOOL)openDatabase -{ +- (BOOL) openDatabase { // Open the database connection. // // We use SQLITE_OPEN_NOMUTEX to use the multi-thread threading mode, // as we will be serializing access to the connection externally. - + int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_PRIVATECACHE; - + #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wincompatible-pointer-types" int status = sqlite3_open_v2([[self databasePath] UTF8String], &_db, flags, NULL); #pragma clang diagnostic pop - - if (status != SQLITE_OK) - { + + if (status != SQLITE_OK) { // There are a few reasons why the database might not open. // One possibility is if the database file has become corrupt. - + // Sometimes the open function returns a db to allow us to query it for the error message. // The openConfigCreate block will close it for us. if (_db) { NSLog(@"Error opening database: %d %s", status, sqlite3_errmsg(_db)); - } - else { + } else { NSLog(@"Error opening database: %d", status); } - + return NO; } // Add a busy handler if we are in multiprocess mode if (_options.enableMultiProcessSupport) { sqlite3_busy_handler(_db, connectionBusyHandler, (__bridge void *)(self)); } - + return YES; -} +} /* openDatabase */ /** * Configures the database connection. * This mainly means enabling WAL mode, and configuring the auto-checkpoint. **/ -- (BOOL)configureDatabase:(BOOL)isNewDatabaseFile -{ +- (BOOL) configureDatabase:(BOOL)isNewDatabaseFile { int status; - + // Set mandatory pragmas - - if (isNewDatabaseFile && (_options.pragmaPageSize > 0)) - { - NSString *pragma_page_size = - [NSString stringWithFormat:@"PRAGMA page_size = %ld;", (long)_options.pragmaPageSize]; - + + if (isNewDatabaseFile && (_options.pragmaPageSize > 0)) { + NSString * pragma_page_size = + [NSString stringWithFormat:@"PRAGMA page_size = %ld;", (long)_options.pragmaPageSize]; + status = sqlite3_exec(_db, [pragma_page_size UTF8String], NULL, NULL, NULL); - if (status != SQLITE_OK) - { + if (status != SQLITE_OK) { NSLog(@"Error setting PRAGMA page_size: %d %s", status, sqlite3_errmsg(_db)); } } - + #if SQLITE_VERSION_NUMBER >= 3007000 status = sqlite3_exec(_db, "PRAGMA journal_mode = WAL;", NULL, NULL, NULL); - if (status != SQLITE_OK) - { + if (status != SQLITE_OK) { NSLog(@"Error setting PRAGMA journal_mode: %d %s", status, sqlite3_errmsg(_db)); return NO; } else if (status == SQLITE_READONLY) { NSLog(@"Attempt to write a readonly database : close journal_mode. or At the same time increase the database read and write permissions "); - status = SQLITE_OK; + status = SQLITE_OK; } #endif - - if (isNewDatabaseFile) - { + + if (isNewDatabaseFile) { status = sqlite3_exec(_db, "PRAGMA auto_vacuum = FULL; VACUUM;", NULL, NULL, NULL); - if (status != SQLITE_OK) - { + if (status != SQLITE_OK) { NSLog(@"Error setting PRAGMA auto_vacuum: %d %s", status, sqlite3_errmsg(_db)); } } - + // Set synchronous to normal for THIS sqlite instance. // // This does NOT affect normal connections. @@ -292,46 +269,42 @@ - (BOOL)configureDatabase:(BOOL)isNewDatabaseFile // (This sqlite db is also used to perform checkpoints. // But a normal value won't affect these operations, // as they will perform sync operations whether the connection is normal or full.) - + status = sqlite3_exec(_db, "PRAGMA synchronous = NORMAL;", NULL, NULL, NULL); - if (status != SQLITE_OK) - { + if (status != SQLITE_OK) { NSLog(@"Error setting PRAGMA synchronous: %d %s", status, sqlite3_errmsg(_db)); // This isn't critical, so we can continue. } - + // Set journal_size_imit. // // We only need to do set this pragma for THIS connection, // because it is the only connection that performs checkpoints. - - NSString *pragma_journal_size_limit = - [NSString stringWithFormat:@"PRAGMA journal_size_limit = %ld;", (long)_options.pragmaJournalSizeLimit]; - + + NSString * pragma_journal_size_limit = + [NSString stringWithFormat:@"PRAGMA journal_size_limit = %ld;", (long)_options.pragmaJournalSizeLimit]; + status = sqlite3_exec(_db, [pragma_journal_size_limit UTF8String], NULL, NULL, NULL); - if (status != SQLITE_OK) - { + if (status != SQLITE_OK) { NSLog(@"Error setting PRAGMA journal_size_limit: %d %s", status, sqlite3_errmsg(_db)); // This isn't critical, so we can continue. } - + // Set mmap_size (if needed). // // This configures memory mapped I/O. - - if (_options.pragmaMMapSize > 0) - { - NSString *pragma_mmap_size = - [NSString stringWithFormat:@"PRAGMA mmap_size = %ld;", (long)_options.pragmaMMapSize]; - + + if (_options.pragmaMMapSize > 0) { + NSString * pragma_mmap_size = + [NSString stringWithFormat:@"PRAGMA mmap_size = %ld;", (long)_options.pragmaMMapSize]; + status = sqlite3_exec(_db, [pragma_mmap_size UTF8String], NULL, NULL, NULL); - if (status != SQLITE_OK) - { + if (status != SQLITE_OK) { NSLog(@"Error setting PRAGMA mmap_size: %d %s", status, sqlite3_errmsg(_db)); // This isn't critical, so we can continue. } } - + // Disable autocheckpointing. // // YapDatabase has its own optimized checkpointing algorithm built-in. @@ -341,71 +314,64 @@ - (BOOL)configureDatabase:(BOOL)isNewDatabaseFile #if SQLITE_VERSION_NUMBER >= 3007000 sqlite3_wal_autocheckpoint(_db, 0); #endif - + return YES; -} +} /* configureDatabase */ #ifdef SQLITE_HAS_CODEC /** * Configures database encryption via SQLCipher. **/ -- (BOOL)configureEncryptionForDatabase:(sqlite3 *)sqlite -{ - if (_options.cipherKeyBlock) - { - NSData *keyData = _options.cipherKeyBlock(); - - if (keyData == nil) - { +- (BOOL) configureEncryptionForDatabase:(sqlite3 *)sqlite { + if (_options.cipherKeyBlock) { + NSData * keyData = _options.cipherKeyBlock(); + + if (keyData == nil) { NSAssert(NO, @"CCOptions.cipherKeyBlock cannot return nil!"); return NO; } - - //Setting the PBKDF2 default iteration number (this will have effect next time database is opened) + + // Setting the PBKDF2 default iteration number (this will have effect next time database is opened) if (_options.cipherDefaultkdfIterNumber > 0) { - char *errorMsg; - NSString *pragmaCommand = [NSString stringWithFormat:@"PRAGMA cipher_default_kdf_iter = %lu", (unsigned long)_options.cipherDefaultkdfIterNumber]; - if (sqlite3_exec(sqlite, [pragmaCommand UTF8String], NULL, NULL, &errorMsg) != SQLITE_OK) - { + char * errorMsg; + NSString * pragmaCommand = [NSString stringWithFormat:@"PRAGMA cipher_default_kdf_iter = %lu", (unsigned long)_options.cipherDefaultkdfIterNumber]; + if (sqlite3_exec(sqlite, [pragmaCommand UTF8String], NULL, NULL, &errorMsg) != SQLITE_OK) { NSLog(@"failed to set database cipher_default_kdf_iter: %s", errorMsg); return NO; } } - - //Setting the PBKDF2 iteration number + + // Setting the PBKDF2 iteration number if (_options.kdfIterNumber > 0) { - char *errorMsg; - NSString *pragmaCommand = [NSString stringWithFormat:@"PRAGMA kdf_iter = %lu", (unsigned long)_options.kdfIterNumber]; - if (sqlite3_exec(sqlite, [pragmaCommand UTF8String], NULL, NULL, &errorMsg) != SQLITE_OK) - { + char * errorMsg; + NSString * pragmaCommand = [NSString stringWithFormat:@"PRAGMA kdf_iter = %lu", (unsigned long)_options.kdfIterNumber]; + if (sqlite3_exec(sqlite, [pragmaCommand UTF8String], NULL, NULL, &errorMsg) != SQLITE_OK) { NSLog(@"failed to set database kdf_iter: %s", errorMsg); return NO; } } - - //Setting the encrypted database page size + + // Setting the encrypted database page size if (_options.cipherPageSize > 0) { - char *errorMsg; - NSString *pragmaCommand = [NSString stringWithFormat:@"PRAGMA cipher_page_size = %lu", (unsigned long)_options.cipherPageSize]; - if (sqlite3_exec(sqlite, [pragmaCommand UTF8String], NULL, NULL, &errorMsg) != SQLITE_OK) - { + char * errorMsg; + NSString * pragmaCommand = [NSString stringWithFormat:@"PRAGMA cipher_page_size = %lu", (unsigned long)_options.cipherPageSize]; + if (sqlite3_exec(sqlite, [pragmaCommand UTF8String], NULL, NULL, &errorMsg) != SQLITE_OK) { NSLog(@"failed to set database cipher_page_size: %s", errorMsg); return NO; } } - + int status = sqlite3_key(sqlite, [keyData bytes], (int)[keyData length]); - if (status != SQLITE_OK) - { + if (status != SQLITE_OK) { NSLog(@"Error setting SQLCipher key: %d %s", status, sqlite3_errmsg(sqlite)); return NO; } } - + return YES; -} -#endif +} /* configureEncryptionForDatabase */ +#endif /* ifdef SQLITE_HAS_CODEC */ /** * Creates the database tables we need: @@ -413,46 +379,43 @@ - (BOOL)configureEncryptionForDatabase:(sqlite3 *)sqlite * - yap2 : stores snapshot and metadata for extensions * - CCSQLite.Database2 : stores collection/key/value/metadata rows **/ -- (BOOL)createTables -{ +- (BOOL) createTables { int status; - - char *createDatabaseTableStatement = - "CREATE TABLE IF NOT EXISTS \"CCSQLite.Database2\"" - " (\"rowid\" INTEGER PRIMARY KEY," - " \"collection\" CHAR NOT NULL," - " \"key\" CHAR NOT NULL," - " \"data\" BLOB," - " \"metadata\" BLOB" - " );"; - + + char * createDatabaseTableStatement = + "CREATE TABLE IF NOT EXISTS \"CCSQLite.Database2\"" + " (\"rowid\" INTEGER PRIMARY KEY," + " \"collection\" CHAR NOT NULL," + " \"key\" CHAR NOT NULL," + " \"data\" BLOB," + " \"metadata\" BLOB" + " );"; + status = sqlite3_exec(_db, createDatabaseTableStatement, NULL, NULL, NULL); - if (status != SQLITE_OK) - { + if (status != SQLITE_OK) { NSLog(@"Failed creating 'CCSQLite.Database2' table: %d %s", status, sqlite3_errmsg(_db)); return NO; } - - char *createIndexStatement = - "CREATE UNIQUE INDEX IF NOT EXISTS \"true_primary_key\" ON \"CCSQLite.Database2\" ( \"collection\", \"key\" );"; - + + char * createIndexStatement = + "CREATE UNIQUE INDEX IF NOT EXISTS \"true_primary_key\" ON \"CCSQLite.Database2\" ( \"collection\", \"key\" );"; + status = sqlite3_exec(_db, createIndexStatement, NULL, NULL, NULL); - if (status != SQLITE_OK) - { + if (status != SQLITE_OK) { NSLog(@"Failed creating index on 'CCSQLite.Database2' table: %d %s", status, sqlite3_errmsg(_db)); return NO; } return YES; -} +} /* createTables */ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #pragma mark Init //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -//- (id)initWithPath:(NSString *)inPath -//{ +// - (id)initWithPath:(NSString *)inPath +// { // return [self initWithPath:inPath // objectSerializer:NULL // objectDeserializer:NULL @@ -463,286 +426,259 @@ - (BOOL)createTables // metadataPreSanitizer:NULL // metadataPostSanitizer:NULL // options:nil]; -//} +// } -- (id)initWithPath:(NSString *)inPath - options:(nullable CCOptions *)inOptions -{ +- (id) initWithPath:(NSString *)inPath + options:(nullable CCOptions *)inOptions { return [self initWithPath:inPath - objectSerializer:NULL - objectDeserializer:NULL - metadataSerializer:NULL - metadataDeserializer:NULL - objectPreSanitizer:NULL - objectPostSanitizer:NULL - metadataPreSanitizer:NULL - metadataPostSanitizer:NULL - options:inOptions]; -} - -- (id)initWithPath:(NSString *)inPath - serializer:(CCSQLiteSerializer)inSerializer - deserializer:(CCSQLiteDeserializer)inDeserializer -{ + objectSerializer:NULL + objectDeserializer:NULL + metadataSerializer:NULL + metadataDeserializer:NULL + objectPreSanitizer:NULL + objectPostSanitizer:NULL + metadataPreSanitizer:NULL + metadataPostSanitizer:NULL + options:inOptions]; +} + +- (id) initWithPath:(NSString *)inPath + serializer:(CCSQLiteSerializer)inSerializer + deserializer:(CCSQLiteDeserializer)inDeserializer { return [self initWithPath:inPath - objectSerializer:inSerializer - objectDeserializer:inDeserializer - metadataSerializer:inSerializer - metadataDeserializer:inDeserializer - objectPreSanitizer:NULL - objectPostSanitizer:NULL - metadataPreSanitizer:NULL - metadataPostSanitizer:NULL - options:nil]; -} - -- (id)initWithPath:(NSString *)inPath - serializer:(CCSQLiteSerializer)inSerializer - deserializer:(CCSQLiteDeserializer)inDeserializer - options:(CCOptions *)inOptions -{ + objectSerializer:inSerializer + objectDeserializer:inDeserializer + metadataSerializer:inSerializer + metadataDeserializer:inDeserializer + objectPreSanitizer:NULL + objectPostSanitizer:NULL + metadataPreSanitizer:NULL + metadataPostSanitizer:NULL + options:nil]; +} + +- (id) initWithPath:(NSString *)inPath + serializer:(CCSQLiteSerializer)inSerializer + deserializer:(CCSQLiteDeserializer)inDeserializer + options:(CCOptions *)inOptions { return [self initWithPath:inPath - objectSerializer:inSerializer - objectDeserializer:inDeserializer - metadataSerializer:inSerializer - metadataDeserializer:inDeserializer - objectPreSanitizer:NULL - objectPostSanitizer:NULL - metadataPreSanitizer:NULL - metadataPostSanitizer:NULL - options:inOptions]; -} - -- (id)initWithPath:(NSString *)inPath - serializer:(CCSQLiteSerializer)inSerializer - deserializer:(CCSQLiteDeserializer)inDeserializer - preSanitizer:(CCSQLitePreSanitizerr)inPreSanitizer - postSanitizer:(CCSQLitePostSanitizer)inPostSanitizer - options:(CCOptions *)inOptions -{ + objectSerializer:inSerializer + objectDeserializer:inDeserializer + metadataSerializer:inSerializer + metadataDeserializer:inDeserializer + objectPreSanitizer:NULL + objectPostSanitizer:NULL + metadataPreSanitizer:NULL + metadataPostSanitizer:NULL + options:inOptions]; +} + +- (id) initWithPath:(NSString *)inPath + serializer:(CCSQLiteSerializer)inSerializer + deserializer:(CCSQLiteDeserializer)inDeserializer + preSanitizer:(CCSQLitePreSanitizerr)inPreSanitizer + postSanitizer:(CCSQLitePostSanitizer)inPostSanitizer + options:(CCOptions *)inOptions { return [self initWithPath:inPath - objectSerializer:inSerializer - objectDeserializer:inDeserializer - metadataSerializer:inSerializer - metadataDeserializer:inDeserializer - objectPreSanitizer:inPreSanitizer - objectPostSanitizer:inPostSanitizer - metadataPreSanitizer:inPreSanitizer - metadataPostSanitizer:inPostSanitizer - options:inOptions]; -} - -- (id)initWithPath:(NSString *)inPath objectSerializer:(CCSQLiteSerializer)inObjectSerializer -objectDeserializer:(CCSQLiteDeserializer)inObjectDeserializer -metadataSerializer:(CCSQLiteSerializer)inMetadataSerializer -metadataDeserializer:(CCSQLiteDeserializer)inMetadataDeserializer -{ + objectSerializer:inSerializer + objectDeserializer:inDeserializer + metadataSerializer:inSerializer + metadataDeserializer:inDeserializer + objectPreSanitizer:inPreSanitizer + objectPostSanitizer:inPostSanitizer + metadataPreSanitizer:inPreSanitizer + metadataPostSanitizer:inPostSanitizer + options:inOptions]; +} + +- (id) initWithPath:(NSString *)inPath objectSerializer:(CCSQLiteSerializer)inObjectSerializer + objectDeserializer:(CCSQLiteDeserializer)inObjectDeserializer + metadataSerializer:(CCSQLiteSerializer)inMetadataSerializer + metadataDeserializer:(CCSQLiteDeserializer)inMetadataDeserializer { return [self initWithPath:inPath - objectSerializer:inObjectSerializer - objectDeserializer:inObjectDeserializer - metadataSerializer:inMetadataSerializer - metadataDeserializer:inMetadataDeserializer - objectPreSanitizer:NULL - objectPostSanitizer:NULL - metadataPreSanitizer:NULL - metadataPostSanitizer:NULL - options:nil]; -} - -- (id)initWithPath:(NSString *)inPath objectSerializer:(CCSQLiteSerializer)inObjectSerializer -objectDeserializer:(CCSQLiteDeserializer)inObjectDeserializer -metadataSerializer:(CCSQLiteSerializer)inMetadataSerializer -metadataDeserializer:(CCSQLiteDeserializer)inMetadataDeserializer - options:(CCOptions *)inOptions -{ + objectSerializer:inObjectSerializer + objectDeserializer:inObjectDeserializer + metadataSerializer:inMetadataSerializer + metadataDeserializer:inMetadataDeserializer + objectPreSanitizer:NULL + objectPostSanitizer:NULL + metadataPreSanitizer:NULL + metadataPostSanitizer:NULL + options:nil]; +} + +- (id) initWithPath:(NSString *)inPath objectSerializer:(CCSQLiteSerializer)inObjectSerializer + objectDeserializer:(CCSQLiteDeserializer)inObjectDeserializer + metadataSerializer:(CCSQLiteSerializer)inMetadataSerializer + metadataDeserializer:(CCSQLiteDeserializer)inMetadataDeserializer + options:(CCOptions *)inOptions { return [self initWithPath:inPath - objectSerializer:inObjectSerializer - objectDeserializer:inObjectDeserializer - metadataSerializer:inMetadataSerializer - metadataDeserializer:inMetadataDeserializer - objectPreSanitizer:NULL - objectPostSanitizer:NULL - metadataPreSanitizer:NULL - metadataPostSanitizer:NULL - options:inOptions]; -} - -- (id)initWithPath:(NSString *)inPath objectSerializer:(CCSQLiteSerializer)inObjectSerializer -objectDeserializer:(CCSQLiteDeserializer)inObjectDeserializer -metadataSerializer:(CCSQLiteSerializer)inMetadataSerializer -metadataDeserializer:(CCSQLiteDeserializer)inMetadataDeserializer -objectPreSanitizer:(CCSQLitePreSanitizerr)inObjectPreSanitizer -objectPostSanitizer:(CCSQLitePostSanitizer)inObjectPostSanitizer -metadataPreSanitizer:(CCSQLitePreSanitizerr)inMetadataPreSanitizer -metadataPostSanitizer:(CCSQLitePostSanitizer)inMetadataPostSanitizer - options:(CCOptions *)inOptions -{ + objectSerializer:inObjectSerializer + objectDeserializer:inObjectDeserializer + metadataSerializer:inMetadataSerializer + metadataDeserializer:inMetadataDeserializer + objectPreSanitizer:NULL + objectPostSanitizer:NULL + metadataPreSanitizer:NULL + metadataPostSanitizer:NULL + options:inOptions]; +} + +- (id) initWithPath:(NSString *)inPath objectSerializer:(CCSQLiteSerializer)inObjectSerializer + objectDeserializer:(CCSQLiteDeserializer)inObjectDeserializer + metadataSerializer:(CCSQLiteSerializer)inMetadataSerializer + metadataDeserializer:(CCSQLiteDeserializer)inMetadataDeserializer + objectPreSanitizer:(CCSQLitePreSanitizerr)inObjectPreSanitizer + objectPostSanitizer:(CCSQLitePostSanitizer)inObjectPostSanitizer + metadataPreSanitizer:(CCSQLitePreSanitizerr)inMetadataPreSanitizer + metadataPostSanitizer:(CCSQLitePostSanitizer)inMetadataPostSanitizer + options:(CCOptions *)inOptions { // First, standardize path. // This allows clients to be lazy when passing paths. - NSString *path = [inPath stringByStandardizingPath]; - - if ((self = [super init])) - { + NSString * path = [inPath stringByStandardizingPath]; + + if ((self = [super init])) { _databasePath = path; _options = inOptions ? [inOptions copy] : [[CCOptions alloc] init]; - - __block BOOL isNewDatabaseFile = ![[NSFileManager defaultManager] fileExistsAtPath: [self databasePath]]; - - BOOL(^openConfigCreate)(void) = ^BOOL (void) { @autoreleasepool { - - BOOL result = YES; - - if (result) result = [self openDatabase]; + + __block BOOL isNewDatabaseFile = ![[NSFileManager defaultManager] fileExistsAtPath:[self databasePath]]; + + BOOL (^ openConfigCreate)(void) = ^BOOL (void) { @autoreleasepool { + + BOOL result = YES; + + if (result) result = [self openDatabase]; #ifdef SQLITE_HAS_CODEC - if (result) result = [self configureEncryptionForDatabase: _db]; + if (result) result = [self configureEncryptionForDatabase:_db]; #endif - if (result) result = [self configureDatabase:isNewDatabaseFile]; - if (result) result = [self createTables]; - - if (!result && _db) - { - sqlite3_close(_db); - _db = NULL; - } - - return result; - }}; - + if (result) result = [self configureDatabase:isNewDatabaseFile]; + if (result) result = [self createTables]; + + if (!result && _db) { + sqlite3_close(_db); + _db = NULL; + } + + return result; + } }; + BOOL result = openConfigCreate(); - if (!result) - { + if (!result) { // There are a few reasons why the database might not open. // One possibility is if the database file has become corrupt. - - if (_options.corruptAction == CCOptionsCorruptAction_Fail) - { + + if (_options.corruptAction == CCOptionsCorruptAction_Fail) { // Fail - do not try to resolve - } - else if (_options.corruptAction == CCOptionsCorruptAction_Rename) - { + } else if (_options.corruptAction == CCOptionsCorruptAction_Rename) { // Try to rename the corrupt database file. - + BOOL renamed = NO; BOOL failed = NO; - - NSString *newDatabasePath = nil; + + NSString * newDatabasePath = nil; int i = 0; - - do - { - NSString *extension = [NSString stringWithFormat:@"%d.corrupt", i]; + + do { + NSString * extension = [NSString stringWithFormat:@"%d.corrupt", i]; newDatabasePath = [[self databasePath] stringByAppendingPathExtension:extension]; - - if ([[NSFileManager defaultManager] fileExistsAtPath:newDatabasePath]) - { + + if ([[NSFileManager defaultManager] fileExistsAtPath:newDatabasePath]) { i++; - } - else - { - NSError *error = nil; + } else { + NSError * error = nil; renamed = [[NSFileManager defaultManager] moveItemAtPath:[self databasePath] toPath:newDatabasePath error:&error]; - if (!renamed) - { + if (!renamed) { failed = YES; NSLog(@"Error renaming corrupt database file: (%@ -> %@) %@", - [[self databasePath] lastPathComponent], [newDatabasePath lastPathComponent], error); + [[self databasePath] lastPathComponent], [newDatabasePath lastPathComponent], error); } } - + } while (i < INT_MAX && !renamed && !failed); - - if (renamed) - { + + if (renamed) { isNewDatabaseFile = YES; result = openConfigCreate(); if (result) { NSLog(@"Database corruption resolved. Renamed corrupt file. (newDB=%@) (corruptDB=%@)", - [[self databasePath] lastPathComponent], [newDatabasePath lastPathComponent]); - } - else { + [[self databasePath] lastPathComponent], [newDatabasePath lastPathComponent]); + } else { NSLog(@"Database corruption unresolved. (name=%@)", [[self databasePath] lastPathComponent]); } } - - } - else // if (options.corruptAction == CCOptionsCorruptAction_Delete) - { - // Try to delete the corrupt database file. - - NSError *error = nil; + + } else { // if (options.corruptAction == CCOptionsCorruptAction_Delete) + // Try to delete the corrupt database file. + + NSError * error = nil; BOOL deleted = [[NSFileManager defaultManager] removeItemAtPath:path error:&error]; - - if (deleted) - { + + if (deleted) { isNewDatabaseFile = YES; result = openConfigCreate(); if (result) { NSLog(@"Database corruption resolved. Deleted corrupt file. (name=%@)", - [[self databasePath] lastPathComponent]); - } - else { + [[self databasePath] lastPathComponent]); + } else { NSLog(@"Database corruption unresolved. (name=%@)", [[self databasePath] lastPathComponent]); } - } - else - { + } else { NSLog(@"Error deleting corrupt database file: %@", error); } } } - if (!result) - { + if (!result) { return nil; } - - + + // Initialize variables - + CCSQLiteSerializer defaultSerializer = nil; CCSQLiteDeserializer defaultDeserializer = nil; - + if (!inObjectSerializer || !inMetadataSerializer) defaultSerializer = [[self class] defaultSerializer]; - + if (!inObjectDeserializer || !inMetadataDeserializer) defaultDeserializer = [[self class] defaultDeserializer]; - - _objectSerializer = (CCSQLiteSerializer)[inObjectSerializer copy] ?: defaultSerializer; - _objectDeserializer = (CCSQLiteDeserializer)[inObjectDeserializer copy] ?: defaultDeserializer; - - _metadataSerializer = (CCSQLiteSerializer)[inMetadataSerializer copy] ?: defaultSerializer; - _metadataDeserializer = (CCSQLiteDeserializer)[inMetadataDeserializer copy] ?: defaultDeserializer; - + + _objectSerializer = (CCSQLiteSerializer)[inObjectSerializer copy] ? : defaultSerializer; + _objectDeserializer = (CCSQLiteDeserializer)[inObjectDeserializer copy] ? : defaultDeserializer; + + _metadataSerializer = (CCSQLiteSerializer)[inMetadataSerializer copy] ? : defaultSerializer; + _metadataDeserializer = (CCSQLiteDeserializer)[inMetadataDeserializer copy] ? : defaultDeserializer; + _objectPreSanitizer = (CCSQLitePreSanitizerr)[inObjectPreSanitizer copy]; _objectPostSanitizer = (CCSQLitePostSanitizer)[inObjectPostSanitizer copy]; - + _metadataPreSanitizer = (CCSQLitePreSanitizerr)[inMetadataPreSanitizer copy]; _metadataPostSanitizer = (CCSQLitePostSanitizer)[inMetadataPostSanitizer copy]; } return self; -} +} /* initWithPath */ //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #pragma mark CCSQLite instantiation and deallocation -+ (instancetype)databaseWithPath:(NSString*)aPath { ++ (instancetype) databaseWithPath:(NSString *)aPath { return CCReturnAutoreleased([[self alloc] initWithPath:aPath]); } -- (instancetype)init { +- (instancetype) init { return [self initWithPath:nil]; } -- (instancetype)initWithPath:(NSString*)aPath { - +- (instancetype) initWithPath:(NSString *)aPath { + assert(sqlite3_threadsafe()); // whoa there big boy- gotta make sure sqlite it happy with what we're going to do. - + self = [super init]; - + if (self) { _databasePath = [aPath copy]; _openResultSets = [[NSMutableSet alloc] init]; @@ -751,22 +687,22 @@ - (instancetype)initWithPath:(NSString*)aPath { _crashOnErrors = NO; _maxBusyRetryTimeInterval = 2; } - + return [self initWithPath:aPath - objectSerializer:NULL - objectDeserializer:NULL - metadataSerializer:NULL - metadataDeserializer:NULL - objectPreSanitizer:NULL - objectPostSanitizer:NULL - metadataPreSanitizer:NULL - metadataPostSanitizer:NULL - options:nil]; - + objectSerializer:NULL + objectDeserializer:NULL + metadataSerializer:NULL + metadataDeserializer:NULL + objectPreSanitizer:NULL + objectPostSanitizer:NULL + metadataPreSanitizer:NULL + metadataPostSanitizer:NULL + options:nil]; + return self; -} +} /* initWithPath */ -- (void)dealloc { +- (void) dealloc { [self close]; CCRelease(_openResultSets); CCRelease(_cachedStatements); @@ -775,11 +711,11 @@ - (void)dealloc { CCRelease(_openFunctions); } -- (NSString *)databasePath { +- (NSString *) databasePath { return _databasePath; } -+ (NSString*)CCUserVersion { ++ (NSString *) CCUserVersion { return @"1.1.1"; } @@ -787,144 +723,142 @@ + (NSString*)CCUserVersion { // /* need to make sure to do X with CCSQLite version 2.4 or later */ // if ([CCSQLite CCVersion] >= 0x0240) { … } -+ (SInt32)CCVersion { - ++ (SInt32) CCVersion { + // we go through these hoops so that we only have to change the version number in a single spot. static dispatch_once_t once; static SInt32 CCVersionVal = 0; - + dispatch_once(&once, ^{ - NSString *prodVersion = [self CCUserVersion]; - + NSString * prodVersion = [self CCUserVersion]; + if ([[prodVersion componentsSeparatedByString:@"."] count] < 3) { prodVersion = [prodVersion stringByAppendingString:@".0"]; } - - NSString *junk = [prodVersion stringByReplacingOccurrencesOfString:@"." withString:@""]; - - char *e = nil; - CCVersionVal = (int) strtoul([junk UTF8String], &e, 16); - + + NSString * junk = [prodVersion stringByReplacingOccurrencesOfString:@"." withString:@""]; + + char * e = nil; + CCVersionVal = (int)strtoul([junk UTF8String], &e, 16); + }); - + return CCVersionVal; -} +} /* CCVersion */ #pragma mark SQLite information -+ (NSString*)sqliteLibVersion { ++ (NSString *) sqliteLibVersion { return [NSString stringWithFormat:@"%s", sqlite3_libversion()]; } -+ (BOOL)isSQLiteThreadSafe { ++ (BOOL) isSQLiteThreadSafe { // make sure to read the sqlite headers on this guy! return sqlite3_threadsafe() != 0; } -- (void*)sqliteHandle { +- (void *) sqliteHandle { return _db; } -- (const char*)sqlitePath { - +- (const char *) sqlitePath { + if (!_databasePath) { return ":memory:"; } - + if ([_databasePath length] == 0) { return ""; // this creates a temporary database (it's an sqlite thing). } - + return [_databasePath fileSystemRepresentation]; - + } #pragma mark Open and close database -- (BOOL)open { +- (BOOL) open { if (_db) { return YES; } - - int err = sqlite3_open([self sqlitePath], (sqlite3**)&_db ); - if(err != SQLITE_OK) { + + int err = sqlite3_open([self sqlitePath], (sqlite3 **)&_db); + if (err != SQLITE_OK) { NSLog(@"error opening!: %d", err); return NO; } - + if (_maxBusyRetryTimeInterval > 0.0) { // set the handler [self setMaxBusyRetryTimeInterval:_maxBusyRetryTimeInterval]; } - - + + return YES; } -- (BOOL)openWithFlags:(int)flags { +- (BOOL) openWithFlags:(int)flags { return [self openWithFlags:flags vfs:nil]; } -- (BOOL)openWithFlags:(int)flags vfs:(NSString *)vfsName { +- (BOOL) openWithFlags:(int)flags vfs:(NSString *)vfsName { #if SQLITE_VERSION_NUMBER >= 3005000 if (_db) { return YES; } - - int err = sqlite3_open_v2([self sqlitePath], (sqlite3**)&_db, flags, [vfsName UTF8String]); - if(err != SQLITE_OK) { + + int err = sqlite3_open_v2([self sqlitePath], (sqlite3 **)&_db, flags, [vfsName UTF8String]); + if (err != SQLITE_OK) { NSLog(@"error opening!: %d", err); return NO; } - + if (_maxBusyRetryTimeInterval > 0.0) { // set the handler [self setMaxBusyRetryTimeInterval:_maxBusyRetryTimeInterval]; } - + return YES; #else NSLog(@"openWithFlags requires SQLite 3.5"); return NO; #endif -} +} /* openWithFlags */ + +- (BOOL) close { -- (BOOL)close { - [self clearCachedStatements]; [self closeOpenResultSets]; - + if (!_db) { return YES; } - - int rc; + + int rc; BOOL retry; BOOL triedFinalizingOpenStatements = NO; - + do { retry = NO; rc = sqlite3_close(_db); if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) { if (!triedFinalizingOpenStatements) { triedFinalizingOpenStatements = YES; - sqlite3_stmt *pStmt; - while ((pStmt = sqlite3_next_stmt(_db, nil)) !=0) { + sqlite3_stmt * pStmt; + while ((pStmt = sqlite3_next_stmt(_db, nil)) != 0) { NSLog(@"Closing leaked statement"); sqlite3_finalize(pStmt); retry = YES; } } - } - else if (SQLITE_OK != rc) { + } else if (SQLITE_OK != rc) { NSLog(@"error closing!: %d", rc); } - } - while (retry); - + } while (retry); + _db = nil; return YES; -} +} /* close */ #pragma mark Busy handler routines @@ -938,46 +872,45 @@ - (BOOL)close { // C function causes problems; the rest don't. Anyway, ignoring the .m // files with appledoc will prevent this problem from occurring. -static int CCDatabaseBusyHandler(void *f, int count) { - CCSQLite *self = (__bridge CCSQLite*)f; - +static int CCDatabaseBusyHandler(void * f, int count) { + CCSQLite * self = (__bridge CCSQLite *)f; + if (count == 0) { self->_startBusyRetryTime = [NSDate timeIntervalSinceReferenceDate]; return 1; } - + NSTimeInterval delta = [NSDate timeIntervalSinceReferenceDate] - (self->_startBusyRetryTime); - + if (delta < [self maxBusyRetryTimeInterval]) { - int requestedSleepInMillseconds = (int) arc4random_uniform(50) + 50; + int requestedSleepInMillseconds = (int)arc4random_uniform(50) + 50; int actualSleepInMilliseconds = sqlite3_sleep(requestedSleepInMillseconds); if (actualSleepInMilliseconds != requestedSleepInMillseconds) { NSLog(@"WARNING: Requested sleep of %i milliseconds, but SQLite returned %i. Maybe SQLite wasn't built with HAVE_USLEEP=1?", requestedSleepInMillseconds, actualSleepInMilliseconds); } return 1; } - + return 0; -} +} /* CCDatabaseBusyHandler */ + +- (void) setMaxBusyRetryTimeInterval:(NSTimeInterval)timeout { -- (void)setMaxBusyRetryTimeInterval:(NSTimeInterval)timeout { - _maxBusyRetryTimeInterval = timeout; - + if (!_db) { return; } - + if (timeout > 0) { sqlite3_busy_handler(_db, &CCDatabaseBusyHandler, (__bridge void *)(self)); - } - else { + } else { // turn it off otherwise sqlite3_busy_handler(_db, nil, nil); } } -- (NSTimeInterval)maxBusyRetryTimeInterval { +- (NSTimeInterval) maxBusyRetryTimeInterval { return _maxBusyRetryTimeInterval; } @@ -985,13 +918,13 @@ - (NSTimeInterval)maxBusyRetryTimeInterval { // we no longer make busyRetryTimeout public // but for folks who don't bother noticing that the interface to CCSQLite changed, // we'll still implement the method so they don't get suprise crashes -- (int)busyRetryTimeout { +- (int) busyRetryTimeout { NSLog(@"%s:%d", __FUNCTION__, __LINE__); NSLog(@"CCSQLite: busyRetryTimeout no longer works, please use maxBusyRetryTimeInterval"); return -1; } -- (void)setBusyRetryTimeout:(int)i { +- (void) setBusyRetryTimeout:(int)i { #pragma unused(i) NSLog(@"%s:%d", __FUNCTION__, __LINE__); NSLog(@"CCSQLite: setBusyRetryTimeout does nothing, please use setMaxBusyRetryTimeInterval:"); @@ -999,94 +932,95 @@ - (void)setBusyRetryTimeout:(int)i { #pragma mark Result set functions -- (BOOL)hasOpenResultSets { +- (BOOL) hasOpenResultSets { return [_openResultSets count] > 0; } -- (void)closeOpenResultSets { - - //Copy the set so we don't get mutation errors - NSSet *openSetCopy = CCReturnAutoreleased([_openResultSets copy]); - for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) { - CCResultSet *rs = (CCResultSet *)[rsInWrappedInATastyValueMeal pointerValue]; - +- (void) closeOpenResultSets { + + // Copy the set so we don't get mutation errors + NSSet * openSetCopy = CCReturnAutoreleased([_openResultSets copy]); + + for (NSValue * rsInWrappedInATastyValueMeal in openSetCopy) { + CCResultSet * rs = (CCResultSet *)[rsInWrappedInATastyValueMeal pointerValue]; + [rs setParentDB:nil]; [rs close]; - + [_openResultSets removeObject:rsInWrappedInATastyValueMeal]; } } -- (void)resultSetDidClose:(CCResultSet *)resultSet { - NSValue *setValue = [NSValue valueWithNonretainedObject:resultSet]; - +- (void) resultSetDidClose:(CCResultSet *)resultSet { + NSValue * setValue = [NSValue valueWithNonretainedObject:resultSet]; + [_openResultSets removeObject:setValue]; } #pragma mark Cached statements -- (void)clearCachedStatements { - - for (NSMutableSet *statements in [_cachedStatements objectEnumerator]) { - for (CCStatement *statement in [statements allObjects]) { +- (void) clearCachedStatements { + + for (NSMutableSet * statements in [_cachedStatements objectEnumerator]) { + for (CCStatement * statement in [statements allObjects]) { [statement close]; } } - + [_cachedStatements removeAllObjects]; } -- (CCStatement*)cachedStatementForQuery:(NSString*)query { - - NSMutableSet* statements = [_cachedStatements objectForKey:query]; - - return [[statements objectsPassingTest:^BOOL(CCStatement* statement, BOOL *stop) { - - *stop = ![statement inUse]; - return *stop; - - }] anyObject]; +- (CCStatement *) cachedStatementForQuery:(NSString *)query { + + NSMutableSet * statements = [_cachedStatements objectForKey:query]; + + return [[statements objectsPassingTest:^BOOL (CCStatement * statement, BOOL * stop) { + + *stop = ![statement inUse]; + return *stop; + + }] anyObject]; } -- (void)setCachedStatement:(CCStatement*)statement forQuery:(NSString*)query { - +- (void) setCachedStatement:(CCStatement *)statement forQuery:(NSString *)query { + query = [query copy]; // in case we got handed in a mutable string... [statement setQuery:query]; - - NSMutableSet* statements = [_cachedStatements objectForKey:query]; + + NSMutableSet * statements = [_cachedStatements objectForKey:query]; if (!statements) { statements = [NSMutableSet set]; } - + [statements addObject:statement]; - + [_cachedStatements setObject:statements forKey:query]; - + CCRelease(query); } #pragma mark Key routines -- (BOOL)rekey:(NSString*)key { - NSData *keyData = [NSData dataWithBytes:(void *)[key UTF8String] length:(NSUInteger)strlen([key UTF8String])]; - +- (BOOL) rekey:(NSString *)key { + NSData * keyData = [NSData dataWithBytes:(void *)[key UTF8String] length:(NSUInteger)strlen([key UTF8String])]; + return [self rekeyWithData:keyData]; } -- (BOOL)rekeyWithData:(NSData *)keyData { +- (BOOL) rekeyWithData:(NSData *)keyData { #ifdef SQLITE_HAS_CODEC if (!keyData) { return NO; } - + int rc = sqlite3_rekey(_db, [keyData bytes], (int)[keyData length]); - + if (rc != SQLITE_OK) { NSLog(@"error on rekey: %d", rc); NSLog(@"%@", [self lastErrorMessage]); } - + return (rc == SQLITE_OK); #else #pragma unused(keyData) @@ -1094,20 +1028,20 @@ - (BOOL)rekeyWithData:(NSData *)keyData { #endif } -- (BOOL)setKey:(NSString*)key { - NSData *keyData = [NSData dataWithBytes:[key UTF8String] length:(NSUInteger)strlen([key UTF8String])]; - +- (BOOL) setKey:(NSString *)key { + NSData * keyData = [NSData dataWithBytes:[key UTF8String] length:(NSUInteger)strlen([key UTF8String])]; + return [self setKeyWithData:keyData]; } -- (BOOL)setKeyWithData:(NSData *)keyData { +- (BOOL) setKeyWithData:(NSData *)keyData { #ifdef SQLITE_HAS_CODEC if (!keyData) { return NO; } - + int rc = sqlite3_key(_db, [keyData bytes], (int)[keyData length]); - + return (rc == SQLITE_OK); #else #pragma unused(keyData) @@ -1117,9 +1051,10 @@ - (BOOL)setKeyWithData:(NSData *)keyData { #pragma mark Date routines -+ (NSDateFormatter *)storeableDateFormat:(NSString *)format { - - NSDateFormatter *result = CCReturnAutoreleased([[NSDateFormatter alloc] init]); ++ (NSDateFormatter *) storeableDateFormat:(NSString *)format { + + NSDateFormatter * result = CCReturnAutoreleased([[NSDateFormatter alloc] init]); + result.dateFormat = format; result.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0]; result.locale = CCReturnAutoreleased([[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]); @@ -1127,44 +1062,44 @@ + (NSDateFormatter *)storeableDateFormat:(NSString *)format { } -- (BOOL)hasDateFormatter { +- (BOOL) hasDateFormatter { return _dateFormat != nil; } -- (void)setDateFormat:(NSDateFormatter *)format { +- (void) setDateFormat:(NSDateFormatter *)format { CCAutorelease(_dateFormat); _dateFormat = CCReturnRetained(format); } -- (NSDate *)dateFromString:(NSString *)s { +- (NSDate *) dateFromString:(NSString *)s { return [_dateFormat dateFromString:s]; } -- (NSString *)stringFromDate:(NSDate *)date { +- (NSString *) stringFromDate:(NSDate *)date { return [_dateFormat stringFromDate:date]; } #pragma mark State of database -- (BOOL)goodConnection { - +- (BOOL) goodConnection { + if (!_db) { return NO; } - - CCResultSet *rs = [self executeQuery:@"select name from sqlite_master where type='table'"]; - + + CCResultSet * rs = [self executeQuery:@"select name from sqlite_master where type='table'"]; + if (rs) { [rs close]; return YES; } - + return NO; } -- (void)warnInUse { +- (void) warnInUse { NSLog(@"The CCSQLite %@ is currently in use.", self); - + #ifndef NS_BLOCK_ASSERTIONS if (_crashOnErrors) { NSAssert(false, @"The CCSQLite %@ is currently in use.", self); @@ -1173,166 +1108,150 @@ - (void)warnInUse { #endif } -- (BOOL)databaseExists { - +- (BOOL) databaseExists { + if (!_db) { - + NSLog(@"The CCSQLite %@ is not open.", self); - + #ifndef NS_BLOCK_ASSERTIONS if (_crashOnErrors) { NSAssert(false, @"The CCSQLite %@ is not open.", self); abort(); } #endif - + return NO; } - + return YES; } #pragma mark Error routines -- (NSString*)lastErrorMessage { +- (NSString *) lastErrorMessage { return [NSString stringWithUTF8String:sqlite3_errmsg(_db)]; } -- (BOOL)hadError { +- (BOOL) hadError { int lastErrCode = [self lastErrorCode]; - + return (lastErrCode > SQLITE_OK && lastErrCode < SQLITE_ROW); } -- (int)lastErrorCode { +- (int) lastErrorCode { return sqlite3_errcode(_db); } -- (int)lastExtendedErrorCode { +- (int) lastExtendedErrorCode { return sqlite3_extended_errcode(_db); } -- (NSError*)errorWithMessage:(NSString*)message { - NSDictionary* errorMessage = [NSDictionary dictionaryWithObject:message forKey:NSLocalizedDescriptionKey]; - +- (NSError *) errorWithMessage:(NSString *)message { + NSDictionary * errorMessage = [NSDictionary dictionaryWithObject:message forKey:NSLocalizedDescriptionKey]; + return [NSError errorWithDomain:@"CCSQLite" code:sqlite3_errcode(_db) userInfo:errorMessage]; } -- (NSError*)lastError { +- (NSError *) lastError { return [self errorWithMessage:[self lastErrorMessage]]; } #pragma mark Update information routines -- (sqlite_int64)lastInsertRowId { - +- (sqlite_int64) lastInsertRowId { + if (_isExecutingStatement) { [self warnInUse]; return NO; } - + _isExecutingStatement = YES; - + sqlite_int64 ret = sqlite3_last_insert_rowid(_db); - + _isExecutingStatement = NO; - + return ret; } -- (int)changes { +- (int) changes { if (_isExecutingStatement) { [self warnInUse]; return 0; } - + _isExecutingStatement = YES; - + int ret = sqlite3_changes(_db); - + _isExecutingStatement = NO; - + return ret; } #pragma mark SQL manipulation -- (void)bindObject:(id)obj toColumn:(int)idx inStatement:(sqlite3_stmt*)pStmt { - +- (void) bindObject:(id)obj toColumn:(int)idx inStatement:(sqlite3_stmt *)pStmt { + if ((!obj) || ((NSNull *)obj == [NSNull null])) { sqlite3_bind_null(pStmt, idx); } - // FIXME - someday check the return codes on these binds. else if ([obj isKindOfClass:[NSData class]]) { - const void *bytes = [obj bytes]; + const void * bytes = [obj bytes]; if (!bytes) { // it's an empty NSData object, aka [NSData data]. // Don't pass a NULL pointer, or sqlite will bind a SQL null instead of a blob. bytes = ""; } sqlite3_bind_blob(pStmt, idx, bytes, (int)[obj length], SQLITE_STATIC); - } - else if ([obj isKindOfClass:[NSDate class]]) { + } else if ([obj isKindOfClass:[NSDate class]]) { if (self.hasDateFormatter) sqlite3_bind_text(pStmt, idx, [[self stringFromDate:obj] UTF8String], -1, SQLITE_STATIC); else sqlite3_bind_double(pStmt, idx, [obj timeIntervalSince1970]); - } - else if ([obj isKindOfClass:[NSNumber class]]) { - + } else if ([obj isKindOfClass:[NSNumber class]]) { + if (strcmp([obj objCType], @encode(char)) == 0) { sqlite3_bind_int(pStmt, idx, [obj charValue]); - } - else if (strcmp([obj objCType], @encode(unsigned char)) == 0) { + } else if (strcmp([obj objCType], @encode(unsigned char)) == 0) { sqlite3_bind_int(pStmt, idx, [obj unsignedCharValue]); - } - else if (strcmp([obj objCType], @encode(short)) == 0) { + } else if (strcmp([obj objCType], @encode(short)) == 0) { sqlite3_bind_int(pStmt, idx, [obj shortValue]); - } - else if (strcmp([obj objCType], @encode(unsigned short)) == 0) { + } else if (strcmp([obj objCType], @encode(unsigned short)) == 0) { sqlite3_bind_int(pStmt, idx, [obj unsignedShortValue]); - } - else if (strcmp([obj objCType], @encode(int)) == 0) { + } else if (strcmp([obj objCType], @encode(int)) == 0) { sqlite3_bind_int(pStmt, idx, [obj intValue]); - } - else if (strcmp([obj objCType], @encode(unsigned int)) == 0) { + } else if (strcmp([obj objCType], @encode(unsigned int)) == 0) { sqlite3_bind_int64(pStmt, idx, (long long)[obj unsignedIntValue]); - } - else if (strcmp([obj objCType], @encode(long)) == 0) { + } else if (strcmp([obj objCType], @encode(long)) == 0) { sqlite3_bind_int64(pStmt, idx, [obj longValue]); - } - else if (strcmp([obj objCType], @encode(unsigned long)) == 0) { + } else if (strcmp([obj objCType], @encode(unsigned long)) == 0) { sqlite3_bind_int64(pStmt, idx, (long long)[obj unsignedLongValue]); - } - else if (strcmp([obj objCType], @encode(long long)) == 0) { + } else if (strcmp([obj objCType], @encode(long long)) == 0) { sqlite3_bind_int64(pStmt, idx, [obj longLongValue]); - } - else if (strcmp([obj objCType], @encode(unsigned long long)) == 0) { + } else if (strcmp([obj objCType], @encode(unsigned long long)) == 0) { sqlite3_bind_int64(pStmt, idx, (long long)[obj unsignedLongLongValue]); - } - else if (strcmp([obj objCType], @encode(float)) == 0) { + } else if (strcmp([obj objCType], @encode(float)) == 0) { sqlite3_bind_double(pStmt, idx, [obj floatValue]); - } - else if (strcmp([obj objCType], @encode(double)) == 0) { + } else if (strcmp([obj objCType], @encode(double)) == 0) { sqlite3_bind_double(pStmt, idx, [obj doubleValue]); - } - else if (strcmp([obj objCType], @encode(BOOL)) == 0) { + } else if (strcmp([obj objCType], @encode(BOOL)) == 0) { sqlite3_bind_int(pStmt, idx, ([obj boolValue] ? 1 : 0)); - } - else { + } else { sqlite3_bind_text(pStmt, idx, [[obj description] UTF8String], -1, SQLITE_STATIC); } - } - else { + } else { sqlite3_bind_text(pStmt, idx, [[obj description] UTF8String], -1, SQLITE_STATIC); } -} +} /* bindObject */ + +- (void) extractSQL:(NSString *)sql argumentsList:(va_list)args intoString:(NSMutableString *)cleanedSQL arguments:(NSMutableArray *)arguments { -- (void)extractSQL:(NSString *)sql argumentsList:(va_list)args intoString:(NSMutableString *)cleanedSQL arguments:(NSMutableArray *)arguments { - NSUInteger length = [sql length]; unichar last = '\0'; + for (NSUInteger i = 0; i < length; ++i) { id arg = nil; unichar current = [sql characterAtIndex:i]; @@ -1347,7 +1266,7 @@ - (void)extractSQL:(NSString *)sql argumentsList:(va_list)args intoString:(NSMut arg = [NSString stringWithFormat:@"%c", va_arg(args, int)]; break; case 's': - arg = [NSString stringWithUTF8String:va_arg(args, char*)]; + arg = [NSString stringWithUTF8String:va_arg(args, char *)]; break; case 'd': case 'D': @@ -1363,12 +1282,10 @@ - (void)extractSQL:(NSString *)sql argumentsList:(va_list)args intoString:(NSMut if (i < length && [sql characterAtIndex:i] == 'i') { // warning: second argument to 'va_arg' is of promotable type 'short'; this va_arg has undefined behavior because arguments will be promoted to 'int' arg = [NSNumber numberWithShort:(short)(va_arg(args, int))]; - } - else if (i < length && [sql characterAtIndex:i] == 'u') { + } else if (i < length && [sql characterAtIndex:i] == 'u') { // warning: second argument to 'va_arg' is of promotable type 'unsigned short'; this va_arg has undefined behavior because arguments will be promoted to 'int' arg = [NSNumber numberWithUnsignedShort:(unsigned short)(va_arg(args, uint))]; - } - else { + } else { i--; } break; @@ -1376,11 +1293,9 @@ - (void)extractSQL:(NSString *)sql argumentsList:(va_list)args intoString:(NSMut i++; if (i < length && [sql characterAtIndex:i] == 'i') { arg = [NSNumber numberWithLongLong:va_arg(args, long long)]; - } - else if (i < length && [sql characterAtIndex:i] == 'u') { + } else if (i < length && [sql characterAtIndex:i] == 'u') { arg = [NSNumber numberWithUnsignedLongLong:va_arg(args, unsigned long long)]; - } - else { + } else { i--; } break; @@ -1398,333 +1313,319 @@ - (void)extractSQL:(NSString *)sql argumentsList:(va_list)args intoString:(NSMut if (next == 'l') { i++; if (i < length && [sql characterAtIndex:i] == 'd') { - //%lld + // %lld arg = [NSNumber numberWithLongLong:va_arg(args, long long)]; - } - else if (i < length && [sql characterAtIndex:i] == 'u') { - //%llu + } else if (i < length && [sql characterAtIndex:i] == 'u') { + // %llu arg = [NSNumber numberWithUnsignedLongLong:va_arg(args, unsigned long long)]; - } - else { + } else { i--; } - } - else if (next == 'd') { - //%ld + } else if (next == 'd') { + // %ld arg = [NSNumber numberWithLong:va_arg(args, long)]; - } - else if (next == 'u') { - //%lu + } else if (next == 'u') { + // %lu arg = [NSNumber numberWithUnsignedLong:va_arg(args, unsigned long)]; - } - else { + } else { i--; } - } - else { + } else { i--; } break; default: // something else that we can't interpret. just pass it on through like normal break; - } - } - else if (current == '%') { + } /* switch */ + } else if (current == '%') { // percent sign; skip this character add = '\0'; } - + if (arg != nil) { [cleanedSQL appendString:@"?"]; [arguments addObject:arg]; - } - else if (add == (unichar)'@' && last == (unichar) '%') { + } else if (add == (unichar)'@' && last == (unichar)'%') { [cleanedSQL appendFormat:@"NULL"]; - } - else if (add != '\0') { + } else if (add != '\0') { [cleanedSQL appendFormat:@"%C", add]; } last = current; } -} +} /* extractSQL */ #pragma mark Execute queries -- (CCResultSet *)executeQuery:(NSString *)sql withParameterDictionary:(NSDictionary *)arguments { +- (CCResultSet *) executeQuery:(NSString *)sql withParameterDictionary:(NSDictionary *)arguments { return [self executeQuery:sql withArgumentsInArray:nil orDictionary:arguments orVAList:nil]; } -- (CCResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args { - +- (CCResultSet *) executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args { + if (![self databaseExists]) { return CCNULL; } - + if (_isExecutingStatement) { [self warnInUse]; return CCNULL; } - + _isExecutingStatement = YES; - + int rc = CCNULL; - sqlite3_stmt *pStmt = CCNULL; - CCStatement *statement = CCNULL; - CCResultSet *rs = CCNULL; - + sqlite3_stmt * pStmt = CCNULL; + CCStatement * statement = CCNULL; + CCResultSet * rs = CCNULL; + if (_traceExecution && sql) { NSLog(@"%@ executeQuery: %@", self, sql); } - + if (_shouldCacheStatements) { statement = [self cachedStatementForQuery:sql]; pStmt = statement ? [statement statement] : CCNULL; [statement reset]; } - + if (!pStmt) { - + rc = sqlite3_prepare_v2(_db, [sql UTF8String], -1, &pStmt, 0); - + if (SQLITE_OK != rc) { if (_logsErrors) { NSLog(@"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]); NSLog(@"DB Query: %@", sql); NSLog(@"DB Path: %@", _databasePath); } - + if (_crashOnErrors) { NSAssert(false, @"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]); abort(); } - + sqlite3_finalize(pStmt); _isExecutingStatement = NO; return nil; } } - + id obj; int idx = 0; int queryCount = sqlite3_bind_parameter_count(pStmt); // pointed out by Dominic Yu (thanks!) - + // If dictionaryArgs is passed in, that means we are using sqlite's named parameter support if (dictionaryArgs) { - - for (NSString *dictionaryKey in [dictionaryArgs allKeys]) { - + + for (NSString * dictionaryKey in [dictionaryArgs allKeys]) { + // Prefix the key with a colon. - NSString *parameterName = [[NSString alloc] initWithFormat:@":%@", dictionaryKey]; - + NSString * parameterName = [[NSString alloc] initWithFormat:@":%@", dictionaryKey]; + if (_traceExecution) { NSLog(@"%@ = %@", parameterName, [dictionaryArgs objectForKey:dictionaryKey]); } - + // Get the index for the parameter name. int namedIdx = sqlite3_bind_parameter_index(pStmt, [parameterName UTF8String]); - + CCRelease(parameterName); - + if (namedIdx > 0) { // Standard binding from here. [self bindObject:[dictionaryArgs objectForKey:dictionaryKey] toColumn:namedIdx inStatement:pStmt]; // increment the binding count, so our check below works out idx++; - } - else { + } else { NSLog(@"Could not find index for %@", dictionaryKey); } } - } - else { - + } else { + while (idx < queryCount) { - + if (arrayArgs && idx < (int)[arrayArgs count]) { obj = [arrayArgs objectAtIndex:(NSUInteger)idx]; - } - else if (args) { + } else if (args) { obj = va_arg(args, id); - } - else { - //We ran out of arguments + } else { + // We ran out of arguments break; } - + if (_traceExecution) { if ([obj isKindOfClass:[NSData class]]) { - NSLog(@"data: %ld bytes", (unsigned long)[(NSData*)obj length]); - } - else { + NSLog(@"data: %ld bytes", (unsigned long)[(NSData *)obj length]); + } else { NSLog(@"obj: %@", obj); } } - + idx++; - + [self bindObject:obj toColumn:idx inStatement:pStmt]; } } - + if (idx != queryCount) { NSLog(@"Error: the bind count is not correct for the # of variables (executeQuery)"); sqlite3_finalize(pStmt); _isExecutingStatement = NO; return nil; } - + CCRetain(statement); // to balance the release below - + if (!statement) { statement = [[CCStatement alloc] init]; [statement setStatement:pStmt]; - + if (_shouldCacheStatements && sql) { [self setCachedStatement:statement forQuery:sql]; } } - + // the statement gets closed in rs's dealloc or [rs close]; rs = [CCResultSet resultSetWithStatement:statement usingParentDatabase:self]; [rs setQuery:sql]; - - NSValue *openResultSet = [NSValue valueWithNonretainedObject:rs]; + + NSValue * openResultSet = [NSValue valueWithNonretainedObject:rs]; [_openResultSets addObject:openResultSet]; - + [statement setUseCount:[statement useCount] + 1]; - + CCRelease(statement); - + _isExecutingStatement = NO; - + return rs; -} +} /* executeQuery */ -- (CCResultSet *)executeQuery:(NSString*)sql, ... { +- (CCResultSet *) executeQuery:(NSString *)sql, ...{ va_list args; va_start(args, sql); - + id result = [self executeQuery:sql withArgumentsInArray:nil orDictionary:nil orVAList:args]; - + va_end(args); return result; } -- (CCResultSet *)executeQueryWithFormat:(NSString*)format, ... { +- (CCResultSet *) executeQueryWithFormat:(NSString *)format, ...{ va_list args; va_start(args, format); - - NSMutableString *sql = [NSMutableString stringWithCapacity:[format length]]; - NSMutableArray *arguments = [NSMutableArray array]; + + NSMutableString * sql = [NSMutableString stringWithCapacity:[format length]]; + NSMutableArray * arguments = [NSMutableArray array]; [self extractSQL:format argumentsList:args intoString:sql arguments:arguments]; - + va_end(args); - + return [self executeQuery:sql withArgumentsInArray:arguments]; } -- (CCResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments { +- (CCResultSet *) executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments { return [self executeQuery:sql withArgumentsInArray:arguments orDictionary:nil orVAList:nil]; } -- (CCResultSet *)executeQuery:(NSString *)sql values:(NSArray *)values error:(NSError * __autoreleasing *)error { - CCResultSet *rs = [self executeQuery:sql withArgumentsInArray:values orDictionary:nil orVAList:nil]; +- (CCResultSet *) executeQuery:(NSString *)sql values:(NSArray *)values error:(NSError * __autoreleasing *)error { + CCResultSet * rs = [self executeQuery:sql withArgumentsInArray:values orDictionary:nil orVAList:nil]; + if (!rs && error) { *error = [self lastError]; } return rs; } -- (CCResultSet *)executeQuery:(NSString*)sql withVAList:(va_list)args { +- (CCResultSet *) executeQuery:(NSString *)sql withVAList:(va_list)args { return [self executeQuery:sql withArgumentsInArray:nil orDictionary:nil orVAList:args]; } #pragma mark Execute updates -- (BOOL)executeUpdate:(NSString*)sql error:(NSError**)outErr withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args { - +- (BOOL) executeUpdate:(NSString *)sql error:(NSError **)outErr withArgumentsInArray:(NSArray *)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args { + if (![self databaseExists]) { return NO; } - + if (_isExecutingStatement) { [self warnInUse]; return NO; } - + _isExecutingStatement = YES; - + int rc = CCNULL; - sqlite3_stmt *pStmt = CCNULL; - CCStatement *cachedStmt = CCNULL; - + sqlite3_stmt * pStmt = CCNULL; + CCStatement * cachedStmt = CCNULL; + if (_traceExecution && sql) { NSLog(@"%@ executeUpdate: %@", self, sql); } - + if (_shouldCacheStatements) { cachedStmt = [self cachedStatementForQuery:sql]; pStmt = cachedStmt ? [cachedStmt statement] : CCNULL; [cachedStmt reset]; } - + if (!pStmt) { rc = sqlite3_prepare_v2(_db, [sql UTF8String], -1, &pStmt, 0); - + if (SQLITE_OK != rc) { if (_logsErrors) { NSLog(@"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]); NSLog(@"DB Query: %@", sql); NSLog(@"DB Path: %@", _databasePath); } - + if (_crashOnErrors) { NSAssert(false, @"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]); abort(); } - + if (outErr) { *outErr = [self errorWithMessage:[NSString stringWithUTF8String:sqlite3_errmsg(_db)]]; } - + sqlite3_finalize(pStmt); - + _isExecutingStatement = NO; return NO; } } - + id obj; int idx = 0; int queryCount = sqlite3_bind_parameter_count(pStmt); - + // If dictionaryArgs is passed in, that means we are using sqlite's named parameter support if (dictionaryArgs) { - - for (NSString *dictionaryKey in [dictionaryArgs allKeys]) { - + + for (NSString * dictionaryKey in [dictionaryArgs allKeys]) { + // Prefix the key with a colon. - NSString *parameterName = [[NSString alloc] initWithFormat:@":%@", dictionaryKey]; - + NSString * parameterName = [[NSString alloc] initWithFormat:@":%@", dictionaryKey]; + if (_traceExecution) { NSLog(@"%@ = %@", parameterName, [dictionaryArgs objectForKey:dictionaryKey]); } // Get the index for the parameter name. int namedIdx = sqlite3_bind_parameter_index(pStmt, [parameterName UTF8String]); - + CCRelease(parameterName); - + if (namedIdx > 0) { // Standard binding from here. [self bindObject:[dictionaryArgs objectForKey:dictionaryKey] toColumn:namedIdx inStatement:pStmt]; - + // increment the binding count, so our check below works out idx++; - } - else { - NSString *message = [NSString stringWithFormat:@"Could not find index for %@", dictionaryKey]; - + } else { + NSString * message = [NSString stringWithFormat:@"Could not find index for %@", dictionaryKey]; + if (_logsErrors) { NSLog(@"%@", message); } @@ -1733,69 +1634,63 @@ - (BOOL)executeUpdate:(NSString*)sql error:(NSError**)outErr withArgumentsInArra } } } - } - else { - + } else { + while (idx < queryCount) { - + if (arrayArgs && idx < (int)[arrayArgs count]) { obj = [arrayArgs objectAtIndex:(NSUInteger)idx]; - } - else if (args) { + } else if (args) { obj = va_arg(args, id); - } - else { - //We ran out of arguments + } else { + // We ran out of arguments break; } - + if (_traceExecution) { if ([obj isKindOfClass:[NSData class]]) { - NSLog(@"data: %ld bytes", (unsigned long)[(NSData*)obj length]); - } - else { + NSLog(@"data: %ld bytes", (unsigned long)[(NSData *)obj length]); + } else { NSLog(@"obj: %@", obj); } } - + idx++; - + [self bindObject:obj toColumn:idx inStatement:pStmt]; } } - - + + if (idx != queryCount) { - NSString *message = [NSString stringWithFormat:@"Error: the bind count (%d) is not correct for the # of variables in the query (%d) (%@) (executeUpdate)", idx, queryCount, sql]; + NSString * message = [NSString stringWithFormat:@"Error: the bind count (%d) is not correct for the # of variables in the query (%d) (%@) (executeUpdate)", idx, queryCount, sql]; if (_logsErrors) { NSLog(@"%@", message); } if (outErr) { *outErr = [self errorWithMessage:message]; } - + sqlite3_finalize(pStmt); _isExecutingStatement = NO; return NO; } - + /* Call sqlite3_step() to run the virtual machine. Since the SQL being - ** executed is not a SELECT statement, we assume no data will be returned. - */ - + ** executed is not a SELECT statement, we assume no data will be returned. + */ + rc = sqlite3_step(pStmt); - + if (SQLITE_DONE == rc) { // all is well, let's return. - } - else if (SQLITE_INTERRUPT == rc) { + } else if (SQLITE_INTERRUPT == rc) { if (_logsErrors) { NSLog(@"Error calling sqlite3_step. Query was interrupted (%d: %s) SQLITE_INTERRUPT", rc, sqlite3_errmsg(_db)); NSLog(@"DB Query: %@", sql); } - } - else if (rc == SQLITE_ROW) { - NSString *message = [NSString stringWithFormat:@"A executeUpdate is being called with a query string '%@'", sql]; + } else if (rc == SQLITE_ROW) { + NSString * message = [NSString stringWithFormat:@"A executeUpdate is being called with a query string '%@'", sql]; if (_logsErrors) { NSLog(@"%@", message); NSLog(@"DB Query: %@", sql); @@ -1803,26 +1698,23 @@ - (BOOL)executeUpdate:(NSString*)sql error:(NSError**)outErr withArgumentsInArra if (outErr) { *outErr = [self errorWithMessage:message]; } - } - else { + } else { if (outErr) { *outErr = [self errorWithMessage:[NSString stringWithUTF8String:sqlite3_errmsg(_db)]]; } - + if (SQLITE_ERROR == rc) { if (_logsErrors) { NSLog(@"Error calling sqlite3_step (%d: %s) SQLITE_ERROR", rc, sqlite3_errmsg(_db)); NSLog(@"DB Query: %@", sql); } - } - else if (SQLITE_MISUSE == rc) { + } else if (SQLITE_MISUSE == rc) { // uh oh. if (_logsErrors) { NSLog(@"Error calling sqlite3_step (%d: %s) SQLITE_MISUSE", rc, sqlite3_errmsg(_db)); NSLog(@"DB Query: %@", sql); } - } - else { + } else { // wtf? if (_logsErrors) { NSLog(@"Unknown error calling sqlite3_step (%d: %s) eu", rc, sqlite3_errmsg(_db)); @@ -1830,181 +1722,181 @@ - (BOOL)executeUpdate:(NSString*)sql error:(NSError**)outErr withArgumentsInArra } } } - + if (_shouldCacheStatements && !cachedStmt) { cachedStmt = [[CCStatement alloc] init]; - + [cachedStmt setStatement:pStmt]; - + [self setCachedStatement:cachedStmt forQuery:sql]; - + CCRelease(cachedStmt); } - + int closeErrorCode; - + if (cachedStmt) { [cachedStmt setUseCount:[cachedStmt useCount] + 1]; closeErrorCode = sqlite3_reset(pStmt); - } - else { + } else { /* Finalize the virtual machine. This releases all memory and other - ** resources allocated by the sqlite3_prepare() call above. - */ + ** resources allocated by the sqlite3_prepare() call above. + */ closeErrorCode = sqlite3_finalize(pStmt); } - + if (closeErrorCode != SQLITE_OK) { if (_logsErrors) { NSLog(@"Unknown error finalizing or resetting statement (%d: %s)", closeErrorCode, sqlite3_errmsg(_db)); NSLog(@"DB Query: %@", sql); } } - + _isExecutingStatement = NO; return (rc == SQLITE_DONE || rc == SQLITE_OK); -} +} /* executeUpdate */ -- (BOOL)executeUpdate:(NSString*)sql, ... { +- (BOOL) executeUpdate:(NSString *)sql, ...{ va_list args; va_start(args, sql); - + BOOL result = [self executeUpdate:sql error:nil withArgumentsInArray:nil orDictionary:nil orVAList:args]; - + va_end(args); return result; } -- (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments { +- (BOOL) executeUpdate:(NSString *)sql withArgumentsInArray:(NSArray *)arguments { return [self executeUpdate:sql error:nil withArgumentsInArray:arguments orDictionary:nil orVAList:nil]; } -- (BOOL)executeUpdate:(NSString*)sql values:(NSArray *)values error:(NSError * __autoreleasing *)error { +- (BOOL) executeUpdate:(NSString *)sql values:(NSArray *)values error:(NSError * __autoreleasing *)error { return [self executeUpdate:sql error:error withArgumentsInArray:values orDictionary:nil orVAList:nil]; } -- (BOOL)executeUpdate:(NSString*)sql withParameterDictionary:(NSDictionary *)arguments { +- (BOOL) executeUpdate:(NSString *)sql withParameterDictionary:(NSDictionary *)arguments { return [self executeUpdate:sql error:nil withArgumentsInArray:nil orDictionary:arguments orVAList:nil]; } -- (BOOL)executeUpdate:(NSString*)sql withVAList:(va_list)args { +- (BOOL) executeUpdate:(NSString *)sql withVAList:(va_list)args { return [self executeUpdate:sql error:nil withArgumentsInArray:nil orDictionary:nil orVAList:args]; } -- (BOOL)executeUpdateWithFormat:(NSString*)format, ... { +- (BOOL) executeUpdateWithFormat:(NSString *)format, ...{ va_list args; va_start(args, format); - - NSMutableString *sql = [NSMutableString stringWithCapacity:[format length]]; - NSMutableArray *arguments = [NSMutableArray array]; - + + NSMutableString * sql = [NSMutableString stringWithCapacity:[format length]]; + NSMutableArray * arguments = [NSMutableArray array]; + [self extractSQL:format argumentsList:args intoString:sql arguments:arguments]; - + va_end(args); - + return [self executeUpdate:sql withArgumentsInArray:arguments]; } -int CCExecuteBulkSQLCallback(void *theBlockAsVoid, int columns, char **values, char **names); // shhh clang. -int CCExecuteBulkSQLCallback(void *theBlockAsVoid, int columns, char **values, char **names) { - +int CCExecuteBulkSQLCallback(void * theBlockAsVoid, int columns, char ** values, char ** names); // shhh clang. +int CCExecuteBulkSQLCallback(void * theBlockAsVoid, int columns, char ** values, char ** names) { + if (!theBlockAsVoid) { return SQLITE_OK; } - - int (^execCallbackBlock)(NSDictionary *resultsDictionary) = (__bridge int (^)(NSDictionary *__strong))(theBlockAsVoid); - - NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:(NSUInteger)columns]; - + + int (^ execCallbackBlock)(NSDictionary * resultsDictionary) = (__bridge int (^)(NSDictionary * __strong))(theBlockAsVoid); + + NSMutableDictionary * dictionary = [NSMutableDictionary dictionaryWithCapacity:(NSUInteger)columns]; + for (NSInteger i = 0; i < columns; i++) { - NSString *key = [NSString stringWithUTF8String:names[i]]; + NSString * key = [NSString stringWithUTF8String:names[i]]; id value = values[i] ? [NSString stringWithUTF8String:values[i]] : [NSNull null]; [dictionary setObject:value forKey:key]; } - + return execCallbackBlock(dictionary); } -- (BOOL)executeStatements:(NSString *)sql { +- (BOOL) executeStatements:(NSString *)sql { return [self executeStatements:sql withResultBlock:nil]; } -- (BOOL)executeStatements:(NSString *)sql withResultBlock:(CCExecuteStatementsCallbackBlock)block { - +- (BOOL) executeStatements:(NSString *)sql withResultBlock:(CCExecuteStatementsCallbackBlock)block { + int rc; - char *errmsg = nil; - + char * errmsg = nil; + rc = sqlite3_exec([self sqliteHandle], [sql UTF8String], block ? CCExecuteBulkSQLCallback : nil, (__bridge void *)(block), &errmsg); - + if (errmsg && [self logsErrors]) { NSLog(@"Error inserting batch: %s", errmsg); sqlite3_free(errmsg); } - + return (rc == SQLITE_OK); } -- (BOOL)executeUpdate:(NSString*)sql withErrorAndBindings:(NSError**)outErr, ... { - +- (BOOL) executeUpdate:(NSString *)sql withErrorAndBindings:(NSError **)outErr, ...{ + va_list args; va_start(args, outErr); - + BOOL result = [self executeUpdate:sql error:outErr withArgumentsInArray:nil orDictionary:nil orVAList:args]; - + va_end(args); return result; } #pragma mark Transactions -- (BOOL)rollback { +- (BOOL) rollback { BOOL b = [self executeUpdate:@"rollback transaction"]; - + if (b) { _inTransaction = NO; } - + return b; } -- (BOOL)commit { +- (BOOL) commit { BOOL b = [self executeUpdate:@"commit transaction"]; - + if (b) { _inTransaction = NO; } - + return b; } -- (BOOL)beginDeferredTransaction { - +- (BOOL) beginDeferredTransaction { + BOOL b = [self executeUpdate:@"begin deferred transaction"]; + if (b) { _inTransaction = YES; } - + return b; } -- (BOOL)beginTransaction { - +- (BOOL) beginTransaction { + BOOL b = [self executeUpdate:@"begin exclusive transaction"]; + if (b) { _inTransaction = YES; } - + return b; } -- (BOOL)inTransaction { +- (BOOL) inTransaction { return _inTransaction; } -- (BOOL)interrupt -{ +- (BOOL) interrupt { if (_db) { sqlite3_interrupt([self sqliteHandle]); return YES; @@ -2012,99 +1904,99 @@ - (BOOL)interrupt return NO; } -static NSString *CCEscapeSavePointName(NSString *savepointName) { +static NSString * CCEscapeSavePointName(NSString * savepointName) { return [savepointName stringByReplacingOccurrencesOfString:@"'" withString:@"''"]; } -- (BOOL)startSavePointWithName:(NSString*)name error:(NSError**)outErr { +- (BOOL) startSavePointWithName:(NSString *)name error:(NSError **)outErr { #if SQLITE_VERSION_NUMBER >= 3007000 NSParameterAssert(name); - - NSString *sql = [NSString stringWithFormat:@"savepoint '%@';", CCEscapeSavePointName(name)]; - + + NSString * sql = [NSString stringWithFormat:@"savepoint '%@';", CCEscapeSavePointName(name)]; + return [self executeUpdate:sql error:outErr withArgumentsInArray:nil orDictionary:nil orVAList:nil]; #else - NSString *errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil); + NSString * errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil); if (self.logsErrors) NSLog(@"%@", errorMessage); return NO; #endif } -- (BOOL)releaseSavePointWithName:(NSString*)name error:(NSError**)outErr { +- (BOOL) releaseSavePointWithName:(NSString *)name error:(NSError **)outErr { #if SQLITE_VERSION_NUMBER >= 3007000 NSParameterAssert(name); - - NSString *sql = [NSString stringWithFormat:@"release savepoint '%@';", CCEscapeSavePointName(name)]; - + + NSString * sql = [NSString stringWithFormat:@"release savepoint '%@';", CCEscapeSavePointName(name)]; + return [self executeUpdate:sql error:outErr withArgumentsInArray:nil orDictionary:nil orVAList:nil]; #else - NSString *errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil); + NSString * errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil); if (self.logsErrors) NSLog(@"%@", errorMessage); return NO; #endif } -- (BOOL)rollbackToSavePointWithName:(NSString*)name error:(NSError**)outErr { +- (BOOL) rollbackToSavePointWithName:(NSString *)name error:(NSError **)outErr { #if SQLITE_VERSION_NUMBER >= 3007000 NSParameterAssert(name); - - NSString *sql = [NSString stringWithFormat:@"rollback transaction to savepoint '%@';", CCEscapeSavePointName(name)]; - + + NSString * sql = [NSString stringWithFormat:@"rollback transaction to savepoint '%@';", CCEscapeSavePointName(name)]; + return [self executeUpdate:sql error:outErr withArgumentsInArray:nil orDictionary:nil orVAList:nil]; #else - NSString *errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil); + NSString * errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil); if (self.logsErrors) NSLog(@"%@", errorMessage); return NO; #endif } -- (NSError*)inSavePoint:(void (^)(BOOL *rollback))block { +- (NSError *) inSavePoint:(void (^)(BOOL * rollback))block { #if SQLITE_VERSION_NUMBER >= 3007000 static unsigned long savePointIdx = 0; - - NSString *name = [NSString stringWithFormat:@"dbSavePoint%ld", savePointIdx++]; - + + NSString * name = [NSString stringWithFormat:@"dbSavePoint%ld", savePointIdx++]; + BOOL shouldRollback = NO; - - NSError *err = CCNULL; - + + NSError * err = CCNULL; + if (![self startSavePointWithName:name error:&err]) { return err; } - + if (block) { block(&shouldRollback); } - + if (shouldRollback) { // We need to rollback and release this savepoint to remove it [self rollbackToSavePointWithName:name error:&err]; } [self releaseSavePointWithName:name error:&err]; - + return err; -#else - NSString *errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil); +#else /* if SQLITE_VERSION_NUMBER >= 3007000 */ + NSString * errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil); if (self.logsErrors) NSLog(@"%@", errorMessage); - return [NSError errorWithDomain:@"CCSQLite" code:0 userInfo:@{NSLocalizedDescriptionKey : errorMessage}]; -#endif -} + return [NSError errorWithDomain:@"CCSQLite" code:0 userInfo:@{ NSLocalizedDescriptionKey : errorMessage }]; +#endif /* if SQLITE_VERSION_NUMBER >= 3007000 */ +} /* inSavePoint */ #pragma mark Cache statements -- (BOOL)shouldCacheStatements { +- (BOOL) shouldCacheStatements { return _shouldCacheStatements; } -- (void)setShouldCacheStatements:(BOOL)value { - +- (void) setShouldCacheStatements:(BOOL)value { + _shouldCacheStatements = value; - + if (_shouldCacheStatements && !_cachedStatements) { [self setCachedStatements:[NSMutableDictionary dictionary]]; } - + if (!_shouldCacheStatements) { [self setCachedStatements:nil]; } @@ -2112,12 +2004,12 @@ - (void)setShouldCacheStatements:(BOOL)value { #pragma mark Callback function -void CCBlockSQLiteCallBackFunction(sqlite3_context *context, int argc, sqlite3_value **argv); // -Wmissing-prototypes -void CCBlockSQLiteCallBackFunction(sqlite3_context *context, int argc, sqlite3_value **argv) { -#if ! __has_feature(objc_arc) - void (^block)(sqlite3_context *context, int argc, sqlite3_value **argv) = (id)sqlite3_user_data(context); +void CCBlockSQLiteCallBackFunction(sqlite3_context * context, int argc, sqlite3_value ** argv); // -Wmissing-prototypes +void CCBlockSQLiteCallBackFunction(sqlite3_context * context, int argc, sqlite3_value ** argv) { +#if !__has_feature(objc_arc) + void (^ block)(sqlite3_context * context, int argc, sqlite3_value ** argv) = (id)sqlite3_user_data(context); #else - void (^block)(sqlite3_context *context, int argc, sqlite3_value **argv) = (__bridge id)sqlite3_user_data(context); + void (^ block)(sqlite3_context * context, int argc, sqlite3_value ** argv) = (__bridge id)sqlite3_user_data(context); #endif if (block) { block(context, argc, argv); @@ -2125,157 +2017,157 @@ void CCBlockSQLiteCallBackFunction(sqlite3_context *context, int argc, sqlite3_v } -- (void)makeFunctionNamed:(NSString*)name maximumArguments:(int)count withBlock:(void (^)(void *context, int argc, void **argv))block { - +- (void) makeFunctionNamed:(NSString *)name maximumArguments:(int)count withBlock:(void (^)(void * context, int argc, void ** argv))block { + if (!_openFunctions) { _openFunctions = [NSMutableSet new]; } - + id b = CCReturnAutoreleased([block copy]); - + [_openFunctions addObject:b]; - + /* I tried adding custom functions to release the block when the connection is destroyed- but they seemed to never be called, so we use _openFunctions to store the values instead. */ -#if ! __has_feature(objc_arc) - sqlite3_create_function([self sqliteHandle], [name UTF8String], count, SQLITE_UTF8, (void*)b, &CCBlockSQLiteCallBackFunction, CCNULL, CCNULL); +#if !__has_feature(objc_arc) + sqlite3_create_function([self sqliteHandle], [name UTF8String], count, SQLITE_UTF8, (void *)b, &CCBlockSQLiteCallBackFunction, CCNULL, CCNULL); #else - sqlite3_create_function([self sqliteHandle], [name UTF8String], count, SQLITE_UTF8, (__bridge void*)b, &CCBlockSQLiteCallBackFunction, CCNULL, CCNULL); + sqlite3_create_function([self sqliteHandle], [name UTF8String], count, SQLITE_UTF8, (__bridge void *)b, &CCBlockSQLiteCallBackFunction, CCNULL, CCNULL); #endif } #pragma mark CCSQLiteAdditions #define RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(type, sel) \ -va_list args; \ -va_start(args, query); \ -CCResultSet *resultSet = [self executeQuery:query withArgumentsInArray:CCNULL orDictionary:CCNULL orVAList:args]; \ -va_end(args); \ -if (![resultSet next]) { return (type)0; } \ -type ret = [resultSet sel:0]; \ -[resultSet close]; \ -[resultSet setParentDB:nil]; \ -return ret; - - -- (NSString*)stringForQuery:(NSString*)query, ... { + va_list args; \ + va_start(args, query); \ + CCResultSet * resultSet = [self executeQuery:query withArgumentsInArray:CCNULL orDictionary:CCNULL orVAList:args]; \ + va_end(args); \ + if (![resultSet next]) { return (type)0; } \ + type ret = [resultSet sel:0]; \ + [resultSet close]; \ + [resultSet setParentDB:nil]; \ + return ret; + + +- (NSString *) stringForQuery:(NSString *)query, ...{ RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSString *, stringForColumnIndex); } -- (int)intForQuery:(NSString*)query, ... { +- (int) intForQuery:(NSString *)query, ...{ RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(int, intForColumnIndex); } -- (long)longForQuery:(NSString*)query, ... { +- (long) longForQuery:(NSString *)query, ...{ RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(long, longForColumnIndex); } -- (BOOL)boolForQuery:(NSString*)query, ... { +- (BOOL) boolForQuery:(NSString *)query, ...{ RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(BOOL, boolForColumnIndex); } -- (double)doubleForQuery:(NSString*)query, ... { +- (double) doubleForQuery:(NSString *)query, ...{ RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(double, doubleForColumnIndex); } -- (NSData*)dataForQuery:(NSString*)query, ... { +- (NSData *) dataForQuery:(NSString *)query, ...{ RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSData *, dataForColumnIndex); } -- (NSDate*)dateForQuery:(NSString*)query, ... { +- (NSDate *) dateForQuery:(NSString *)query, ...{ RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSDate *, dateForColumnIndex); } -- (BOOL)tableExists:(NSString*)tableName { - +- (BOOL) tableExists:(NSString *)tableName { + tableName = [tableName lowercaseString]; - - CCResultSet *rs = [self executeQuery:@"select [sql] from sqlite_master where [type] = 'table' and lower(name) = ?", tableName]; - - //if at least one next exists, table exists + + CCResultSet * rs = [self executeQuery:@"select [sql] from sqlite_master where [type] = 'table' and lower(name) = ?", tableName]; + + // if at least one next exists, table exists BOOL returnBool = [rs next]; - - //close and free object + + // close and free object [rs close]; - + return returnBool; } /* - get table with list of tables: result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING] - check if table exist in database (patch from OZLB) + * get table with list of tables: result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING] + * check if table exist in database (patch from OZLB) */ -- (CCResultSet*)getSchema { - - //result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING] - CCResultSet *rs = [self executeQuery:@"SELECT type, name, tbl_name, rootpage, sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type != 'meta' AND name NOT LIKE 'sqlite_%' ORDER BY tbl_name, type DESC, name"]; - +- (CCResultSet *) getSchema { + + // result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING] + CCResultSet * rs = [self executeQuery:@"SELECT type, name, tbl_name, rootpage, sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type != 'meta' AND name NOT LIKE 'sqlite_%' ORDER BY tbl_name, type DESC, name"]; + return rs; } /* - get table schema: result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER] + * get table schema: result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER] */ -- (CCResultSet*)getTableSchema:(NSString*)tableName { - - //result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER] - CCResultSet *rs = [self executeQuery:[NSString stringWithFormat: @"pragma table_info('%@')", tableName]]; - +- (CCResultSet *) getTableSchema:(NSString *)tableName { + + // result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER] + CCResultSet * rs = [self executeQuery:[NSString stringWithFormat:@"pragma table_info('%@')", tableName]]; + return rs; } -- (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName { - +- (BOOL) columnExists:(NSString *)columnName inTableWithName:(NSString *)tableName { + BOOL returnBool = NO; - + tableName = [tableName lowercaseString]; columnName = [columnName lowercaseString]; - - CCResultSet *rs = [self getTableSchema:tableName]; - - //check if column is present in table schema + + CCResultSet * rs = [self getTableSchema:tableName]; + + // check if column is present in table schema while ([rs next]) { if ([[[rs stringForColumn:@"name"] lowercaseString] isEqualToString:columnName]) { returnBool = YES; break; } } - - //If this is not done CCSQLite instance stays out of pool + + // If this is not done CCSQLite instance stays out of pool [rs close]; - + return returnBool; -} +} /* columnExists */ -- (uint32_t)applicationID { +- (uint32_t) applicationID { #if SQLITE_VERSION_NUMBER >= 3007017 uint32_t r = 0; - - CCResultSet *rs = [self executeQuery:@"pragma application_id"]; - + + CCResultSet * rs = [self executeQuery:@"pragma application_id"]; + if ([rs next]) { r = (uint32_t)[rs longLongIntForColumnIndex:0]; } - + [rs close]; - + return r; #else - NSString *errorMessage = NSLocalizedString(@"Application ID functions require SQLite 3.7.17", nil); + NSString * errorMessage = NSLocalizedString(@"Application ID functions require SQLite 3.7.17", nil); if (self.logsErrors) NSLog(@"%@", errorMessage); return 0; #endif } -- (void)setApplicationID:(uint32_t)appID { +- (void) setApplicationID:(uint32_t)appID { #if SQLITE_VERSION_NUMBER >= 3007017 - NSString *query = [NSString stringWithFormat:@"pragma application_id=%d", appID]; - CCResultSet *rs = [self executeQuery:query]; + NSString * query = [NSString stringWithFormat:@"pragma application_id=%d", appID]; + CCResultSet * rs = [self executeQuery:query]; [rs next]; [rs close]; #else - NSString *errorMessage = NSLocalizedString(@"Application ID functions require SQLite 3.7.17", nil); + NSString * errorMessage = NSLocalizedString(@"Application ID functions require SQLite 3.7.17", nil); if (self.logsErrors) NSLog(@"%@", errorMessage); #endif } @@ -2283,63 +2175,65 @@ - (void)setApplicationID:(uint32_t)appID { #if TARGET_OS_MAC && !TARGET_OS_IPHONE -- (NSString*)applicationIDString { +- (NSString *) applicationIDString { #if SQLITE_VERSION_NUMBER >= 3007017 - NSString *s = NSFileTypeForHFSTypeCode([self applicationID]); - + NSString * s = NSFileTypeForHFSTypeCode([self applicationID]); + assert([s length] == 6); - + s = [s substringWithRange:NSMakeRange(1, 4)]; - - + + return s; #else - NSString *errorMessage = NSLocalizedString(@"Application ID functions require SQLite 3.7.17", nil); + NSString * errorMessage = NSLocalizedString(@"Application ID functions require SQLite 3.7.17", nil); if (self.logsErrors) NSLog(@"%@", errorMessage); return nil; #endif } -- (void)setApplicationIDString:(NSString*)s { +- (void) setApplicationIDString:(NSString *)s { #if SQLITE_VERSION_NUMBER >= 3007017 if ([s length] != 4) { NSLog(@"setApplicationIDString: string passed is not exactly 4 chars long. (was %ld)", [s length]); } - + [self setApplicationID:NSHFSTypeCodeFromFileType([NSString stringWithFormat:@"'%@'", s])]; #else - NSString *errorMessage = NSLocalizedString(@"Application ID functions require SQLite 3.7.17", nil); + NSString * errorMessage = NSLocalizedString(@"Application ID functions require SQLite 3.7.17", nil); if (self.logsErrors) NSLog(@"%@", errorMessage); #endif } -#endif +#endif /* if TARGET_OS_MAC && !TARGET_OS_IPHONE */ -- (uint32_t)userVersion { +- (uint32_t) userVersion { uint32_t r = 0; - - CCResultSet *rs = [self executeQuery:@"pragma user_version"]; - + + CCResultSet * rs = [self executeQuery:@"pragma user_version"]; + if ([rs next]) { r = (uint32_t)[rs longLongIntForColumnIndex:0]; } - + [rs close]; return r; } -- (void)setUserVersion:(uint32_t)version { - NSString *query = [NSString stringWithFormat:@"pragma user_version = %d", version]; - CCResultSet *rs = [self executeQuery:query]; +- (void) setUserVersion:(uint32_t)version { + NSString * query = [NSString stringWithFormat:@"pragma user_version = %d", version]; + CCResultSet * rs = [self executeQuery:query]; + [rs next]; [rs close]; } -- (BOOL)validateSQL:(NSString*)sql error:(NSError**)error { - sqlite3_stmt *pStmt = NULL; +- (BOOL) validateSQL:(NSString *)sql error:(NSError **)error { + sqlite3_stmt * pStmt = NULL; BOOL validationSucceeded = YES; - + int rc = sqlite3_prepare_v2(_db, [sql UTF8String], -1, &pStmt, 0); + if (rc != SQLITE_OK) { validationSucceeded = NO; if (error) { @@ -2349,76 +2243,78 @@ - (BOOL)validateSQL:(NSString*)sql error:(NSError**)error { forKey:NSLocalizedDescriptionKey]]; } } - + sqlite3_finalize(pStmt); - + return validationSucceeded; } -- (SqliteValueType)valueType:(void *)value { +- (SqliteValueType) valueType:(void *)value { return sqlite3_value_type(value); } -- (int)valueInt:(void *)value { +- (int) valueInt:(void *)value { return sqlite3_value_int(value); } -- (long long)valueLong:(void *)value { +- (long long) valueLong:(void *)value { return sqlite3_value_int64(value); } -- (double)valueDouble:(void *)value { +- (double) valueDouble:(void *)value { return sqlite3_value_double(value); } -- (NSData *)valueData:(void *)value { - const void *bytes = sqlite3_value_blob(value); +- (NSData *) valueData:(void *)value { + const void * bytes = sqlite3_value_blob(value); int length = sqlite3_value_bytes(value); + return bytes ? [NSData dataWithBytes:bytes length:(NSUInteger)length] : nil; } -- (NSString *)valueString:(void *)value { - const char *cString = (const char *)sqlite3_value_text(value); +- (NSString *) valueString:(void *)value { + const char * cString = (const char *)sqlite3_value_text(value); + return cString ? [NSString stringWithUTF8String:cString] : nil; } -- (void)resultNullInContext:(void *)context { +- (void) resultNullInContext:(void *)context { sqlite3_result_null(context); } -- (void)resultInt:(int) value context:(void *)context { +- (void) resultInt:(int)value context:(void *)context { sqlite3_result_int(context, value); } -- (void)resultLong:(long long)value context:(void *)context { +- (void) resultLong:(long long)value context:(void *)context { sqlite3_result_int64(context, value); } -- (void)resultDouble:(double)value context:(void *)context { +- (void) resultDouble:(double)value context:(void *)context { sqlite3_result_double(context, value); } -- (void)resultData:(NSData *)data context:(void *)context { +- (void) resultData:(NSData *)data context:(void *)context { sqlite3_result_blob(context, data.bytes, (int)data.length, SQLITE_TRANSIENT); } -- (void)resultString:(NSString *)value context:(void *)context { +- (void) resultString:(NSString *)value context:(void *)context { sqlite3_result_text(context, [value UTF8String], -1, SQLITE_TRANSIENT); } -- (void)resultError:(NSString *)error context:(void *)context { +- (void) resultError:(NSString *)error context:(void *)context { sqlite3_result_error(context, [error UTF8String], -1); } -- (void)resultErrorCode:(int)errorCode context:(void *)context { +- (void) resultErrorCode:(int)errorCode context:(void *)context { sqlite3_result_error_code(context, errorCode); } -- (void)resultErrorNoMemoryInContext:(void *)context { +- (void) resultErrorNoMemoryInContext:(void *)context { sqlite3_result_error_nomem(context); } -- (void)resultErrorTooBigInContext:(void *)context { +- (void) resultErrorTooBigInContext:(void *)context { sqlite3_result_error_toobig(context); } @@ -2431,14 +2327,14 @@ - (void)resultErrorTooBigInContext:(void *)context { * * @return return value description */ -+ (NSData *) object2Data : (id) object { ++ (NSData *) object2Data:(id)object { if ([object isKindOfClass:[NSString class]]) { - NSString *data = object; + NSString * data = object; return [data dataUsingEncoding:NSUTF8StringEncoding]; } else if ([object isKindOfClass:[NSData class]]) { return object; } else if ([object isKindOfClass:[NSArray class]] || [object isKindOfClass:[NSDictionary class]]) { - return [NSJSONSerialization dataWithJSONObject:object options:0 error: nil]; + return [NSJSONSerialization dataWithJSONObject:object options:0 error:nil]; } else { NSLog(@"error args for object"); return nil; @@ -2452,11 +2348,11 @@ + (NSData *) object2Data : (id) object { * * @return return value description */ -+ (id) data2Object : (id) data { ++ (id) data2Object:(id)data { if (data && [data isKindOfClass:[NSData class]]) { return [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; } - + return data; } @@ -2464,6 +2360,6 @@ + (id) data2Object : (id) data { @interface CCSQLite (PrivateStuff) -- (CCResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args; +- (CCResultSet *) executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args; @end diff --git a/CCSQLite/CCSQLitePool.m b/CCSQLite/CCSQLitePool.m index 02b2f32..18520a2 100644 --- a/CCSQLite/CCSQLitePool.m +++ b/CCSQLite/CCSQLitePool.m @@ -9,33 +9,33 @@ #import "CCSQLitePool.h" #import "CCSQLite.h" -@interface CCSQLitePool() { - dispatch_queue_t _lockQueue; - - NSMutableArray *_databaseInPool; - NSMutableArray *_databaseOutPool; +@interface CCSQLitePool () { + dispatch_queue_t _lockQueue; + + NSMutableArray * _databaseInPool; + NSMutableArray * _databaseOutPool; } -- (void)pushDatabaseBackInPool:(CCSQLite*)db; -- (CCSQLite*)db; +- (void) pushDatabaseBackInPool:(CCSQLite *)db; +- (CCSQLite *) db; @end @implementation CCSQLitePool -+ (instancetype)databasePoolWithPath:(NSString*)aPath { ++ (instancetype) databasePoolWithPath:(NSString *)aPath { return CCReturnAutoreleased([[self alloc] initWithPath:aPath]); } -+ (instancetype)databasePoolWithPath:(NSString*)aPath flags:(int)openFlags { ++ (instancetype) databasePoolWithPath:(NSString *)aPath flags:(int)openFlags { return CCReturnAutoreleased([[self alloc] initWithPath:aPath flags:openFlags]); } -- (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString *)vfsName { - +- (instancetype) initWithPath:(NSString *)aPath flags:(int)openFlags vfs:(NSString *)vfsName { + self = [super init]; - + if (self != nil) { _path = [aPath copy]; _lockQueue = dispatch_queue_create([[NSString stringWithFormat:@"CCSQLitePool.%@", self] UTF8String], NULL); @@ -44,35 +44,34 @@ - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString _openFlags = openFlags; _vfsName = [vfsName copy]; } - + return self; } -- (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags { +- (instancetype) initWithPath:(NSString *)aPath flags:(int)openFlags { return [self initWithPath:aPath flags:openFlags vfs:nil]; } -- (instancetype)initWithPath:(NSString*)aPath -{ +- (instancetype) initWithPath:(NSString *)aPath { // default flags for sqlite3_open return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE]; } -- (instancetype)init { +- (instancetype) init { return [self initWithPath:nil]; } -+ (Class)databaseClass { ++ (Class) databaseClass { return [CCSQLite class]; } -- (void)dealloc { - +- (void) dealloc { + _delegate = CCNULL; CCRelease(_path); CCRelease(_databaseInPool); CCRelease(_databaseOutPool); - + if (_lockQueue) { CCDispatchQueueRelease(_lockQueue); _lockQueue = CCNULL; @@ -80,203 +79,198 @@ - (void)dealloc { } -- (void)executeLocked:(void (^)(void))aBlock { +- (void) executeLocked:(void (^)(void))aBlock { dispatch_sync(_lockQueue, aBlock); } -- (void)pushDatabaseBackInPool:(CCSQLite*)db { - +- (void) pushDatabaseBackInPool:(CCSQLite *)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 CCSQLite being put back into the pool is already present in the pool" userInfo:nil] raise]; - } - - [self->_databaseInPool addObject:db]; - [self->_databaseOutPool removeObject:db]; - - }]; + + if ([self->_databaseInPool containsObject:db]) { + [[NSException exceptionWithName:@"Database already in pool" reason:@"The CCSQLite being put back into the pool is already present in the pool" userInfo:nil] raise]; + } + + [self->_databaseInPool addObject:db]; + [self->_databaseOutPool removeObject:db]; + + }]; } -- (CCSQLite*)db { - - __block CCSQLite *db; - - +- (CCSQLite *) db { + + __block CCSQLite * 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 = [[[self class] databaseClass] databaseWithPath:self->_path]; - shouldNotifyDelegate = YES; - } - - //This ensures that the db is opened before returning + 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 = [[[self class] databaseClass] 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 vfs:self->_vfsName]; + BOOL success = [db openWithFlags:self->_openFlags vfs:self->_vfsName]; #else - BOOL success = [db open]; + BOOL success = [db open]; #endif - if (success) { - if ([self->_delegate respondsToSelector:@selector(databasePool:shouldAddDatabaseToPool:)] && ![self->_delegate databasePool:self shouldAddDatabaseToPool:db]) { - [db close]; - db = CCNULL; - } - 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 = CCNULL; - } - }]; - + if (success) { + if ([self->_delegate respondsToSelector:@selector(databasePool:shouldAddDatabaseToPool:)] && ![self->_delegate databasePool:self shouldAddDatabaseToPool:db]) { + [db close]; + db = CCNULL; + } 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 = CCNULL; + } + }]; + return db; -} +} /* db */ + +- (NSUInteger) countOfCheckedInDatabases { -- (NSUInteger)countOfCheckedInDatabases { - __block NSUInteger count; - + [self executeLocked:^() { - count = [self->_databaseInPool count]; - }]; - + count = [self->_databaseInPool count]; + }]; + return count; } -- (NSUInteger)countOfCheckedOutDatabases { - +- (NSUInteger) countOfCheckedOutDatabases { + __block NSUInteger count; - + [self executeLocked:^() { - count = [self->_databaseOutPool count]; - }]; - + count = [self->_databaseOutPool count]; + }]; + return count; } -- (NSUInteger)countOfOpenDatabases { +- (NSUInteger) countOfOpenDatabases { __block NSUInteger count; - + [self executeLocked:^() { - count = [self->_databaseOutPool count] + [self->_databaseInPool count]; - }]; - + count = [self->_databaseOutPool count] + [self->_databaseInPool count]; + }]; + return count; } -- (void)releaseAllDatabases { +- (void) releaseAllDatabases { [self executeLocked:^() { - [self->_databaseOutPool removeAllObjects]; - [self->_databaseInPool removeAllObjects]; - }]; + [self->_databaseOutPool removeAllObjects]; + [self->_databaseInPool removeAllObjects]; + }]; } -- (void)inDatabase:(void (^)(CCSQLite *db))block { - - CCSQLite *db = [self db]; - +- (void) inDatabase:(void (^)(CCSQLite * db))block { + + CCSQLite * db = [self db]; + block(db); - + [self pushDatabaseBackInPool:db]; } -- (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(CCSQLite *db, BOOL *rollback))block { - +- (void) beginTransaction:(BOOL)useDeferred withBlock:(void (^)(CCSQLite * db, BOOL * rollback))block { + BOOL shouldRollback = NO; - - CCSQLite *db = [self db]; - + + CCSQLite * db = [self db]; + if (useDeferred) { [db beginDeferredTransaction]; - } - else { + } else { [db beginTransaction]; } - - + + block(db, &shouldRollback); - + if (shouldRollback) { [db rollback]; - } - else { + } else { [db commit]; } - + [self pushDatabaseBackInPool:db]; -} +} /* beginTransaction */ -- (void)inDeferredTransaction:(void (^)(CCSQLite *db, BOOL *rollback))block { +- (void) inDeferredTransaction:(void (^)(CCSQLite * db, BOOL * rollback))block { [self beginTransaction:YES withBlock:block]; } -- (void)inTransaction:(void (^)(CCSQLite *db, BOOL *rollback))block { +- (void) inTransaction:(void (^)(CCSQLite * db, BOOL * rollback))block { [self beginTransaction:NO withBlock:block]; } -- (NSError*)inSavePoint:(void (^)(CCSQLite *db, BOOL *rollback))block { +- (NSError *) inSavePoint:(void (^)(CCSQLite * db, BOOL * rollback))block { #if SQLITE_VERSION_NUMBER >= 3007000 static unsigned long savePointIdx = 0; - - NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; - + + NSString * name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; + BOOL shouldRollback = NO; - - CCSQLite *db = [self db]; - - NSError *err = CCNULL; - + + CCSQLite * db = [self db]; + + NSError * err = CCNULL; + 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); +#else /* if SQLITE_VERSION_NUMBER >= 3007000 */ + NSString * errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil); if (self.logsErrors) NSLog(@"%@", errorMessage); - return [NSError errorWithDomain:@"CCSQLite" code:0 userInfo:@{NSLocalizedDescriptionKey : errorMessage}]; -#endif -} + return [NSError errorWithDomain:@"CCSQLite" code:0 userInfo:@{ NSLocalizedDescriptionKey : errorMessage }]; +#endif /* if SQLITE_VERSION_NUMBER >= 3007000 */ +} /* inSavePoint */ @end diff --git a/CCSQLite/CCSQLiteQueue.m b/CCSQLite/CCSQLiteQueue.m index 50487ac..087474f 100644 --- a/CCSQLite/CCSQLiteQueue.m +++ b/CCSQLite/CCSQLiteQueue.m @@ -10,18 +10,18 @@ #import "CCSQLite.h" @interface CCSQLiteQueue () { - dispatch_queue_t _queue; - CCSQLite *_db; + dispatch_queue_t _queue; + CCSQLite * _db; } @end /* - - Note: we call [self retain]; before using dispatch_sync, just incase - CCSQLiteQueue is released on another thread and we're in the middle of doing - something in dispatch_sync - + * + * Note: we call [self retain]; before using dispatch_sync, just incase + * CCSQLiteQueue is released on another thread and we're in the middle of doing + * something in dispatch_sync + * */ /* @@ -33,37 +33,37 @@ @interface CCSQLiteQueue () { @implementation CCSQLiteQueue -+ (instancetype)databaseQueueWithPath:(NSString*)aPath { - - CCSQLiteQueue *q = [[self alloc] initWithPath:aPath]; - ++ (instancetype) databaseQueueWithPath:(NSString *)aPath { + + CCSQLiteQueue * q = [[self alloc] initWithPath:aPath]; + CCAutorelease(q); - + return q; } -+ (instancetype)databaseQueueWithPath:(NSString*)aPath flags:(int)openFlags { - - CCSQLiteQueue *q = [[self alloc] initWithPath:aPath flags:openFlags]; - ++ (instancetype) databaseQueueWithPath:(NSString *)aPath flags:(int)openFlags { + + CCSQLiteQueue * q = [[self alloc] initWithPath:aPath flags:openFlags]; + CCAutorelease(q); - + return q; } -+ (Class)databaseClass { ++ (Class) databaseClass { return [CCSQLite class]; } -- (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString *)vfsName { - +- (instancetype) initWithPath:(NSString *)aPath flags:(int)openFlags vfs:(NSString *)vfsName { + self = [super init]; - + if (self != nil) { - + _db = [[[self class] databaseClass] databaseWithPath:aPath]; CCRetain(_db); - + #if SQLITE_VERSION_NUMBER >= 3005000 BOOL success = [_db openWithFlags:openFlags vfs:vfsName]; #else @@ -74,45 +74,45 @@ - (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags vfs:(NSString CCRelease(self); return CCNULL; } - + _path = CCReturnRetained(aPath); - + _queue = dispatch_queue_create([[NSString stringWithFormat:@"CCSQLiteQueue.%@", self] UTF8String], NULL); dispatch_queue_set_specific(_queue, kDispatchQueueSpecificKey, (__bridge void *)self, NULL); _openFlags = openFlags; _vfsName = [vfsName copy]; } - + return self; -} +} /* initWithPath */ -- (instancetype)initWithPath:(NSString*)aPath flags:(int)openFlags { +- (instancetype) initWithPath:(NSString *)aPath flags:(int)openFlags { return [self initWithPath:aPath flags:openFlags vfs:nil]; } -- (instancetype)initWithPath:(NSString*)aPath { - +- (instancetype) initWithPath:(NSString *)aPath { + // default flags for sqlite3_open return [self initWithPath:aPath flags:SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE vfs:nil]; } -- (instancetype)init { +- (instancetype) init { return [self initWithPath:nil]; } -- (void)dealloc { - +- (void) dealloc { + CCRelease(_db); CCRelease(_path); - + if (_queue) { CCDispatchQueueRelease(_queue); _queue = CCNULL; } } -- (void)close { +- (void) close { CCRetain(self); dispatch_sync(_queue, ^() { [self->_db close]; @@ -122,15 +122,14 @@ - (void)close { CCRelease(self); } -- (void)interrupt -{ +- (void) interrupt { [[self database] interrupt]; } -- (CCSQLite*)database { +- (CCSQLite *) database { if (!_db) { _db = CCReturnRetained([[[self class] databaseClass] databaseWithPath:_path]); - + #if SQLITE_VERSION_NUMBER >= 3005000 BOOL success = [_db openWithFlags:_openFlags vfs:_vfsName]; #else @@ -143,106 +142,104 @@ - (CCSQLite*)database { return CCNULL; } } - + return _db; } -- (void)inDatabase:(void (^)(CCSQLite *db))block { +- (void) inDatabase:(void (^)(CCSQLite * db))block { #ifndef NDEBUG /* Get the currently executing queue (which should probably be nil, but in theory could be another DB queue * and then check it against self to make sure we're not about to deadlock. */ - CCSQLiteQueue *currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey); + CCSQLiteQueue * currentSyncQueue = (__bridge id)dispatch_get_specific(kDispatchQueueSpecificKey); assert(currentSyncQueue != self && "inDatabase: was called reentrantly on the same queue, which would lead to a deadlock"); #endif - + CCRetain(self); - + dispatch_sync(_queue, ^() { - - CCSQLite *db = [self database]; + + CCSQLite * db = [self database]; block(db); - + if ([db hasOpenResultSets]) { NSLog(@"Warning: there is at least one open result set around after performing [CCSQLiteQueue inDatabase:]"); - + #if defined(DEBUG) && DEBUG - NSSet *openSetCopy = CCReturnAutoreleased([[db valueForKey:@"_openResultSets"] copy]); - for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) { - CCResultSet *rs = (CCResultSet *)[rsInWrappedInATastyValueMeal pointerValue]; + NSSet * openSetCopy = CCReturnAutoreleased([[db valueForKey:@"_openResultSets"] copy]); + for (NSValue * rsInWrappedInATastyValueMeal in openSetCopy) { + CCResultSet * rs = (CCResultSet *)[rsInWrappedInATastyValueMeal pointerValue]; NSLog(@"query: '%@'", [rs query]); } #endif } }); - + CCRelease(self); -} +} /* inDatabase */ -- (void)beginTransaction:(BOOL)useDeferred withBlock:(void (^)(CCSQLite *db, BOOL *rollback))block { +- (void) beginTransaction:(BOOL)useDeferred withBlock:(void (^)(CCSQLite * db, BOOL * rollback))block { CCRetain(self); dispatch_sync(_queue, ^() { - + BOOL shouldRollback = NO; - + if (useDeferred) { [[self database] beginDeferredTransaction]; - } - else { + } else { [[self database] beginTransaction]; } - + block([self database], &shouldRollback); - + if (shouldRollback) { [[self database] rollback]; - } - else { + } else { [[self database] commit]; } }); - + CCRelease(self); -} +} /* beginTransaction */ -- (void)inDeferredTransaction:(void (^)(CCSQLite *db, BOOL *rollback))block { +- (void) inDeferredTransaction:(void (^)(CCSQLite * db, BOOL * rollback))block { [self beginTransaction:YES withBlock:block]; } -- (void)inTransaction:(void (^)(CCSQLite *db, BOOL *rollback))block { +- (void) inTransaction:(void (^)(CCSQLite * db, BOOL * rollback))block { [self beginTransaction:NO withBlock:block]; } -- (NSError*)inSavePoint:(void (^)(CCSQLite *db, BOOL *rollback))block { +- (NSError *) inSavePoint:(void (^)(CCSQLite * db, BOOL * rollback))block { #if SQLITE_VERSION_NUMBER >= 3007000 static unsigned long savePointIdx = 0; - __block NSError *err = CCNULL; + __block NSError * err = CCNULL; CCRetain(self); dispatch_sync(_queue, ^() { - - NSString *name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; - + + NSString * name = [NSString stringWithFormat:@"savePoint%ld", savePointIdx++]; + BOOL shouldRollback = NO; - + if ([[self database] startSavePointWithName:name error:&err]) { - + block([self database], &shouldRollback); - + if (shouldRollback) { // We need to rollback and release this savepoint to remove it [[self database] rollbackToSavePointWithName:name error:&err]; } [[self database] releaseSavePointWithName:name error:&err]; - + } }); CCRelease(self); return err; -#else - NSString *errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil); +#else /* if SQLITE_VERSION_NUMBER >= 3007000 */ + NSString * errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil); if (self.logsErrors) NSLog(@"%@", errorMessage); - return [NSError errorWithDomain:@"CCSQLite" code:0 userInfo:@{NSLocalizedDescriptionKey : errorMessage}]; -#endif -} + return [NSError errorWithDomain:@"CCSQLite" code:0 userInfo:@{ NSLocalizedDescriptionKey : errorMessage }]; +#endif /* if SQLITE_VERSION_NUMBER >= 3007000 */ +} /* inSavePoint */ @end diff --git a/CCSQLite/CCStatement.m b/CCSQLite/CCStatement.m index a5f4c12..bde672a 100644 --- a/CCSQLite/CCStatement.m +++ b/CCSQLite/CCStatement.m @@ -11,28 +11,28 @@ @implementation CCStatement -- (void)dealloc { +- (void) dealloc { [self close]; } -- (void)close { +- (void) close { if (_statement) { sqlite3_finalize(_statement); _statement = CCNULL; } - + _inUse = NO; } -- (void)reset { +- (void) reset { if (_statement) { sqlite3_reset(_statement); } - + _inUse = NO; } -- (NSString*)description { +- (NSString *) description { return [NSString stringWithFormat:@"%@ %ld hit(s) for query %@", [super description], _useCount, _query]; }