FMDB测试用代码

#import <Foundation/Foundation.h>

#import "FMDatabase.h"

#import "FMDatabaseAdditions.h"

#import "FMDatabasePool.h"

#import "FMDatabaseQueue.h"


#define FMDBQuickCheck(SomeBool) { if (!(SomeBool)) { NSLog(@"Failure on line %d", __LINE__); abort(); } }


void testPool(NSString *dbPath);

void FMDBReportABugFunction();


int main (int argc, const char * argv[]) {

    

    @autoreleasepool {

        

        FMDBReportABugFunction();

        

        NSString *dbPath = @"/tmp/tmp.db";

        

        // delete the old db.

        //删除老的tmp.db

        NSFileManager *fileManager = [NSFileManager defaultManager];

        [fileManager removeItemAtPath:dbPath error:nil];

        

        FMDatabase *db = [FMDatabase databaseWithPath:dbPath];

        //看sqlite这个库是否是编译为threadsafe版本

        NSLog(@"Is SQLite compiled with it's thread safe options turned on? %@!", [FMDatabase isSQLiteThreadSafe] ? @"Yes" : @"No");

        

        {

            // -------------------------------------------------------------------------------

            // Un-opened database check.

            //查询数据前对于数据库文件是否存在的提示

            FMDBQuickCheck([db executeQuery:@"select * from table"] == nil);

            NSLog(@"%d: %@", [db lastErrorCode], [db lastErrorMessage]);

        }

        

        //对于open方法的检测。

        if (![db open]) {

            NSLog(@"Could not open db.");

            

            return 0;

        }

        

        // kind of experimentalish.

        //有经验的做法,都把这个值设置为YES

        [db setShouldCacheStatements:YES];

        

        // create a bad statement, just to test the error code.

        //执行一个不合法的语句,验证[db hadError]是否正确表示。

        [db executeUpdate:@"blah blah blah"];

        

        FMDBQuickCheck([db hadError]);

        

        if ([db hadError]) {

            NSLog(@"Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);

        }

        

        //执行一个不合法的语句,并提示错误,通过NSError传递错误信息

        NSError *err = 0x00;

        FMDBQuickCheck(![db update:@"blah blah blah" withErrorAndBindings:&err]);

        FMDBQuickCheck(err != nil);

        FMDBQuickCheck([err code] == SQLITE_ERROR);

        NSLog(@"err: '%@'", err);

        

        // empty strings should still return a value.

        //空字符串不为null

        FMDBQuickCheck(([db boolForQuery:@"SELECT ? not null", @""]));

        

        // same with empty bits o' mutable data

        //初始化的NSMutableData不为null

        FMDBQuickCheck(([db boolForQuery:@"SELECT ? not null", [NSMutableData data]]));

        

        // same with empty bits o' data

        //初始化的NSData不为null

        FMDBQuickCheck(([db boolForQuery:@"SELECT ? not null", [NSData data]]));

        

        // how do we do pragmas?  Like so:

        //预编译命令的执行,像 PRAGMA journal_mode=delete 该命令启用后,事务回滚日志不记录

        FMResultSet *ps = [db executeQuery:@"PRAGMA journal_mode=delete"];

        FMDBQuickCheck(![db hadError]);

        FMDBQuickCheck(ps);

        FMDBQuickCheck([ps next]);

        [ps close];

        

        // oh, but some pragmas require updates?

        [db executeUpdate:@"PRAGMA page_size=2048"];

        FMDBQuickCheck(![db hadError]);

        

        // what about a vacuum?

        //整理数据库碎片,通常这个命令执行后数据库文件会变小

        [db executeUpdate:@"vacuum"];

        FMDBQuickCheck(![db hadError]);

        

        // but of course, I don't bother checking the error codes below.

        // Bad programmer, no cookie.

        

        [db executeUpdate:@"create table test (a text, b text, c integer, d double, e double)"];

        

        //hi'这个字符串居然被录入进去了

        [db beginTransaction];

        int i = 0;

        while (i++ < 20) {

            [db executeUpdate:@"insert into test (a, b, c, d, e) values (?, ?, ?, ?, ?)" ,

             @"hi'", // look!  I put in a ', and I'm not escaping it!

             [NSString stringWithFormat:@"number %d", i],

             [NSNumber numberWithInt:i],

             [NSDate date],

             [NSNumber numberWithFloat:2.2f]];

        }

        [db commit];

        

        

        

        // do it again, just because

        [db beginTransaction];

        i = 0;

        while (i++ < 20) {

            [db executeUpdate:@"insert into test (a, b, c, d, e) values (?, ?, ?, ?, ?)" ,

             @"hi again'", // look!  I put in a ', and I'm not escaping it!

             [NSString stringWithFormat:@"number %d", i],

             [NSNumber numberWithInt:i],

             [NSDate date],

             [NSNumber numberWithFloat:2.2f]];

        }

        [db commit];

        

        

        

        

        //用FMResultSet查询数据集。

        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.

            NSLog(@"%d %@ %@ %@ %@ %f %f",

                  [rs intForColumn:@"c"],

                  [rs stringForColumn:@"b"],

                  [rs stringForColumn:@"a"],

                  [rs stringForColumn:@"rowid"],

                  [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

        // the autorelease pool closes, so sqlite will complain about it.

        //这儿关闭下FMResultSet

        [rs close];

        

        FMDBQuickCheck(![db hasOpenResultSets]);

        

        

        //再tm查一次,看rs[0]这玩意能用波。

        rs = [db executeQuery:@"select rowid, a, b, c from test"];

        while ([rs next]) {

            

            FMDBQuickCheck([rs[0] isEqualTo:rs[@"rowid"]]);

            FMDBQuickCheck([rs[1] isEqualTo:rs[@"a"]]);

            FMDBQuickCheck([rs[2] isEqualTo:rs[@"b"]]);

            FMDBQuickCheck([rs[3] isEqualTo:rs[@"c"]]);

        }

        [rs close];

        

        

        

        

        

        [db executeUpdate:@"create table ull (a integer)"];

        

        [db executeUpdate:@"insert into ull (a) values (?)" , [NSNumber numberWithUnsignedLongLong:ULLONG_MAX]];

        //64位机器,最大整数是18446744073709551615 ,20位 1800吉兆亿,此段发现这么大的数也能存哦,sqlite里面显示是-1

        NSLog(@"%@", [NSNumber numberWithUnsignedLongLong:ULLONG_MAX]);

        rs = [db executeQuery:@"select  a from ull"];

        while ([rs next]) {

            unsigned long long a = [rs unsignedLongLongIntForColumnIndex:0];

            unsigned long long b = [rs unsignedLongLongIntForColumn:@"a"];

            

            FMDBQuickCheck(a == ULLONG_MAX);

            FMDBQuickCheck(b == ULLONG_MAX);

        }

        

        

        // check case sensitive result dictionary.

        [db executeUpdate:@"create table cs (aRowName integer, bRowName text)"];

        FMDBQuickCheck(![db hadError]);

        [db executeUpdate:@"insert into cs (aRowName, bRowName) values (?, ?)" , [NSNumber numberWithBool:1], @"hello"];

        FMDBQuickCheck(![db hadError]);

        

        rs = [db executeQuery:@"select * from cs"];

        while ([rs next]) {

            //把一个[rs resultDictionary]放到Dictionary里面的方法,好棒。

            NSDictionary *d = [rs resultDictionary];

            

            FMDBQuickCheck([d objectForKey:@"aRowName"]);

            FMDBQuickCheck(![d objectForKey:@"arowname"]);

            FMDBQuickCheck([d objectForKey:@"bRowName"]);

            FMDBQuickCheck(![d objectForKey:@"browname"]);

        }

        

        

        // check funky table names + getTableSchema

        //getTableSchema这个方法不知道有毛意义。

        [db executeUpdate:@"create table '234 fds' (foo text)"];

        FMDBQuickCheck(![db hadError]);

        rs = [db getTableSchema:@"234 fds"];

        FMDBQuickCheck([rs next]);

        [rs close];

        

        

        

        

        

        //通过NSMutableDictionary来传递参数,好棒。但总觉得这个数据结构有点儿重型啊。NSMutableDictionary中参数大于所用的没关系,只要有就可以哦

        {

            // -------------------------------------------------------------------------------

            // Named parameters count test.

            FMDBQuickCheck([db executeUpdate:@"create table namedparamcounttest (a text, b text, c integer, d double)"]);

            NSMutableDictionary *dictionaryArgs = [NSMutableDictionary dictionary];

            [dictionaryArgs setObject:@"Text1" forKey:@"a"];

            [dictionaryArgs setObject:@"Text2" forKey:@"b"];

            [dictionaryArgs setObject:[NSNumber numberWithInt:1] forKey:@"c"];

            [dictionaryArgs setObject:[NSNumber numberWithDouble:2.0] forKey:@"d"];

            FMDBQuickCheck([db executeUpdate:@"insert into namedparamcounttest values (:a, :b, :c, :d)" withParameterDictionary:dictionaryArgs]);

            

            rs = [db executeQuery:@"select * from namedparamcounttest"];

            

            FMDBQuickCheck((rs != nil));

            

            [rs next];

            

            FMDBQuickCheck([[rs stringForColumn:@"a"] isEqualToString:@"Text1"]);

            FMDBQuickCheck([[rs stringForColumn:@"b"] isEqualToString:@"Text2"]);

            FMDBQuickCheck([rs intForColumn:@"c"] == 1);

            FMDBQuickCheck([rs doubleForColumn:@"d"] == 2.0);

            

            [rs close];

            

            // note that at this point, dictionaryArgs has way more values than we need, but the query should still work since

            // a is in there, and that's all we need.

            rs = [db executeQuery:@"select * from namedparamcounttest where a = :a" withParameterDictionary:dictionaryArgs];

            

            FMDBQuickCheck((rs != nil));

            FMDBQuickCheck([rs next]);

            [rs close];

            

            

            

            // ***** Please note the following codes *****

            

            dictionaryArgs = [NSMutableDictionary dictionary];

            

            [dictionaryArgs setObject:@"NewText1" forKey:@"a"];

            [dictionaryArgs setObject:@"NewText2" forKey:@"b"];

            [dictionaryArgs setObject:@"OneMoreText" forKey:@"OneMore"];

            

            BOOL rc = [db executeUpdate:@"update namedparamcounttest set a = :a, b = :b where b = 'Text2'" withParameterDictionary:dictionaryArgs];

            

            FMDBQuickCheck(rc);

            

            if (!rc) {

                NSLog(@"ERROR: %d - %@", db.lastErrorCode, db.lastErrorMessage);

            }

            

            

        }

        

        

        

        

        

        

        

        

        

        //来看看对大数据的支持了

        // ----------------------------------------------------------------------------------------

        // blob support.

        [db executeUpdate:@"create table blobTable (a text, b blob)"];

        

        // let's read in an image from safari's app bundle.

        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]) {

                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");

                //老子不太明白这里为啥要个Nocopy,得看对NSData的使用,内存里再加个备份么。

                // ye shall read the header for this function, or suffer the consequences.

                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 {

                NSLog(@"Could not select image.");

            }

            

            [rs close];

            

        }

        else {

            NSLog(@"Can't find compass image..");

        }

        

        

        // test out the convenience methods in +Additions

        //验证下快捷的方法,比如[db changes];

        //比如intForQuery

        [db executeUpdate:@"create table t1 (a integer)"];

        [db executeUpdate:@"insert into t1 values (?)", [NSNumber numberWithInt:5]];

        

        NSLog(@"Count of changes (should be 1): %d", [db changes]);

        FMDBQuickCheck([db changes] == 1);

        

        int ia = [db intForQuery:@"select a from t1 where a = ?", [NSNumber numberWithInt:5]];

        if (ia != 5) {

            NSLog(@"intForQuery didn't work (a != 5)");

        }

        

        // test the busy rety timeout schtuff.

        //再验证下timeout

        [db setBusyRetryTimeout:500];

        //麻痹为毛再看一个连接呢

        FMDatabase *newDb = [FMDatabase databaseWithPath:dbPath];

        [newDb open];

        

        rs = [newDb executeQuery:@"select rowid,* from test where a = ?", @"hi'"];

        [rs next]; // just grab one... which will keep the db locked.

        

        NSLog(@"Testing the busy timeout");

        

        BOOL success = [db executeUpdate:@"insert into t1 values (5)"];

        

        if (success) {

            NSLog(@"Whoa- the database didn't stay locked!");

            return 7;

        }

        else {

            NSLog(@"Hurray, our timeout worked");

        }

        

        [rs close];

        [newDb close];

        

        success = [db executeUpdate:@"insert into t1 values (5)"];

        if (!success) {

            NSLog(@"Whoa- the database shouldn't be locked!");

            return 8;

        }

        else {

            NSLog(@"Hurray, we can insert again!");

        }

        

        

        

        // test some nullness.

        //测试插入nil值

        [db executeUpdate:@"create table t2 (a integer, b integer)"];

        

        if (![db executeUpdate:@"insert into t2 values (?, ?)", nil, [NSNumber numberWithInt:5]]) {

            NSLog(@"UH OH, can't insert a nil value for some reason...");

        }

        

        

        

        

        rs = [db executeQuery:@"select * from t2"];

        while ([rs next]) {

            NSString *aa = [rs stringForColumnIndex:0];

            NSString *b = [rs stringForColumnIndex:1];

            

            if (aa != nil) {

                NSLog(@"%s:%d", __FUNCTION__, __LINE__);

                NSLog(@"OH OH, PROBLEMO!");

                return 10;

            }

            else {

                NSLog(@"YAY, NULL VALUES");

            }

            

            if (![b isEqualToString:@"5"]) {

                NSLog(@"%s:%d", __FUNCTION__, __LINE__);

                NSLog(@"OH OH, PROBLEMO!");

                return 10;

            }

        }

        

        

        

        

        

        

        

        

        

        

        // test some inner loop funkness.

        [db executeUpdate:@"create table t3 (a somevalue)"];

        

        

        // do it again, just because

        [db beginTransaction];

        i = 0;

        while (i++ < 20) {

            [db executeUpdate:@"insert into t3 (a) values (?)" , [NSNumber numberWithInt:i]];

        }

        [db commit];

        

        

        

        

        rs = [db executeQuery:@"select * from t3"];

        while ([rs next]) {

            int foo = [rs intForColumnIndex:0];

            

            int newVal = foo + 100;

            

            [db executeUpdate:@"update t3 set a = ? where a = ?" , [NSNumber numberWithInt:newVal], [NSNumber numberWithInt:foo]];

            

            

            FMResultSet *rs2 = [db executeQuery:@"select a from t3 where a = ?", [NSNumber numberWithInt:newVal]];

            [rs2 next];

            

            if ([rs2 intForColumnIndex:0] != newVal) {

                NSLog(@"Oh crap, our update didn't work out!");

                return 9;

            }

            

            [rs2 close];

        }

        

        

        // NSNull tests

        [db executeUpdate:@"create table nulltest (a text, b text)"];

        

        [db executeUpdate:@"insert into nulltest (a, b) values (?, ?)" , [NSNull null], @"a"];

        [db executeUpdate:@"insert into nulltest (a, b) values (?, ?)" , nil, @"b"];

        

        rs = [db executeQuery:@"select * from nulltest"];

        

        while ([rs next]) {

            

            NSString *a = [rs stringForColumnIndex:0];

            NSString *b = [rs stringForColumnIndex:1];

            

            if (!b) {

                NSLog(@"Oh crap, the nil / null inserts didn't work!");

                return 10;

            }

            

            if (a) {

                NSLog(@"Oh crap, the nil / null inserts didn't work (son of error message)!");

                return 11;

            }

            else {

                NSLog(@"HURRAH FOR NSNULL (and nil)!");

            }

        }

        

        

        FMDBQuickCheck([db columnExists:@"a" inTableWithName:@"nulltest"]);

        FMDBQuickCheck([db columnExists:@"b" inTableWithName:@"nulltest"]);

        FMDBQuickCheck(![db columnExists:@"c" inTableWithName:@"nulltest"]);

        

        

        // null dates

        //日期为nil

        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)"];

        

        // grab the data for this again, since we overwrote it with some memory that has since disapeared.

        safariCompass = [NSData dataWithContentsOfFile:@"/Applications/Safari.app/Contents/Resources/compass.icns"];

        

        [db executeUpdate:@"insert into nulltest2 (s, d, i, f, b) values (?, ?, ?, ?, ?)" , @"Hi", safariCompass, [NSNumber numberWithInt:12], [NSNumber numberWithFloat:4.4f], [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]) {

            

            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 utest (a text)"];

            [db executeUpdate:@"insert into utest values (?)", @"/übertest"];

            

            rs = [db executeQuery:@"select * from utest where a = ?", @"/übertest"];

            FMDBQuickCheck([rs next]);

            [rs close];

        }

        

        

        {

            [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"]);

            //getSchema这个能返回所有的表哦。

            rs = [db getSchema];

            while ([rs next]) {

                FMDBQuickCheck([[rs stringForColumn:@"type"] isEqualToString:@"table"]);

            }

        }

        

        

        {

            FMDBQuickCheck([db executeUpdate:@"create table t5 (a text, b int, c blob, d text, e text)"]);

            FMDBQuickCheck(([db executeUpdateWithFormat:@"insert into t5 values (%s, %d, %@, %c, %lld)", "text", 42, @"BLOB", 'd', 12345678901234]));

            

            rs = [db executeQueryWithFormat:@"select * from t5 where a = %s and a = %@ and b = %d", "text", @"text", 42];

            FMDBQuickCheck((rs != nil));

            

            [rs next];

            

            FMDBQuickCheck([[rs stringForColumn:@"a"] isEqualToString:@"text"]);

            FMDBQuickCheck(([rs intForColumn:@"b"] == 42));

            FMDBQuickCheck([[rs stringForColumn:@"c"] isEqualToString:@"BLOB"]);

            FMDBQuickCheck([[rs stringForColumn:@"d"] isEqualToString:@"d"]);

            FMDBQuickCheck(([rs longLongIntForColumn:@"e"] == 12345678901234));

            

            [rs close];

        }

        

        

        

        {

            FMDBQuickCheck([db executeUpdate:@"create table t55 (a text, b int, c float)"]);

            short testShort = -4;

            float testFloat = 5.5;

            FMDBQuickCheck(([db executeUpdateWithFormat:@"insert into t55 values (%c, %hi, %g)", 'a', testShort, testFloat]));

            

            unsigned short testUShort = 6;

            FMDBQuickCheck(([db executeUpdateWithFormat:@"insert into t55 values (%c, %hu, %g)", 'a', testUShort, testFloat]));

            

            

            rs = [db executeQueryWithFormat:@"select * from t55 where a = %s order by 2", "a"];

            FMDBQuickCheck((rs != nil));

            

            [rs next];

            

            FMDBQuickCheck([[rs stringForColumn:@"a"] isEqualToString:@"a"]);

            FMDBQuickCheck(([rs intForColumn:@"b"] == -4));

            FMDBQuickCheck([[rs stringForColumn:@"c"] isEqualToString:@"5.5"]);

            

            

            [rs next];

            

            FMDBQuickCheck([[rs stringForColumn:@"a"] isEqualToString:@"a"]);

            FMDBQuickCheck(([rs intForColumn:@"b"] == 6));

            FMDBQuickCheck([[rs stringForColumn:@"c"] isEqualToString:@"5.5"]);

            

            [rs close];

            

        }

        

        

        

        

        {

            FMDBQuickCheck(([db update:@"insert into t5 values (?, ?, ?, ?, ?)" withErrorAndBindings:&err, @"text", [NSNumber numberWithInt:42], @"BLOB", @"d", [NSNumber numberWithInt:0]]));

            

        }

        

        

        // test attach for the heck of it.

        {

            

            //FMDatabase *dbA = [FMDatabase databaseWithPath:dbPath];

            [fileManager removeItemAtPath:@"/tmp/attachme.db" error:nil];

            FMDatabase *dbB = [FMDatabase databaseWithPath:@"/tmp/attachme.db"];

            FMDBQuickCheck([dbB open]);

            FMDBQuickCheck([dbB executeUpdate:@"create table attached (a text)"]);

            FMDBQuickCheck(([dbB executeUpdate:@"insert into attached values (?)", @"test"]));

            FMDBQuickCheck([dbB close]);

            

            [db executeUpdate:@"attach database '/tmp/attachme.db' as attack"];

            

            rs = [db executeQuery:@"select * from attack.attached"];

            FMDBQuickCheck([rs next]);

            [rs close];

            

        }

        

        

        

        {

            // -------------------------------------------------------------------------------

            // Named parameters.

            FMDBQuickCheck([db executeUpdate:@"create table namedparamtest (a text, b text, c integer, d double)"]);

            NSMutableDictionary *dictionaryArgs = [NSMutableDictionary dictionary];

            [dictionaryArgs setObject:@"Text1" forKey:@"a"];

            [dictionaryArgs setObject:@"Text2" forKey:@"b"];

            [dictionaryArgs setObject:[NSNumber numberWithInt:1] forKey:@"c"];

            [dictionaryArgs setObject:[NSNumber numberWithDouble:2.0] forKey:@"d"];

            FMDBQuickCheck([db executeUpdate:@"insert into namedparamtest values (:a, :b, :c, :d)" withParameterDictionary:dictionaryArgs]);

            

            rs = [db executeQuery:@"select * from namedparamtest"];

            

            FMDBQuickCheck((rs != nil));

            

            [rs next];

            

            FMDBQuickCheck([[rs stringForColumn:@"a"] isEqualToString:@"Text1"]);

            FMDBQuickCheck([[rs stringForColumn:@"b"] isEqualToString:@"Text2"]);

            FMDBQuickCheck([rs intForColumn:@"c"] == 1);

            FMDBQuickCheck([rs doubleForColumn:@"d"] == 2.0);

            

            [rs close];

            

            

            dictionaryArgs = [NSMutableDictionary dictionary];

            

            [dictionaryArgs setObject:@"Text2" forKey:@"blah"];

            

            rs = [db executeQuery:@"select * from namedparamtest where b = :blah" withParameterDictionary:dictionaryArgs];

            

            FMDBQuickCheck((rs != nil));

            FMDBQuickCheck([rs next]);

            FMDBQuickCheck([[rs stringForColumn:@"b"] isEqualToString:@"Text2"]);

            

            [rs close];

            

            

            

            

        }

        

        // just for fun.

        //PRAGMA database_list 查看数据库列表。

        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]) {

            

            NSEnumerator *e = [[db cachedStatements] objectEnumerator];;

            FMStatement *statement;

            

            while ((statement = [e nextObject])) {

                NSLog(@"%@", statement);

            }

        }

        

        

        [db setShouldCacheStatements:true];

        

        [db executeUpdate:@"CREATE TABLE testCacheStatements(key INTEGER PRIMARY KEY, value INTEGER)"];

        [db executeUpdate:@"INSERT INTO testCacheStatements (key, value) VALUES (1, 2)"];

        [db executeUpdate:@"INSERT INTO testCacheStatements (key, value) VALUES (2, 4)"];

        

        FMDBQuickCheck([[db executeQuery:@"SELECT * FROM testCacheStatements WHERE key=1"] next]);

        FMDBQuickCheck([[db executeQuery:@"SELECT * FROM testCacheStatements WHERE key=1"] next]);

        //这里关闭了db

        [db close];

        

        //TODO testpool

        //testPool(dbPath);

                

        FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:dbPath];

        

        FMDBQuickCheck(queue);

        {

            [queue inDatabase:^(FMDatabase *adb) {

                [adb executeUpdate:@"create table qfoo (foo text)"];

                [adb executeUpdate:@"insert into qfoo values ('hi')"];

                [adb executeUpdate:@"insert into qfoo values ('hello')"];

                [adb executeUpdate:@"insert into qfoo values ('not')"];

                

                int count = 0;

                FMResultSet *rsl = [adb executeQuery:@"select * from qfoo where foo like 'h%'"];

                while ([rsl next]) {

                    count++;

                }

                

                FMDBQuickCheck(count == 2);

                

                count = 0;

                rsl = [adb executeQuery:@"select * from qfoo where foo like ?", @"h%"];

                while ([rsl next]) {

                    count++;

                }

                

                FMDBQuickCheck(count == 2);

            }];

        }        

        {

            // You should see pairs of numbers show up in stdout for this stuff:

            //stdout中会有很多显示。

            size_t ops = 16;

            dispatch_queue_t dqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

            dispatch_apply(ops, dqueue, ^(size_t nby) {

                

                // just mix things up a bit for demonstration purposes.

                if (nby % 2 == 1) {

                    [NSThread sleepForTimeInterval:.1];

                    //用一个inTransaction去查询数据库,查8遍。

                    [queue inTransaction:^(FMDatabase *adb, BOOL *rollback) {

                        NSLog(@"Starting query  %ld", nby);

                        

                        FMResultSet *rsl = [adb executeQuery:@"select * from qfoo where foo like 'h%'"];

                        while ([rsl next]) {

                            ;// whatever.

                        }

                        

                        NSLog(@"Ending query    %ld", nby);

                    }];

                    

                }

                

                if (nby % 3 == 1) {

                    [NSThread sleepForTimeInterval:.1];

                }

                //用一个inTransaction去插入数据,插16遍

                [queue inTransaction:^(FMDatabase *adb, BOOL *rollback) {

                    NSLog(@"Starting update %ld", nby);

                    [adb executeUpdate:@"insert into qfoo values ('1')"];

                    [adb executeUpdate:@"insert into qfoo values ('2')"];

                    [adb executeUpdate:@"insert into qfoo values ('3')"];

                    NSLog(@"Ending update   %ld", nby);

                }];

            });

            

            [queue close];

            //用inDatabase插一遍

            [queue inDatabase:^(FMDatabase *adb) {

                FMDBQuickCheck([adb executeUpdate:@"insert into qfoo values ('1')"]);

            }];

        }

        

        {

            

            

            [queue inDatabase:^(FMDatabase *adb) {

                [adb executeUpdate:@"create table colNameTest (a, b, c, d)"];

                FMDBQuickCheck([adb executeUpdate:@"insert into colNameTest values (1, 2, 3, 4)"]);

                

                FMResultSet *ars = [adb executeQuery:@"select * from colNameTest"];

                

                NSDictionary *d = [ars columnNameToIndexMap];

                FMDBQuickCheck([d count] == 4);

                

                FMDBQuickCheck([[d objectForKey:@"a"] intValue] == 0);

                FMDBQuickCheck([[d objectForKey:@"b"] intValue] == 1);

                FMDBQuickCheck([[d objectForKey:@"c"] intValue] == 2);

                FMDBQuickCheck([[d objectForKey:@"d"] intValue] == 3);

                

                [ars close];

                

            }];

            

        }

        

        

        {

            [queue inDatabase:^(FMDatabase *adb) {

                [adb executeUpdate:@"create table transtest (a integer)"];

                FMDBQuickCheck([adb executeUpdate:@"insert into transtest values (1)"]);

                FMDBQuickCheck([adb executeUpdate:@"insert into transtest values (2)"]);

                

                int rowCount = 0;

                FMResultSet *ars = [adb executeQuery:@"select * from transtest"];

                while ([ars next]) {

                    rowCount++;

                }

                

                FMDBQuickCheck(rowCount == 2);

            }];

            

            

            //有事务退出机制的inTransaction

            [queue inTransaction:^(FMDatabase *adb, BOOL *rollback) {

                FMDBQuickCheck([adb executeUpdate:@"insert into transtest values (3)"]);

                

                if (YES) {

                    // uh oh!, something went wrong (not really, this is just a test

                    *rollback = YES;

                    return;

                }

                

                FMDBQuickCheck([adb executeUpdate:@"insert into transtest values (4)"]);

            }];

            

            [queue inDatabase:^(FMDatabase *adb) {

                

                int rowCount = 0;

                FMResultSet *ars = [adb executeQuery:@"select * from transtest"];

                while ([ars next]) {

                    rowCount++;

                }

                

                FMDBQuickCheck(![adb hasOpenResultSets]);

                

                NSLog(@"after rollback, rowCount is %d (should be 2)", rowCount);

                

                FMDBQuickCheck(rowCount == 2);

            }];

        }

        

        // hey, let's make a custom function!

        //自定义函数

        [queue inDatabase:^(FMDatabase *adb) {

            

            [adb executeUpdate:@"create table ftest (foo text)"];

            [adb executeUpdate:@"insert into ftest values ('hello')"];

            [adb executeUpdate:@"insert into ftest values ('hi')"];

            [adb executeUpdate:@"insert into ftest values ('not h!')"];

            [adb executeUpdate:@"insert into ftest values ('definitely not h!')"];

            

            [adb makeFunctionNamed:@"StringStartsWithH" maximumArguments:1 withBlock:^(sqlite3_context *context, int aargc, sqlite3_value **aargv) {

                if (sqlite3_value_type(aargv[0]) == SQLITE_TEXT) {

                    

                    @autoreleasepool {

                        

                        const char *c = (const char *)sqlite3_value_text(aargv[0]);

                        

                        NSString *s = [NSString stringWithUTF8String:c];

                        

                        sqlite3_result_int(context, [s hasPrefix:@"h"]);

                    }

                }

                else {

                    NSLog(@"Unknown formart for StringStartsWithH (%d) %s:%d", sqlite3_value_type(aargv[0]), __FUNCTION__, __LINE__);

                    sqlite3_result_null(context);

                }

            }];

            //找列中以h开头的记录。

            int rowCount = 0;

            FMResultSet *ars = [adb executeQuery:@"select * from ftest where StringStartsWithH(foo)"];

            while ([ars next]) {

                rowCount++;

                

                NSLog(@"Does %@ start with 'h'?", [rs stringForColumnIndex:0]);

                

            }

            FMDBQuickCheck(rowCount == 2);

            

        }];

        

        

        NSLog(@"That was version %@ of sqlite", [FMDatabase sqliteLibVersion]);

        

        

    }// this is the end of our @autorelease pool.

    

    

    return 0;

}


