From 25f34a14f4bb70375507c1af97b90f0b362a59cb Mon Sep 17 00:00:00 2001 From: Roshan Muralidharan Date: Thu, 9 Oct 2014 13:52:12 -0500 Subject: [PATCH 1/2] Adding 'nextWithError' method to FMResultSet to obtain error details --- Tests/FMResultSetTests.m | 91 ++++++++++++++++++++++++++++++++++ fmdb.xcodeproj/project.pbxproj | 4 ++ src/fmdb/FMResultSet.h | 15 +++++- src/fmdb/FMResultSet.m | 25 ++++++++++ 4 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 Tests/FMResultSetTests.m diff --git a/Tests/FMResultSetTests.m b/Tests/FMResultSetTests.m new file mode 100644 index 0000000..b62eea3 --- /dev/null +++ b/Tests/FMResultSetTests.m @@ -0,0 +1,91 @@ +// +// FMResultSetTests.m +// fmdb +// +// Created by Muralidharan,Roshan on 10/6/14. +// +// + +#import "FMDBTempDBTests.h" +#import "FMDatabase.h" +#import "FMResultSet.h" + +@interface FMResultSetTests : FMDBTempDBTests + +@end + +@implementation FMResultSetTests + ++ (void)populateDatabase:(FMDatabase *)db +{ + [db executeUpdate:@"create table test (a text, b text, c integer, d double, e double)"]; + + [db beginTransaction]; + int i = 0; + while (i++ < 20) { + [db executeUpdate:@"insert into test (a, b, c, d, e) values (?, ?, ?, ?, ?)" , + @"hi'", + [NSString stringWithFormat:@"number %d", i], + [NSNumber numberWithInt:i], + [NSDate date], + [NSNumber numberWithFloat:2.2f]]; + } + [db commit]; +} + +- (void)testNextWithError_WithoutError +{ + [self.db executeUpdate:@"CREATE TABLE testTable(key INTEGER PRIMARY KEY, value INTEGER)"]; + [self.db executeUpdate:@"INSERT INTO testTable (key, value) VALUES (1, 2)"]; + [self.db executeUpdate:@"INSERT INTO testTable (key, value) VALUES (2, 4)"]; + + FMResultSet *resultSet = [self.db executeQuery:@"SELECT * FROM testTable WHERE key=1"]; + XCTAssertNotNil(resultSet); + NSError *error; + XCTAssertTrue([resultSet nextWithError:&error]); + XCTAssertNil(error); + + XCTAssertFalse([resultSet nextWithError:&error]); + XCTAssertNil(error); + + [resultSet close]; +} + +- (void)testNextWithError_WithBusyError +{ + [self.db executeUpdate:@"CREATE TABLE testTable(key INTEGER PRIMARY KEY, value INTEGER)"]; + [self.db executeUpdate:@"INSERT INTO testTable (key, value) VALUES (1, 2)"]; + [self.db executeUpdate:@"INSERT INTO testTable (key, value) VALUES (2, 4)"]; + + FMResultSet *resultSet = [self.db executeQuery:@"SELECT * FROM testTable WHERE key=1"]; + XCTAssertNotNil(resultSet); + + FMDatabase *newDB = [FMDatabase databaseWithPath:self.databasePath]; + [newDB open]; + + [newDB beginTransaction]; + NSError *error; + XCTAssertFalse([resultSet nextWithError:&error]); + [newDB commit]; + + + XCTAssertEqual(error.code, SQLITE_BUSY, @"SQLITE_BUSY should be the last error"); + [resultSet close]; +} + +- (void)testNextWithError_WithMisuseError +{ + [self.db executeUpdate:@"CREATE TABLE testTable(key INTEGER PRIMARY KEY, value INTEGER)"]; + [self.db executeUpdate:@"INSERT INTO testTable (key, value) VALUES (1, 2)"]; + [self.db executeUpdate:@"INSERT INTO testTable (key, value) VALUES (2, 4)"]; + + FMResultSet *resultSet = [self.db executeQuery:@"SELECT * FROM testTable WHERE key=9"]; + XCTAssertNotNil(resultSet); + XCTAssertFalse([resultSet next]); + NSError *error; + XCTAssertFalse([resultSet nextWithError:&error]); + + XCTAssertEqual(error.code, SQLITE_MISUSE, @"SQLITE_MISUSE should be the last error"); +} + +@end diff --git a/fmdb.xcodeproj/project.pbxproj b/fmdb.xcodeproj/project.pbxproj index 735912a..d805b20 100644 --- a/fmdb.xcodeproj/project.pbxproj +++ b/fmdb.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 3354379C19E71096005661F3 /* FMResultSetTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3354379B19E71096005661F3 /* FMResultSetTests.m */; }; 621721B21892BFE30006691F /* FMDatabase.m in Sources */ = {isa = PBXBuildFile; fileRef = CCC24EBB0A13E34D00A6D3E3 /* FMDatabase.m */; }; 621721B31892BFE30006691F /* FMResultSet.m in Sources */ = {isa = PBXBuildFile; fileRef = CCC24EC00A13E34D00A6D3E3 /* FMResultSet.m */; }; 621721B41892BFE30006691F /* FMDatabaseQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = CC47A00E148581E9002CCDAB /* FMDatabaseQueue.m */; }; @@ -88,6 +89,7 @@ /* Begin PBXFileReference section */ 08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 32A70AAB03705E1F00C91783 /* fmdb_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fmdb_Prefix.pch; path = src/sample/fmdb_Prefix.pch; sourceTree = SOURCE_ROOT; }; + 3354379B19E71096005661F3 /* FMResultSetTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FMResultSetTests.m; sourceTree = ""; }; 6290CBB5188FE836009790F8 /* libFMDB-IOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libFMDB-IOS.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 6290CBB6188FE836009790F8 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 6290CBC6188FE837009790F8 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; @@ -275,6 +277,7 @@ BF5D041A18416BB2008C5AA9 /* Tests */ = { isa = PBXGroup; children = ( + 3354379B19E71096005661F3 /* FMResultSetTests.m */, BF940F5A18417D490001E077 /* FMDBTempDBTests.h */, BF940F5B18417D490001E077 /* FMDBTempDBTests.m */, BF5D042018416BB2008C5AA9 /* FMDatabaseTests.m */, @@ -488,6 +491,7 @@ CCA66A3019C0CB1900EFDAC1 /* FMTokenizers.m in Sources */, BF940F5C18417D490001E077 /* FMDBTempDBTests.m in Sources */, BF940F5E18417DEA0001E077 /* FMDatabaseAdditionsTests.m in Sources */, + 3354379C19E71096005661F3 /* FMResultSetTests.m in Sources */, BF5D042118416BB2008C5AA9 /* FMDatabaseTests.m in Sources */, 67CB1E3019AD27D000A3CA7F /* FMDatabaseFTS3Tests.m in Sources */, BFE55E131841C9A000CB3A63 /* FMDatabasePoolTests.m in Sources */, diff --git a/src/fmdb/FMResultSet.h b/src/fmdb/FMResultSet.h index 8585a69..65250f0 100644 --- a/src/fmdb/FMResultSet.h +++ b/src/fmdb/FMResultSet.h @@ -74,7 +74,7 @@ /** Retrieve next row for result set. - You must always invoke `next` before attempting to access the values returned in a query, even if you're only expecting one. + You must always invoke `next` or `nextWithError` before attempting to access the values returned in a query, even if you're only expecting one. @return `YES` if row successfully retrieved; `NO` if end of result set reached @@ -83,6 +83,19 @@ - (BOOL)next; +/** Retrieve next row for result set. + + You must always invoke `next` or `nextWithError` before attempting to access the values returned in a query, even if you're only expecting one. + + @param outErr A 'NSError' object to receive any error object (if any). + + @return 'YES' if row successfully retrieved; 'NO' if end of result set reached + + @see hasAnotherRow + */ + +- (BOOL)nextWithError:(NSError **)outErr; + /** Did the last call to `` succeed in retrieving another row? @return `YES` if the last call to `` succeeded in retrieving another record; `NO` if not. diff --git a/src/fmdb/FMResultSet.m b/src/fmdb/FMResultSet.m index 9d6c6e1..a49fc4b 100644 --- a/src/fmdb/FMResultSet.m +++ b/src/fmdb/FMResultSet.m @@ -147,26 +147,51 @@ - (BOOL)next { + return [self nextWithError:nil]; +} + +- (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) { // all is well, let's return. } 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) { // uh oh. NSLog(@"Error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); + if (outErr) { + if (_parentDB) { + *outErr = [_parentDB lastError]; + } + 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]; + *outErr = [NSError errorWithDomain:@"FMDatabase" code:SQLITE_MISUSE userInfo:errorMessage]; + } + + } } else { // wtf? NSLog(@"Unknown error calling sqlite3_step (%d: %s) rs", rc, sqlite3_errmsg([_parentDB sqliteHandle])); + if (outErr) { + *outErr = [_parentDB lastError]; + } } From a2db0af530b5976e1a12d3ef675a7e7a42fd2b88 Mon Sep 17 00:00:00 2001 From: August Mueller Date: Sun, 19 Oct 2014 14:35:42 -0700 Subject: [PATCH 2/2] Cleanup and sdk fixes. --- CHANGES_AND_TODO_LIST.txt | 3 +++ fmdb.xcodeproj/project.pbxproj | 14 ++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/CHANGES_AND_TODO_LIST.txt b/CHANGES_AND_TODO_LIST.txt index f630cf0..ac242a7 100644 --- a/CHANGES_AND_TODO_LIST.txt +++ b/CHANGES_AND_TODO_LIST.txt @@ -3,6 +3,9 @@ Zip, nada, zilch. Got any ideas? If you would like to contribute some code- awesome! I just ask that you make it conform to the coding conventions already set in here, and to add a couple of tests for your new code to fmdb.m. And of course, the code should be of general use to more than just a couple of folks. Send your patches to gus@flyingmeat.com. +2013.10.19 + Added a 'nextWithError:' to FMResultSet. Thanks to Roshan Muralidharan for the patch. + 2014.09.10 New classes for exposing SQLite's FTS features. Thanks to Andrew Goodale for the code. diff --git a/fmdb.xcodeproj/project.pbxproj b/fmdb.xcodeproj/project.pbxproj index ff31a12..6dc450f 100644 --- a/fmdb.xcodeproj/project.pbxproj +++ b/fmdb.xcodeproj/project.pbxproj @@ -295,14 +295,14 @@ BF5D041A18416BB2008C5AA9 /* Tests */ = { isa = PBXGroup; children = ( - 3354379B19E71096005661F3 /* FMResultSetTests.m */, - BF940F5A18417D490001E077 /* FMDBTempDBTests.h */, - BF940F5B18417D490001E077 /* FMDBTempDBTests.m */, - BF5D042018416BB2008C5AA9 /* FMDatabaseTests.m */, - BFE55E121841C9A000CB3A63 /* FMDatabasePoolTests.m */, - BFE55E141841D38800CB3A63 /* FMDatabaseQueueTests.m */, BF940F5D18417DEA0001E077 /* FMDatabaseAdditionsTests.m */, 67CB1E2F19AD27D000A3CA7F /* FMDatabaseFTS3Tests.m */, + BFE55E121841C9A000CB3A63 /* FMDatabasePoolTests.m */, + BFE55E141841D38800CB3A63 /* FMDatabaseQueueTests.m */, + BF5D042018416BB2008C5AA9 /* FMDatabaseTests.m */, + BF940F5A18417D490001E077 /* FMDBTempDBTests.h */, + BF940F5B18417D490001E077 /* FMDBTempDBTests.m */, + 3354379B19E71096005661F3 /* FMResultSetTests.m */, BF5D041B18416BB2008C5AA9 /* Supporting Files */, ); path = Tests; @@ -612,6 +612,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx10.9; }; name = Debug; }; @@ -631,6 +632,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + SDKROOT = macosx10.9; }; name = Release; };