...
|
...
|
@@ -2,6 +2,8 @@ |
|
|
#import "FMDatabase.h"
|
|
|
#import "FMDatabaseAdditions.h"
|
|
|
|
|
|
#define FMDBQuickCheck(SomeBool) { if (!(SomeBool)) { NSLog(@"Failure on line %d", __LINE__); return 123; } }
|
|
|
|
|
|
int main (int argc, const char * argv[]) {
|
|
|
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
|
|
|
...
|
...
|
@@ -11,7 +13,7 @@ int main (int argc, const char * argv[]) { |
|
|
|
|
|
FMDatabase* db = [FMDatabase databaseWithPath:@"/tmp/tmp.db"];
|
|
|
if (![db open]) {
|
|
|
RMLog(@"Could not open db.");
|
|
|
NSLog(@"Could not open db.");
|
|
|
[pool release];
|
|
|
return 0;
|
|
|
}
|
...
|
...
|
@@ -21,8 +23,11 @@ int main (int argc, const char * argv[]) { |
|
|
|
|
|
// create a bad statement, just to test the error code.
|
|
|
[db executeUpdate:@"blah blah blah"];
|
|
|
|
|
|
FMDBQuickCheck([db hadError]);
|
|
|
|
|
|
if ([db hadError]) {
|
|
|
RMLog(@"Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);
|
|
|
NSLog(@"Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);
|
|
|
}
|
|
|
|
|
|
// but of course, I don't bother checking the error codes below.
|
...
|
...
|
@@ -65,7 +70,7 @@ int main (int argc, const char * argv[]) { |
|
|
FMResultSet *rs = [db executeQuery:@"select rowid,* from test where a = ?", @"hi'"];
|
|
|
while ([rs next]) {
|
|
|
// just print out what we've got in a number of formats.
|
|
|
RMLog(@"%d %@ %@ %@ %@ %f %f",
|
|
|
NSLog(@"%d %@ %@ %@ %@ %f %f",
|
|
|
[rs intForColumn:@"c"],
|
|
|
[rs stringForColumn:@"b"],
|
|
|
[rs stringForColumn:@"a"],
|
...
|
...
|
@@ -73,6 +78,14 @@ int main (int argc, const char * argv[]) { |
|
|
[rs dateForColumn:@"d"],
|
|
|
[rs doubleForColumn:@"d"],
|
|
|
[rs doubleForColumn:@"e"]);
|
|
|
|
|
|
|
|
|
if (!([[rs columnNameForIndex:0] isEqualToString:@"rowid"] &&
|
|
|
[[rs columnNameForIndex:1] isEqualToString:@"a"])
|
|
|
) {
|
|
|
NSLog(@"WHOA THERE BUDDY, columnNameForIndex ISN'T WORKING!");
|
|
|
return 7;
|
|
|
}
|
|
|
}
|
|
|
// close the result set.
|
|
|
// it'll also close when it's dealloc'd, but we're closing the database before
|
...
|
...
|
@@ -84,32 +97,32 @@ int main (int argc, const char * argv[]) { |
|
|
[db executeUpdate:@"create table blobTable (a text, b blob)"];
|
|
|
|
|
|
// let's read in an image from safari's app bundle.
|
|
|
NSData *d = [NSData dataWithContentsOfFile:@"/Applications/Safari.app/Contents/Resources/compass.icns"];
|
|
|
if (d) {
|
|
|
[db executeUpdate:@"insert into blobTable (a, b) values (?,?)", @"safari's compass", d];
|
|
|
NSData *safariCompass = [NSData dataWithContentsOfFile:@"/Applications/Safari.app/Contents/Resources/compass.icns"];
|
|
|
if (safariCompass) {
|
|
|
[db executeUpdate:@"insert into blobTable (a, b) values (?,?)", @"safari's compass", safariCompass];
|
|
|
|
|
|
rs = [db executeQuery:@"select b from blobTable where a = ?", @"safari's compass"];
|
|
|
if ([rs next]) {
|
|
|
d = [rs dataForColumn:@"b"];
|
|
|
[d writeToFile:@"/tmp/compass.icns" atomically:NO];
|
|
|
safariCompass = [rs dataForColumn:@"b"];
|
|
|
[safariCompass writeToFile:@"/tmp/compass.icns" atomically:NO];
|
|
|
|
|
|
// let's look at our fancy image that we just wrote out..
|
|
|
system("/usr/bin/open /tmp/compass.icns");
|
|
|
|
|
|
// ye shall read the header for this function, or suffer the consequences.
|
|
|
d = [rs dataNoCopyForColumn:@"b"];
|
|
|
[d writeToFile:@"/tmp/compass_data_no_copy.icns" atomically:NO];
|
|
|
safariCompass = [rs dataNoCopyForColumn:@"b"];
|
|
|
[safariCompass writeToFile:@"/tmp/compass_data_no_copy.icns" atomically:NO];
|
|
|
system("/usr/bin/open /tmp/compass_data_no_copy.icns");
|
|
|
}
|
|
|
else {
|
|
|
RMLog(@"Could not select image.");
|
|
|
NSLog(@"Could not select image.");
|
|
|
}
|
|
|
|
|
|
[rs close];
|
|
|
|
|
|
}
|
|
|
else {
|
|
|
RMLog(@"Can't find compass image..");
|
|
|
NSLog(@"Can't find compass image..");
|
|
|
}
|
|
|
|
|
|
|
...
|
...
|
@@ -118,7 +131,7 @@ int main (int argc, const char * argv[]) { |
|
|
[db executeUpdate:@"insert into t1 values (?)", [NSNumber numberWithInt:5]];
|
|
|
int a = [db intForQuery:@"select a from t1 where a = ?", [NSNumber numberWithInt:5]];
|
|
|
if (a != 5) {
|
|
|
RMLog(@"intForQuery didn't work (a != 5)");
|
|
|
NSLog(@"intForQuery didn't work (a != 5)");
|
|
|
}
|
|
|
|
|
|
// test the busy rety timeout schtuff.
|
...
|
...
|
@@ -131,16 +144,16 @@ int main (int argc, const char * argv[]) { |
|
|
rs = [newDb executeQuery:@"select rowid,* from test where a = ?", @"hi'"];
|
|
|
[rs next]; // just grab one... which will keep the db locked.
|
|
|
|
|
|
RMLog(@"Testing the busy timeout");
|
|
|
NSLog(@"Testing the busy timeout");
|
|
|
|
|
|
BOOL success = [db executeUpdate:@"insert into t1 values (5)"];
|
|
|
|
|
|
if (success) {
|
|
|
RMLog(@"Whoa- the database didn't stay locked!");
|
|
|
NSLog(@"Whoa- the database didn't stay locked!");
|
|
|
return 7;
|
|
|
}
|
|
|
else {
|
|
|
RMLog(@"Hurray, our timeout worked");
|
|
|
NSLog(@"Hurray, our timeout worked");
|
|
|
}
|
|
|
|
|
|
[rs close];
|
...
|
...
|
@@ -148,11 +161,11 @@ int main (int argc, const char * argv[]) { |
|
|
|
|
|
success = [db executeUpdate:@"insert into t1 values (5)"];
|
|
|
if (!success) {
|
|
|
RMLog(@"Whoa- the database shouldn't be locked!");
|
|
|
NSLog(@"Whoa- the database shouldn't be locked!");
|
|
|
return 8;
|
|
|
}
|
|
|
else {
|
|
|
RMLog(@"Hurray, we can insert again!");
|
|
|
NSLog(@"Hurray, we can insert again!");
|
|
|
}
|
|
|
|
|
|
|
...
|
...
|
@@ -161,7 +174,7 @@ int main (int argc, const char * argv[]) { |
|
|
[db executeUpdate:@"create table t2 (a integer, b integer)"];
|
|
|
|
|
|
if (![db executeUpdate:@"insert into t2 values (?, ?)", nil, [NSNumber numberWithInt:5]]) {
|
|
|
RMLog(@"UH OH, can't insert a nil value for some reason...");
|
|
|
NSLog(@"UH OH, can't insert a nil value for some reason...");
|
|
|
}
|
|
|
|
|
|
|
...
|
...
|
@@ -173,17 +186,17 @@ int main (int argc, const char * argv[]) { |
|
|
NSString *b = [rs stringForColumnIndex:1];
|
|
|
|
|
|
if (a != nil) {
|
|
|
RMLog(@"%s:%d", __FUNCTION__, __LINE__);
|
|
|
RMLog(@"OH OH, PROBLEMO!");
|
|
|
NSLog(@"%s:%d", __FUNCTION__, __LINE__);
|
|
|
NSLog(@"OH OH, PROBLEMO!");
|
|
|
return 10;
|
|
|
}
|
|
|
else {
|
|
|
RMLog(@"YAY, NULL VALUES");
|
|
|
NSLog(@"YAY, NULL VALUES");
|
|
|
}
|
|
|
|
|
|
if (![b isEqualToString:@"5"]) {
|
|
|
RMLog(@"%s:%d", __FUNCTION__, __LINE__);
|
|
|
RMLog(@"OH OH, PROBLEMO!");
|
|
|
NSLog(@"%s:%d", __FUNCTION__, __LINE__);
|
|
|
NSLog(@"OH OH, PROBLEMO!");
|
|
|
return 10;
|
|
|
}
|
|
|
}
|
...
|
...
|
@@ -225,7 +238,7 @@ int main (int argc, const char * argv[]) { |
|
|
[rs2 next];
|
|
|
|
|
|
if ([rs2 intForColumnIndex:0] != newVal) {
|
|
|
RMLog(@"Oh crap, our update didn't work out!");
|
|
|
NSLog(@"Oh crap, our update didn't work out!");
|
|
|
return 9;
|
|
|
}
|
|
|
|
...
|
...
|
@@ -247,19 +260,222 @@ int main (int argc, const char * argv[]) { |
|
|
NSString *b = [rs stringForColumnIndex:1];
|
|
|
|
|
|
if (!b) {
|
|
|
RMLog(@"Oh crap, the nil / null inserts didn't work!");
|
|
|
NSLog(@"Oh crap, the nil / null inserts didn't work!");
|
|
|
return 10;
|
|
|
}
|
|
|
|
|
|
if (a) {
|
|
|
RMLog(@"Oh crap, the nil / null inserts didn't work (son of error message)!");
|
|
|
NSLog(@"Oh crap, the nil / null inserts didn't work (son of error message)!");
|
|
|
return 11;
|
|
|
}
|
|
|
else {
|
|
|
RMLog(@"HURRAH FOR NSNULL (and nil)!");
|
|
|
NSLog(@"HURRAH FOR NSNULL (and nil)!");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// null dates
|
|
|
|
|
|
NSDate *date = [NSDate date];
|
|
|
[db executeUpdate:@"create table datetest (a double, b double, c double)"];
|
|
|
[db executeUpdate:@"insert into datetest (a, b, c) values (?, ?, 0)" , [NSNull null], date];
|
|
|
|
|
|
rs = [db executeQuery:@"select * from datetest"];
|
|
|
|
|
|
while ([rs next]) {
|
|
|
|
|
|
NSDate *a = [rs dateForColumnIndex:0];
|
|
|
NSDate *b = [rs dateForColumnIndex:1];
|
|
|
NSDate *c = [rs dateForColumnIndex:2];
|
|
|
|
|
|
if (a) {
|
|
|
NSLog(@"Oh crap, the null date insert didn't work!");
|
|
|
return 12;
|
|
|
}
|
|
|
|
|
|
if (!c) {
|
|
|
NSLog(@"Oh crap, the 0 date insert didn't work!");
|
|
|
return 12;
|
|
|
}
|
|
|
|
|
|
NSTimeInterval dti = fabs([b timeIntervalSinceDate:date]);
|
|
|
|
|
|
if (floor(dti) > 0.0) {
|
|
|
NSLog(@"Date matches didn't really happen... time difference of %f", dti);
|
|
|
return 13;
|
|
|
}
|
|
|
|
|
|
|
|
|
dti = fabs([c timeIntervalSinceDate:[NSDate dateWithTimeIntervalSince1970:0]]);
|
|
|
|
|
|
if (floor(dti) > 0.0) {
|
|
|
NSLog(@"Date matches didn't really happen... time difference of %f", dti);
|
|
|
return 13;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
NSDate *foo = [db dateForQuery:@"select b from datetest where c = 0"];
|
|
|
assert(foo);
|
|
|
NSTimeInterval dti = fabs([foo timeIntervalSinceDate:date]);
|
|
|
if (floor(dti) > 0.0) {
|
|
|
NSLog(@"Date matches didn't really happen... time difference of %f", dti);
|
|
|
return 14;
|
|
|
}
|
|
|
|
|
|
[db executeUpdate:@"create table nulltest2 (s text, d data, i integer, f double, b integer)"];
|
|
|
|
|
|
[db executeUpdate:@"insert into nulltest2 (s, d, i, f, b) values (?, ?, ?, ?, ?)" , @"Hi", safariCompass, [NSNumber numberWithInt:12], [NSNumber numberWithFloat:4.4], [NSNumber numberWithBool:YES]];
|
|
|
[db executeUpdate:@"insert into nulltest2 (s, d, i, f, b) values (?, ?, ?, ?, ?)" , nil, nil, nil, nil, [NSNull null]];
|
|
|
|
|
|
rs = [db executeQuery:@"select * from nulltest2"];
|
|
|
|
|
|
while ([rs next]) {
|
|
|
|
|
|
int i = [rs intForColumnIndex:2];
|
|
|
|
|
|
if (i == 12) {
|
|
|
// it's the first row we inserted.
|
|
|
FMDBQuickCheck(![rs columnIndexIsNull:0]);
|
|
|
FMDBQuickCheck(![rs columnIndexIsNull:1]);
|
|
|
FMDBQuickCheck(![rs columnIndexIsNull:2]);
|
|
|
FMDBQuickCheck(![rs columnIndexIsNull:3]);
|
|
|
FMDBQuickCheck(![rs columnIndexIsNull:4]);
|
|
|
FMDBQuickCheck( [rs columnIndexIsNull:5]);
|
|
|
|
|
|
FMDBQuickCheck([[rs dataForColumn:@"d"] length] == [safariCompass length]);
|
|
|
FMDBQuickCheck(![rs dataForColumn:@"notthere"]);
|
|
|
FMDBQuickCheck(![rs stringForColumnIndex:-2]);
|
|
|
FMDBQuickCheck([rs boolForColumnIndex:4]);
|
|
|
FMDBQuickCheck([rs boolForColumn:@"b"]);
|
|
|
|
|
|
FMDBQuickCheck(fabs(4.4 - [rs doubleForColumn:@"f"]) < 0.0000001);
|
|
|
|
|
|
FMDBQuickCheck(12 == [rs intForColumn:@"i"]);
|
|
|
FMDBQuickCheck(12 == [rs intForColumnIndex:2]);
|
|
|
|
|
|
FMDBQuickCheck(0 == [rs intForColumnIndex:12]); // there is no 12
|
|
|
FMDBQuickCheck(0 == [rs intForColumn:@"notthere"]);
|
|
|
|
|
|
FMDBQuickCheck(12 == [rs longForColumn:@"i"]);
|
|
|
FMDBQuickCheck(12 == [rs longLongIntForColumn:@"i"]);
|
|
|
}
|
|
|
else {
|
|
|
// let's test various null things.
|
|
|
|
|
|
FMDBQuickCheck([rs columnIndexIsNull:0]);
|
|
|
FMDBQuickCheck([rs columnIndexIsNull:1]);
|
|
|
FMDBQuickCheck([rs columnIndexIsNull:2]);
|
|
|
FMDBQuickCheck([rs columnIndexIsNull:3]);
|
|
|
FMDBQuickCheck([rs columnIndexIsNull:4]);
|
|
|
FMDBQuickCheck([rs columnIndexIsNull:5]);
|
|
|
|
|
|
|
|
|
FMDBQuickCheck(![rs dataForColumn:@"d"]);
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
[db executeUpdate:@"create table testOneHundredTwelvePointTwo (a text, b integer)"];
|
|
|
[db executeUpdate:@"insert into testOneHundredTwelvePointTwo values (?, ?)" withArgumentsInArray:[NSArray arrayWithObjects:@"one", [NSNumber numberWithInteger:2], nil]];
|
|
|
[db executeUpdate:@"insert into testOneHundredTwelvePointTwo values (?, ?)" withArgumentsInArray:[NSArray arrayWithObjects:@"one", [NSNumber numberWithInteger:3], nil]];
|
|
|
|
|
|
|
|
|
rs = [db executeQuery:@"select * from testOneHundredTwelvePointTwo where b > ?" withArgumentsInArray:[NSArray arrayWithObject:[NSNumber numberWithInteger:1]]];
|
|
|
|
|
|
FMDBQuickCheck([rs next]);
|
|
|
|
|
|
FMDBQuickCheck([rs hasAnotherRow]);
|
|
|
FMDBQuickCheck(![db hadError]);
|
|
|
|
|
|
FMDBQuickCheck([[rs stringForColumnIndex:0] isEqualToString:@"one"]);
|
|
|
FMDBQuickCheck([rs intForColumnIndex:1] == 2);
|
|
|
|
|
|
FMDBQuickCheck([rs next]);
|
|
|
|
|
|
FMDBQuickCheck([rs intForColumnIndex:1] == 3);
|
|
|
|
|
|
FMDBQuickCheck(![rs next]);
|
|
|
FMDBQuickCheck(![rs hasAnotherRow]);
|
|
|
|
|
|
}
|
|
|
|
|
|
{
|
|
|
|
|
|
FMDBQuickCheck([db executeUpdate:@"create table t4 (a text, b text)"]);
|
|
|
FMDBQuickCheck(([db executeUpdate:@"insert into t4 (a, b) values (?, ?)", @"one", @"two"]));
|
|
|
|
|
|
rs = [db executeQuery:@"select t4.a as 't4.a', t4.b from t4;"];
|
|
|
|
|
|
FMDBQuickCheck((rs != nil));
|
|
|
|
|
|
[rs next];
|
|
|
|
|
|
FMDBQuickCheck([[rs stringForColumn:@"t4.a"] isEqualToString:@"one"]);
|
|
|
FMDBQuickCheck([[rs stringForColumn:@"b"] isEqualToString:@"two"]);
|
|
|
|
|
|
FMDBQuickCheck(strcmp((const char*)[rs UTF8StringForColumnName:@"b"], "two") == 0);
|
|
|
|
|
|
[rs close];
|
|
|
|
|
|
// let's try these again, with the withArgumentsInArray: variation
|
|
|
FMDBQuickCheck([db executeUpdate:@"drop table t4;" withArgumentsInArray:[NSArray array]]);
|
|
|
FMDBQuickCheck([db executeUpdate:@"create table t4 (a text, b text)" withArgumentsInArray:[NSArray array]]);
|
|
|
FMDBQuickCheck(([db executeUpdate:@"insert into t4 (a, b) values (?, ?)" withArgumentsInArray:[NSArray arrayWithObjects:@"one", @"two", nil]]));
|
|
|
|
|
|
rs = [db executeQuery:@"select t4.a as 't4.a', t4.b from t4;" withArgumentsInArray:[NSArray array]];
|
|
|
|
|
|
FMDBQuickCheck((rs != nil));
|
|
|
|
|
|
[rs next];
|
|
|
|
|
|
FMDBQuickCheck([[rs stringForColumn:@"t4.a"] isEqualToString:@"one"]);
|
|
|
FMDBQuickCheck([[rs stringForColumn:@"b"] isEqualToString:@"two"]);
|
|
|
|
|
|
FMDBQuickCheck(strcmp((const char*)[rs UTF8StringForColumnName:@"b"], "two") == 0);
|
|
|
|
|
|
[rs close];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
FMDBQuickCheck([db tableExists:@"t4"]);
|
|
|
FMDBQuickCheck(![db tableExists:@"thisdoesntexist"]);
|
|
|
|
|
|
rs = [db getSchema];
|
|
|
while ([rs next]) {
|
|
|
FMDBQuickCheck([[rs stringForColumn:@"type"] isEqualToString:@"table"]);
|
|
|
}
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// just for fun.
|
|
|
rs = [db executeQuery:@"PRAGMA database_list"];
|
|
|
while ([rs next]) {
|
|
|
NSString *file = [rs stringForColumn:@"file"];
|
|
|
NSLog(@"database_list: %@", file);
|
|
|
}
|
|
|
|
|
|
|
|
|
// print out some stats if we are using cached statements.
|
|
|
if ([db shouldCacheStatements]) {
|
|
|
|
...
|
...
|
@@ -267,10 +483,10 @@ int main (int argc, const char * argv[]) { |
|
|
FMStatement *statement;
|
|
|
|
|
|
while ((statement = [e nextObject])) {
|
|
|
RMLog(@"%@", statement);
|
|
|
NSLog(@"%@", statement);
|
|
|
}
|
|
|
}
|
|
|
RMLog(@"That was version %@ of sqlite", [FMDatabase sqliteLibVersion]);
|
|
|
NSLog(@"That was version %@ of sqlite", [FMDatabase sqliteLibVersion]);
|
|
|
|
|
|
|
|
|
[db close];
|
...
|
...
|
|