mirror of
https://github.com/darlinghq/fmdb.git
synced 2024-11-27 06:20:34 +00:00
commit
e0fcde9a0e
@ -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)
|
||||
|
||||
|
@ -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'
|
||||
|
@ -59,6 +59,54 @@
|
||||
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]];
|
||||
@ -260,7 +308,50 @@
|
||||
|
||||
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
|
||||
|
@ -1125,7 +1125,7 @@
|
||||
}
|
||||
|
||||
- (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 {
|
||||
|
@ -69,12 +69,11 @@
|
||||
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];
|
||||
}
|
||||
|
@ -552,7 +552,7 @@
|
||||
08FB7793FE84155DC02AAC07 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0820;
|
||||
LastUpgradeCheck = 0900;
|
||||
TargetAttributes = {
|
||||
83C73EFD1C326AB000FFC730 = {
|
||||
CreatedOnToolsVersion = 7.2;
|
||||
@ -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;
|
||||
@ -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;
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0820"
|
||||
LastUpgradeVersion = "0900"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@ -26,6 +26,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
@ -36,6 +37,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0820"
|
||||
LastUpgradeVersion = "0900"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@ -26,6 +26,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
@ -36,6 +37,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
language = ""
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
|
@ -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;
|
||||
@ -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
|
||||
@ -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>`.
|
||||
|
@ -98,7 +98,7 @@ NS_ASSUME_NONNULL_END
|
||||
}
|
||||
|
||||
+ (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:
|
||||
@ -1312,6 +1312,16 @@ int FMDBExecuteBulkSQLCallback(void *theBlockAsVoid, int columns, char **values,
|
||||
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"];
|
||||
@ -1323,16 +1333,16 @@ int FMDBExecuteBulkSQLCallback(void *theBlockAsVoid, int columns, char **values,
|
||||
}
|
||||
|
||||
- (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) {
|
||||
|
@ -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.
|
||||
|
||||
|
@ -281,11 +281,15 @@ typedef NS_ENUM(NSInteger, FMDBTransaction) {
|
||||
[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];
|
||||
}
|
||||
|
||||
|
@ -205,17 +205,33 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
/** Synchronously perform database operations on queue, using transactions.
|
||||
|
||||
@param block The code to be run on the queue of `FMDatabaseQueue`
|
||||
|
||||
@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 on queue, using deferred transactions.
|
||||
|
||||
|
||||
@param block The code to be run on the queue of `FMDatabaseQueue`
|
||||
*/
|
||||
|
||||
- (void)inDeferredTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block;
|
||||
|
||||
/** Synchronously perform database operations on queue, using exclusive transactions.
|
||||
|
||||
@param block The code to be run on the queue of `FMDatabaseQueue`
|
||||
*/
|
||||
|
||||
- (void)inExclusiveTransaction:(__attribute__((noescape)) void (^)(FMDatabase *db, BOOL *rollback))block;
|
||||
|
||||
/** Synchronously perform database operations on queue, using immediate transactions.
|
||||
|
||||
@param block The code to be run on the queue of `FMDatabaseQueue`
|
||||
|
@ -127,7 +127,6 @@ static const void * const kDispatchQueueSpecificKey = &kDispatchQueueSpecificKey
|
||||
return [self initWithPath:nil];
|
||||
}
|
||||
|
||||
|
||||
- (void)dealloc {
|
||||
FMDBRelease(_db);
|
||||
FMDBRelease(_path);
|
||||
@ -189,6 +188,7 @@ static const void * const kDispatchQueueSpecificKey = &kDispatchQueueSpecificKey
|
||||
dispatch_sync(_queue, ^() {
|
||||
|
||||
FMDatabase *db = [self database];
|
||||
|
||||
block(db);
|
||||
|
||||
if ([db hasOpenResultSets]) {
|
||||
@ -238,11 +238,15 @@ static const void * const kDispatchQueueSpecificKey = &kDispatchQueueSpecificKey
|
||||
FMDBRelease(self);
|
||||
}
|
||||
|
||||
- (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];
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.7.3</string>
|
||||
<string>2.7.4</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
Loading…
Reference in New Issue
Block a user