/*

 Test the various FMDatabasePool things.

 */


void testPool(NSString *dbPath) {

    

    FMDatabasePool *dbPool = [FMDatabasePool databasePoolWithPath:dbPath];

    

    FMDBQuickCheck([dbPool countOfOpenDatabases] == 0);

    

    __block FMDatabase *db1;

    

    [dbPool inDatabase:^(FMDatabase *db) {

        

        

        

        FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);

        

        FMDBQuickCheck([db tableExists:@"t4"]);

        

        db1 = db;

        

    }];

    

    [dbPool inDatabase:^(FMDatabase *db) {

        FMDBQuickCheck(db1 == db);

        

        [dbPool inDatabase:^(FMDatabase *db2) {

            FMDBQuickCheck(db2 != db);

        }];

        

    }];

    

    

    

    FMDBQuickCheck([dbPool countOfOpenDatabases] == 2);

    

    

    [dbPool inDatabase:^(FMDatabase *db) {

        [db executeUpdate:@"create table easy (a text)"];

        [db executeUpdate:@"create table easy2 (a text)"];

        

    }];

    

    

    FMDBQuickCheck([dbPool countOfOpenDatabases] == 2);

    

    [dbPool releaseAllDatabases];

    

    FMDBQuickCheck([dbPool countOfOpenDatabases] == 0);

    

    [dbPool inDatabase:^(FMDatabase *aDb) {

        

        FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 0);

        FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 1);

        

        FMDBQuickCheck([aDb tableExists:@"t4"]);

        

        FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 0);

        FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 1);

        

        FMDBQuickCheck(([aDb executeUpdate:@"insert into easy (a) values (?)", @"hi"]));

        

        // just for fun.

        FMResultSet *rs2 = [aDb executeQuery:@"select * from easy"];

        FMDBQuickCheck([rs2 next]);

        while ([rs2 next]) { ; } // whatevers.

        

        FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);

        FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 0);

        FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 1);

    }];

    

    

    FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);

    

    

    {

        

        [dbPool inDatabase:^(FMDatabase *db) {

            

            [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1]];

            [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:2]];

            [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:3]];

            

            FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 0);

            FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 1);

        }];

    }

    

    

    FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);

    

    [dbPool setMaximumNumberOfDatabasesToCreate:2];

    

    

    [dbPool inDatabase:^(FMDatabase *db) {

        [dbPool inDatabase:^(FMDatabase *db2) {

            [dbPool inDatabase:^(FMDatabase *db3) {

                FMDBQuickCheck([dbPool countOfOpenDatabases] == 2);

                FMDBQuickCheck(!db3);

            }];

            

        }];

    }];

    

    [dbPool setMaximumNumberOfDatabasesToCreate:0];

    

    [dbPool releaseAllDatabases];

    

    FMDBQuickCheck([dbPool countOfOpenDatabases] == 0);

    

    [dbPool inDatabase:^(FMDatabase *db) {

        [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:3]];

    }];

    

    

    FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);

    

    

    [dbPool inTransaction:^(FMDatabase *adb, BOOL *rollback) {

        [adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1001]];

        [adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1002]];

        [adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1003]];

        

        FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);

        FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 0);

        FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 1);

    }];

    

    

    FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);

    FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 1);

    FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 0);

    

    

    [dbPool inDatabase:^(FMDatabase *db) {

        FMResultSet *rs2 = [db executeQuery:@"select * from easy where a = ?", [NSNumber numberWithInt:1001]];

        FMDBQuickCheck([rs2 next]);

        FMDBQuickCheck(![rs2 next]);

    }];

    

    

    

    [dbPool inDeferredTransaction:^(FMDatabase *adb, BOOL *rollback) {

        [adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1004]];

        [adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1005]];

        

        *rollback = YES;

    }];

    

    FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);

    FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 1);

    FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 0);

    

    NSError *err = [dbPool inSavePoint:^(FMDatabase *db, BOOL *rollback) {

        [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1006]];

    }];

    

    FMDBQuickCheck(!err);

    

    {

        

        err = [dbPool inSavePoint:^(FMDatabase *adb, BOOL *rollback) {

            FMDBQuickCheck(![adb hadError]);

            [adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1009]];

            

            [adb inSavePoint:^(BOOL *arollback) {

                FMDBQuickCheck(([adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1010]]));

                *arollback = YES;

            }];

        }];

        

        

        FMDBQuickCheck(!err);

        

        [dbPool inDatabase:^(FMDatabase *db) {

            

            

            FMResultSet *rs2 = [db executeQuery:@"select * from easy where a = ?", [NSNumber numberWithInt:1009]];

            FMDBQuickCheck([rs2 next]);

            FMDBQuickCheck(![rs2 next]); // close it out.

            

            rs2 = [db executeQuery:@"select * from easy where a = ?", [NSNumber numberWithInt:1010]];

            FMDBQuickCheck(![rs2 next]);

        }];

        

        

    }

    

    {

        

        [dbPool inDatabase:^(FMDatabase *db) {

            [db executeUpdate:@"create table likefoo (foo text)"];

            [db executeUpdate:@"insert into likefoo values ('hi')"];

            [db executeUpdate:@"insert into likefoo values ('hello')"];

            [db executeUpdate:@"insert into likefoo values ('not')"];

            

            int count = 0;

            FMResultSet *rsl = [db executeQuery:@"select * from likefoo where foo like 'h%'"];

            while ([rsl next]) {

                count++;

            }

            

            FMDBQuickCheck(count == 2);

            

            count = 0;

            rsl = [db executeQuery:@"select * from likefoo where foo like ?", @"h%"];

            while ([rsl next]) {

                count++;

            }

            

            FMDBQuickCheck(count == 2);

            

        }];

    }

    

    

    {

        

        size_t ops = 128;

        

        dispatch_queue_t dqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

        

        dispatch_apply(ops, dqueue, ^(size_t nby) {

            

            // just mix things up a bit for demonstration purposes.

            if (nby % 2 == 1) {

                

                [NSThread sleepForTimeInterval:.1];

            }

            

            [dbPool inDatabase:^(FMDatabase *db) {

                NSLog(@"Starting query  %ld", nby);

                

                FMResultSet *rsl = [db executeQuery:@"select * from likefoo where foo like 'h%'"];

                while ([rsl next]) {

                    if (nby % 3 == 1) {

                        [NSThread sleepForTimeInterval:.05];

                    }

                }

                

                NSLog(@"Ending query    %ld", nby);

            }];

        });

        

        NSLog(@"Number of open databases after crazy gcd stuff: %ld", [dbPool countOfOpenDatabases]);

    }

    

    

    // if you want to see a deadlock, just uncomment this line and run:

    //#define ONLY_USE_THE_POOL_IF_YOU_ARE_DOING_READS_OTHERWISE_YOULL_DEADLOCK_USE_FMDATABASEQUEUE_INSTEAD 1

