Skip to content

Commit

Permalink
Merge pull request #620 from robertmryan/master
Browse files Browse the repository at this point in the history
Update transactions
  • Loading branch information
ccgus committed Oct 24, 2017
2 parents 7ebbfd0 + 1da3a20 commit e0fcde9
Show file tree
Hide file tree
Showing 15 changed files with 200 additions and 19 deletions.
5 changes: 5 additions & 0 deletions CHANGES_AND_TODO_LIST.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ 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 the necessary of tests for your new code to tests target. 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.

2017.10.23 Version 2.7.4
Added support for explicit transactions.

Add warning that `beginTransaction` and `inTransaction` behavior is likely to change.

2017.10.20 Version 2.7.3
Added support for immediate transactions and checkpoint. (thanks to @benasher44)

Expand Down
2 changes: 1 addition & 1 deletion FMDB.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'FMDB'
s.version = '2.7.3'
s.version = '2.7.4'
s.summary = 'A Cocoa / Objective-C wrapper around SQLite.'
s.homepage = 'https://github.com/ccgus/fmdb'
s.license = 'MIT'
Expand Down
91 changes: 91 additions & 0 deletions Tests/FMDatabaseQueueTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,54 @@ - (void)testURLOpenNoURL {
queue = nil;
}

- (void)testInvalidURL {
NSURL *tempFolder = [NSURL fileURLWithPath:NSTemporaryDirectory()];
NSURL *folderURL = [tempFolder URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
NSURL *fileURL = [folderURL URLByAppendingPathComponent:@"test.sqlite"];

FMDatabaseQueue *queue = [[FMDatabaseQueue alloc] initWithURL:fileURL];
XCTAssertNil(queue, @"Database queue should not be returned for invalid path");
queue = nil;
}

- (void)testInvalidPath {
NSURL *tempFolder = [NSURL fileURLWithPath:NSTemporaryDirectory()];
NSURL *folderURL = [tempFolder URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
NSURL *fileURL = [folderURL URLByAppendingPathComponent:@"test.sqlite"];

FMDatabaseQueue *queue = [[FMDatabaseQueue alloc] initWithPath:fileURL.path];
XCTAssertNil(queue, @"Database queue should not be returned for invalid path");
queue = nil;
}

- (void)testReopenFailure {
NSFileManager *manager = [NSFileManager defaultManager];

NSURL *tempFolder = [NSURL fileURLWithPath:NSTemporaryDirectory()];
NSURL *folderURL = [tempFolder URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
BOOL success = [manager createDirectoryAtURL:folderURL withIntermediateDirectories:true attributes:nil error:nil];
NSAssert(success, @"Unable to create folder");

NSURL *fileURL = [folderURL URLByAppendingPathComponent:@"test.sqlite"];

FMDatabaseQueue *queue = [[FMDatabaseQueue alloc] initWithURL:fileURL];
XCTAssert(queue, @"Database queue was unable to be created");

[queue close];

success = [manager removeItemAtURL:fileURL error:nil];
XCTAssert(success, @"Unable to remove database");

success = [manager removeItemAtURL:folderURL error:nil];
XCTAssert(success, @"Unable to remove folder");

[queue inDatabase:^(FMDatabase *db) {
XCTAssertNil(db, @"Should be `nil` or never have reached here because database couldn't be reopened");
}];

queue = nil;
}

- (void)testURLOpen {
NSURL *tempFolder = [NSURL fileURLWithPath:NSTemporaryDirectory()];
NSURL *fileURL = [tempFolder URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]];
Expand Down Expand Up @@ -260,7 +308,50 @@ - (void)testTransaction

XCTAssertEqual(rowCount, 2);
}];

}

