mirror of
https://github.com/darlinghq/fmdb.git
synced 2024-11-30 07:50:27 +00:00
Merge branch 'rosh89-FMResultSet_Next_Error_Handling'
This commit is contained in:
commit
dca59f3c3b
@ -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.
|
||||
|
||||
|
91
Tests/FMResultSetTests.m
Normal file
91
Tests/FMResultSetTests.m
Normal file
@ -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
|
@ -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 = "<absolute>"; };
|
||||
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 = "<group>"; };
|
||||
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; };
|
||||
@ -293,13 +295,14 @@
|
||||
BF5D041A18416BB2008C5AA9 /* Tests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
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;
|
||||
@ -506,6 +509,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 */,
|
||||
@ -608,6 +612,7 @@
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx10.9;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@ -627,6 +632,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
SDKROOT = macosx10.9;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
@ -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 `<next>` succeed in retrieving another row?
|
||||
|
||||
@return `YES` if the last call to `<next>` succeeded in retrieving another record; `NO` if not.
|
||||
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user