#ifdef ONLY_USE_THE_POOL_IF_YOU_ARE_DOING_READS_OTHERWISE_YOULL_DEADLOCK_USE_FMDATABASEQUEUE_INSTEAD

    {

        

        int ops = 16;

        

        dispatch_queue_t dqueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

        

        dispatch_apply(ops, dqueue, ^(size_t nby) {

            

            // just mix things up a bit for demonstration purposes.

            if (nby % 2 == 1) {

                [NSThread sleepForTimeInterval:.1];

                

                [dbPool inTransaction:^(FMDatabase *db, BOOL *rollback) {

                    NSLog(@"Starting query  %ld", nby);

                    

                    FMResultSet *rsl = [db executeQuery:@"select * from likefoo where foo like 'h%'"];

                    while ([rsl next]) {

                        ;// whatever.

                    }

                    

                    NSLog(@"Ending query    %ld", nby);

                }];

                

            }

            

            if (nby % 3 == 1) {

                [NSThread sleepForTimeInterval:.1];

            }

            

            [dbPool inTransaction:^(FMDatabase *db, BOOL *rollback) {

                NSLog(@"Starting update %ld", nby);

                [db executeUpdate:@"insert into likefoo values ('1')"];

                [db executeUpdate:@"insert into likefoo values ('2')"];

                [db executeUpdate:@"insert into likefoo values ('3')"];

                NSLog(@"Ending update   %ld", nby);

            }];

        });

        

        [dbPool releaseAllDatabases];

        

        [dbPool inDatabase:^(FMDatabase *db) {

            FMDBQuickCheck([db executeUpdate:@"insert into likefoo values ('1')"]);

        }];

    }