- (void)testSavePoint
{
[self.queue inDatabase:^(FMDatabase *adb) {
[adb executeUpdate:@"create table transtest (a integer)"];
XCTAssertTrue([adb executeUpdate:@"insert into transtest values (1)"]);
XCTAssertTrue([adb executeUpdate:@"insert into transtest values (2)"]);

int rowCount = 0;
FMResultSet *ars = [adb executeQuery:@"select * from transtest"];
while ([ars next]) {
rowCount++;
}

XCTAssertEqual(rowCount, 2);
}];

[self.queue inSavePoint:^(FMDatabase *adb, BOOL *rollback) {
XCTAssertTrue([adb executeUpdate:@"insert into transtest values (3)"]);

if (YES) {
// uh oh!, something went wrong (not really, this is just a test
*rollback = YES;
return;
}

XCTFail(@"This shouldn't be reached");
}];

[self.queue inDatabase:^(FMDatabase *adb) {

int rowCount = 0;
FMResultSet *ars = [adb executeQuery:@"select * from transtest"];
while ([ars next]) {
rowCount++;
}

XCTAssertFalse([adb hasOpenResultSets]);

XCTAssertEqual(rowCount, 2);
}];

}

@end
2 changes: 1 addition & 1 deletion Tests/FMDatabaseTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -1125,7 +1125,7 @@ - (void)createCustomFunctions {
}

- (void)testVersionNumber {
XCTAssertTrue([FMDatabase FMDBVersion] == 0x0273); // this is going to break everytime we bump it.
XCTAssertTrue([FMDatabase FMDBVersion] == 0x0274); // this is going to break everytime we bump it.
}

