diff options
author | Robert Ryan <robert.ryan@mindspring.com> | 2020-05-06 19:48:18 +0300 |
---|---|---|
committer | Robert Ryan <robert.ryan@mindspring.com> | 2020-05-06 20:09:11 +0300 |
commit | 4009be0a6f9de7cc6d6a59cf8ff820269015a828 (patch) | |
tree | 5d0b3b0a843c9c1732a709ab47560dafbc850a2b /Tests | |
parent | daa532443f7ef8b441a8c886c80f113ac433ca92 (diff) |
Allow rebinding of values for prepared queries
Diffstat (limited to 'Tests')
-rw-r--r-- | Tests/FMDatabaseTests.m | 186 |
1 files changed, 185 insertions, 1 deletions
diff --git a/Tests/FMDatabaseTests.m b/Tests/FMDatabaseTests.m index b9e1f8a..8ca2df5 100644 --- a/Tests/FMDatabaseTests.m +++ b/Tests/FMDatabaseTests.m @@ -1124,7 +1124,12 @@ } - (void)testVersionNumber { - XCTAssertEqual([FMDatabase FMDBVersion], 0x0276); // this is going to break everytime we bump it. + XCTAssertEqual([FMDatabase FMDBVersion], 0x0277); // this is going to break everytime we bump it. +} + +- (void)testUserVersion { + NSComparisonResult result = [[FMDatabase FMDBUserVersion] compare:@"2.7.7" options:NSNumericSearch]; + XCTAssertEqual(result, NSOrderedSame); } - (void)testVersionStringAboveRequired { @@ -1551,4 +1556,183 @@ [manager removeItemAtURL:fileURL2 error:nil]; } +// These three utility methods used by `testTransient`, to illustrate dangers of SQLITE_STATIC + +- (BOOL)utility1ForTestTransient:(FMDatabase *)db withValue:(long)value { + @autoreleasepool { + NSString *string = [[NSString alloc] initWithFormat:@"value %@", @(value)]; + return [db executeUpdate:@"INSERT INTO foo (bar) VALUES (?)", [string dataUsingEncoding:NSUTF8StringEncoding]]; + } +} + +- (FMResultSet *)utility2ForTestTransient:(FMDatabase *)db withValue:(long)value { + @autoreleasepool { + NSString *string = [[NSString alloc] initWithFormat:@"value %@", @(value)]; + return [db executeQuery:@"SELECT * FROM foo WHERE bar = ?", [string dataUsingEncoding:NSUTF8StringEncoding]]; + } +} + +- (BOOL)utility3ForTestTransient:(FMResultSet *)rs withValue:(long)value { + @autoreleasepool { + NSString *string = [[NSString alloc] initWithFormat:@"xxxxx %@", @(value + 1)]; + XCTAssertEqualObjects(string, @"xxxxx 43"); // Just to ensure the above isn't optimized out + return [rs next]; + } +} + +- (void)testTransient { + NSURL *tempURL = [NSURL fileURLWithPath:NSTemporaryDirectory()]; + NSURL *fileURL = [tempURL URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]]; + NSFileManager *manager = [NSFileManager defaultManager]; + + // ok, first create one database + + FMDatabase *db = [FMDatabase databaseWithURL:fileURL]; + BOOL success = [db open]; + XCTAssert(success, @"Database not created correctly for purposes of test"); + success = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS foo (bar BLOB)"]; + XCTAssert(success, @"Table created correctly for purposes of test"); + + long value = 42; + success = [self utility1ForTestTransient:db withValue:value]; + XCTAssert(success, @"INSERT failed"); + + FMResultSet *rs = [self utility2ForTestTransient:db withValue:value]; + XCTAssert(rs, @"Creating SELECT failed"); + + // the following is the key test, namely if FMDB uses SQLITE_STATIC, the following may fail, but SQLITE_TRANSIENT ensures it will succeed + + success = [self utility3ForTestTransient:rs withValue:value]; + XCTAssert(success, @"Performing SELECT failed"); + + // let's clean up + + [rs close]; + [db close]; + [manager removeItemAtURL:fileURL error:nil]; +} + +- (void)testBindFailure { + NSURL *tempURL = [NSURL fileURLWithPath:NSTemporaryDirectory()]; + NSURL *fileURL = [tempURL URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]]; + NSFileManager *manager = [NSFileManager defaultManager]; + + // ok, first create one database + + FMDatabase *db = [FMDatabase databaseWithURL:fileURL]; + BOOL success = [db open]; + XCTAssert(success, @"Database not created correctly for purposes of test"); + success = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS foo (bar BLOB)"]; + XCTAssert(success, @"Table created correctly for purposes of test"); + + NSUInteger limit = (NSUInteger)[db limitFor:SQLITE_LIMIT_LENGTH value:-1] + 1; + NSLog(@"%lu", (unsigned long)limit); + NSData *data = [NSMutableData dataWithLength:limit]; + success = [db executeUpdate:@"INSERT INTO foo (bar) VALUES (?)", data]; + XCTAssertFalse(success, @"Table created correctly for purposes of test"); + + // let's clean up + + [db close]; + [manager removeItemAtURL:fileURL error:nil]; +} + +- (void)testRebindingWithDictionary { + NSURL *tempURL = [NSURL fileURLWithPath:NSTemporaryDirectory()]; + NSURL *fileURL = [tempURL URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]]; + NSFileManager *manager = [NSFileManager defaultManager]; + [manager removeItemAtURL:fileURL error:nil]; + + // ok, first create one database + + FMDatabase *db = [FMDatabase databaseWithURL:fileURL]; + BOOL success = [db open]; + XCTAssert(success, @"Database not created correctly for purposes of test"); + success = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS foo (id INTEGER PRIMARY KEY, bar TEXT)"]; + XCTAssert(success, @"Table created correctly for purposes of test"); + + FMResultSet *rs = [db prepare:@"INSERT INTO foo (bar) VALUES (:bar)"]; + XCTAssert(rs, @"INSERT statement not prepared %@", [db lastErrorMessage]); + + NSString *value1 = @"foo"; + XCTAssert([rs bindWithDictionary:@{@"bar": value1}], @"Unable to bind"); + XCTAssert([rs step], @"Performing query failed"); + + NSString *value2 = @"bar"; + XCTAssert([rs bindWithDictionary:@{@"bar": value2}], @"Unable to bind"); + XCTAssert([rs step], @"Performing query failed"); + + XCTAssert([rs bindWithDictionary:@{@"bar": value2}], @"Unable to bind"); + XCTAssert([rs step], @"Performing query failed"); + + [rs close]; + + rs = [db prepare:@"SELECT bar FROM foo WHERE bar = :bar"]; + XCTAssert([rs bindWithDictionary:@{@"bar": value1}], @"Unable to bind"); + XCTAssert([rs next], @"No record found"); + XCTAssertEqualObjects([rs stringForColumnIndex:0], value1); + XCTAssertFalse([rs next], @"There should have been only one record"); + + XCTAssert([rs bindWithDictionary:@{@"bar": value2}], @"Unable to bind"); + XCTAssert([rs next], @"No record found"); + XCTAssertEqualObjects([rs stringForColumnIndex:0], value2); + XCTAssert([rs next], @"No record found"); + XCTAssertEqualObjects([rs stringForColumnIndex:0], value2); + XCTAssertFalse([rs next], @"There should have been only two records"); + + // let's clean up + + [rs close]; + [db close]; + [manager removeItemAtURL:fileURL error:nil]; +} + +- (void)testRebindingWithArray { + NSURL *tempURL = [NSURL fileURLWithPath:NSTemporaryDirectory()]; + NSURL *fileURL = [tempURL URLByAppendingPathComponent:[[NSUUID UUID] UUIDString]]; + NSFileManager *manager = [NSFileManager defaultManager]; + + // ok, first create one database + + FMDatabase *db = [FMDatabase databaseWithURL:fileURL]; + BOOL success = [db open]; + XCTAssert(success, @"Database not created correctly for purposes of test"); + success = [db executeUpdate:@"CREATE TABLE IF NOT EXISTS foo (id INTEGER PRIMARY KEY, bar TEXT)"]; + XCTAssert(success, @"Table created correctly for purposes of test"); + + FMResultSet *rs = [db prepare:@"INSERT INTO foo (bar) VALUES (?)"]; + XCTAssert(rs, @"INSERT statement not prepared %@", [db lastErrorMessage]); + + NSString *value1 = @"foo"; + XCTAssert([rs bindWithArray:@[value1]], @"Unable to bind"); + XCTAssert([rs step], @"Performing INSERT 1 failed"); + + NSString *value2 = @"bar"; + XCTAssert([rs bindWithArray:@[value2]], @"Unable to bind"); + XCTAssert([rs step], @"Performing INSERT 2 failed"); + XCTAssert([rs bindWithArray:@[value2]], @"Unable to bind"); + XCTAssert([rs step], @"Performing INSERT 2 failed"); + + [rs close]; + + rs = [db prepare:@"SELECT bar FROM foo WHERE bar = ?"]; + XCTAssert([rs bindWithArray:@[value1]], @"Unable to bind"); + XCTAssert([rs next], @"No record found"); + XCTAssertEqualObjects([rs stringForColumnIndex:0], value1); + XCTAssertFalse([rs next], @"There should have been only one record"); + + XCTAssert([rs bindWithArray:@[value2]], @"Unable to bind"); + XCTAssert([rs next], @"No record found"); + XCTAssertEqualObjects([rs stringForColumnIndex:0], value2); + XCTAssert([rs next], @"No record found"); + XCTAssertEqualObjects([rs stringForColumnIndex:0], value2); + XCTAssertFalse([rs next], @"There should have been only two records"); + + // let's clean up + + [rs close]; + [db close]; + [manager removeItemAtURL:fileURL error:nil]; +} + @end |