#endif

    

}



/*

 What is this function for?  Think of it as a template which a developer can use

 to report bugs.

 

 If you have a bug, make it reproduce in this function and then let the

 developer(s) know either via the github bug reporter or the mailing list.

 */

//如果与错误的话,就修改这个方法,加上你出错的核心部分代码,然后report.

void FMDBReportABugFunction() {

    

    NSString *dbPath = @"/tmp/bugreportsample.db";

    

    // delete the old db if it exists

    NSFileManager *fileManager = [NSFileManager defaultManager];

    [fileManager removeItemAtPath:dbPath error:nil];

    

    FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:dbPath];

    

    [queue inDatabase:^(FMDatabase *db) {

        

        /*

         Change the contents of this block to suit your needs.

         */

        

        BOOL worked = [db executeUpdate:@"create table test (a text, b text, c integer, d double, e double)"];

        FMDBQuickCheck(worked);

        

        

        worked = [db executeUpdate:@"insert into test values ('a', 'b', 1, 2.2, 2.3)"];

        FMDBQuickCheck(worked);

        

        FMResultSet *rs = [db executeQuery:@"select * from test"];

        FMDBQuickCheck([rs next]);

        [rs close];

        

    }];

    

    

    [queue close];

    

    

    // uncomment the following line if you don't want to run through all the other tests.

    //exit(0);

    

}





好文:http://www.keakon.net/2011/10/25/SQLite%E5%9C%A8%E5%A4%9A%E7%BA%BF%E7%A8%8B%E7%8E%AF%E5%A2%83%E4%B8%8B%E7%9A%84%E5%BA%94%E7%94%A8


SQLite在多线程环境下的应用

转载于:https://my.oschina.net/openlab/blog/124626

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值