- (void)testExecuteStatements {
Expand Down
3 changes: 1 addition & 2 deletions Tests/FMResultSetTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,11 @@ - (void)testNextWithError_WithBusyError
FMDatabase *newDB = [FMDatabase databaseWithPath:self.databasePath];
[newDB open];

[newDB beginTransaction];
[newDB beginExclusiveTransaction];
NSError *error;
XCTAssertFalse([resultSet nextWithError:&error]);
[newDB commit];


XCTAssertEqual(error.code, SQLITE_BUSY, @"SQLITE_BUSY should be the last error");
[resultSet close];
}
Expand Down
14 changes: 13 additions & 1 deletion fmdb.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0820;
LastUpgradeCheck = 0900;
TargetAttributes = {
83C73EFD1C326AB000FFC730 = {
CreatedOnToolsVersion = 7.2;
Expand Down Expand Up @@ -767,12 +767,18 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
Expand All @@ -799,12 +805,18 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
Expand Down
4 changes: 3 additions & 1 deletion fmdb.xcodeproj/xcshareddata/xcschemes/FMDB MacOS.xcscheme
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0820"
LastUpgradeVersion = "0900"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand All @@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
Expand All @@ -36,6 +37,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
Expand Down
4 changes: 3 additions & 1 deletion fmdb.xcodeproj/xcshareddata/xcschemes/FMDB iOS.xcscheme
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0820"
LastUpgradeVersion = "0900"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand All @@ -26,6 +26,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
Expand All @@ -36,6 +37,7 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
Expand Down
25 changes: 23 additions & 2 deletions src/fmdb/FMDatabase.h
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,15 @@ typedef NS_ENUM(int, FMDBCheckpointMode) {
@see rollback
@see beginDeferredTransaction
@see isInTransaction
@warning Unlike SQLite's `BEGIN TRANSACTION`, this method currently performs
an exclusive transaction, not a deferred transaction. This behavior
is likely to change in future versions of FMDB, whereby this method
will likely eventually adopt standard SQLite behavior and perform
deferred transactions. If you really need exclusive tranaction, it is
recommended that you use `beginExclusiveTransaction`, instead, not
only to make your intent explicit, but also to future-proof your code.
*/

- (BOOL)beginTransaction;
Expand All @@ -702,9 +711,9 @@ typedef NS_ENUM(int, FMDBCheckpointMode) {
- (BOOL)beginDeferredTransaction;

/** Begin an immediate transaction
@return `YES` on success; `NO` on failure. If failed, you can call `<lastError>`, `<lastErrorCode>`, or `<lastErrorMessage>` for diagnostic information regarding the failure.
@see commit
@see rollback
@see beginTransaction
Expand All @@ -713,6 +722,18 @@ typedef NS_ENUM(int, FMDBCheckpointMode) {

- (BOOL)beginImmediateTransaction;

/** Begin an exclusive transaction
@return `YES` on success; `NO` on failure. If failed, you can call `<lastError>`, `<lastErrorCode>`, or `<lastErrorMessage>` for diagnostic information regarding the failure.
@see commit
@see rollback
@see beginTransaction
@see isInTransaction
*/

- (BOOL)beginExclusiveTransaction;

/** Commit a transaction
Commit a transaction that was initiated with either `<beginTransaction>` or with `<beginDeferredTransaction>`.
Expand Down
18 changes: 14 additions & 4 deletions src/fmdb/FMDatabase.m
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ - (NSURL *)databaseURL {
}

+ (NSString*)FMDBUserVersion {
return @"2.7.3";
return @"2.7.4";
}

// returns 0x0240 for version 2.4. This makes it super easy to do things like:
Expand Down Expand Up @@ -1312,6 +1312,16 @@ - (BOOL)commit {
return b;
}

- (BOOL)beginTransaction {

BOOL b = [self executeUpdate:@"begin exclusive transaction"];
if (b) {
_isInTransaction = YES;
}

return b;
}

- (BOOL)beginDeferredTransaction {

BOOL b = [self executeUpdate:@"begin deferred transaction"];
Expand All @@ -1323,16 +1333,16 @@ - (BOOL)beginDeferredTransaction {
}

- (BOOL)beginImmediateTransaction {

BOOL b = [self executeUpdate:@"begin immediate transaction"];
if (b) {
_isInTransaction = YES;
}

return b;
}

- (BOOL)beginTransaction {
- (BOOL)beginExclusiveTransaction {

BOOL b = [self executeUpdate:@"begin exclusive transaction"];
if (b) {
Expand Down
17 changes: 16 additions & 1 deletion src/fmdb/FMDatabasePool.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,11 +199,26 @@ NS_ASSUME_NONNULL_BEGIN
- (void)inDatabase:(__attribute__((noescape)) void (^)(FMDatabase *db))block;

/** Synchronously perform database operations in pool using transaction.
@param block The code to be run on the `FMDatabasePool` pool.
@warning Unlike SQLite's `BEGIN TRANSACTION`, this method currently performs
an exclusive transaction, not a deferred transaction. This behavior
is likely to change in future versions of FMDB, whereby this method
will likely eventually adopt standard SQLite behavior and perform
deferred transactions. If you really need exclusive tranaction, it is
recommended that you use `inExclusiveTransaction`, instead, not only
to make your intent explicit, but also to future-proof your code.
*/

- (void)inTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block;

/** Synchronously perform database operations in pool using exclusive transaction.
@param block The code to be run on the `FMDatabasePool` pool.
*/

- (void)inTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block;
- (void)inExclusiveTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block;

/** Synchronously perform database operations in pool using deferred transaction.
Expand Down
6 changes: 5 additions & 1 deletion src/fmdb/FMDatabasePool.m
Original file line number Diff line number Diff line change
Expand Up @@ -281,11 +281,15 @@ - (void)beginTransaction:(FMDBTransaction)transaction withBlock:(void (^)(FMData
[self pushDatabaseBackInPool:db];
}

- (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {
[self beginTransaction:FMDBTransactionExclusive withBlock:block];
}

- (void)inDeferredTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {
[self beginTransaction:FMDBTransactionDeferred withBlock:block];
}

- (void)inTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {
- (void)inExclusiveTransaction:(void (^)(FMDatabase *db, BOOL *rollback))block {
[self beginTransaction:FMDBTransactionExclusive withBlock:block];
}

Expand Down
Loading

0 comments on commit e0fcde9

Please sign in to comment.