fmdb.m 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  1. #import <Foundation/Foundation.h>
  2. #import "FMDatabase.h"
  3. #import "FMDatabaseAdditions.h"
  4. #import "FMDatabasePool.h"
  5. #define FMDBQuickCheck(SomeBool) { if (!(SomeBool)) { NSLog(@"Failure on line %d", __LINE__); abort(); } }
  6. int main (int argc, const char * argv[]) {
  7. NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  8. NSString *dbPath = @"/tmp/tmp.db";
  9. // delete the old db.
  10. NSFileManager *fileManager = [NSFileManager defaultManager];
  11. [fileManager removeItemAtPath:dbPath error:nil];
  12. FMDatabase *db = [FMDatabase databaseWithPath:dbPath];
  13. NSLog(@"Is SQLite compiled with it's thread safe options turned on? %@!", [FMDatabase isSQLiteThreadSafe] ? @"Yes" : @"No");
  14. {
  15. // -------------------------------------------------------------------------------
  16. // Un-opened database check.
  17. FMDBQuickCheck([db executeQuery:@"select * from table"] == nil);
  18. NSLog(@"%d: %@", [db lastErrorCode], [db lastErrorMessage]);
  19. }
  20. if (![db open]) {
  21. NSLog(@"Could not open db.");
  22. [pool release];
  23. return 0;
  24. }
  25. // kind of experimentalish.
  26. [db setShouldCacheStatements:YES];
  27. // create a bad statement, just to test the error code.
  28. [db executeUpdate:@"blah blah blah"];
  29. FMDBQuickCheck([db hadError]);
  30. if ([db hadError]) {
  31. NSLog(@"Err %d: %@", [db lastErrorCode], [db lastErrorMessage]);
  32. }
  33. NSError *err = 0x00;
  34. FMDBQuickCheck(![db update:@"blah blah blah" withErrorAndBindings:&err]);
  35. FMDBQuickCheck(err != nil);
  36. FMDBQuickCheck([err code] == SQLITE_ERROR);
  37. NSLog(@"err: '%@'", err);
  38. // but of course, I don't bother checking the error codes below.
  39. // Bad programmer, no cookie.
  40. [db executeUpdate:@"create table test (a text, b text, c integer, d double, e double)"];
  41. [db beginTransaction];
  42. int i = 0;
  43. while (i++ < 20) {
  44. [db executeUpdate:@"insert into test (a, b, c, d, e) values (?, ?, ?, ?, ?)" ,
  45. @"hi'", // look! I put in a ', and I'm not escaping it!
  46. [NSString stringWithFormat:@"number %d", i],
  47. [NSNumber numberWithInt:i],
  48. [NSDate date],
  49. [NSNumber numberWithFloat:2.2f]];
  50. }
  51. [db commit];
  52. // do it again, just because
  53. [db beginTransaction];
  54. i = 0;
  55. while (i++ < 20) {
  56. [db executeUpdate:@"insert into test (a, b, c, d, e) values (?, ?, ?, ?, ?)" ,
  57. @"hi again'", // look! I put in a ', and I'm not escaping it!
  58. [NSString stringWithFormat:@"number %d", i],
  59. [NSNumber numberWithInt:i],
  60. [NSDate date],
  61. [NSNumber numberWithFloat:2.2f]];
  62. }
  63. [db commit];
  64. FMResultSet *rs = [db executeQuery:@"select rowid,* from test where a = ?", @"hi'"];
  65. while ([rs next]) {
  66. // just print out what we've got in a number of formats.
  67. NSLog(@"%d %@ %@ %@ %@ %f %f",
  68. [rs intForColumn:@"c"],
  69. [rs stringForColumn:@"b"],
  70. [rs stringForColumn:@"a"],
  71. [rs stringForColumn:@"rowid"],
  72. [rs dateForColumn:@"d"],
  73. [rs doubleForColumn:@"d"],
  74. [rs doubleForColumn:@"e"]);
  75. if (!([[rs columnNameForIndex:0] isEqualToString:@"rowid"] &&
  76. [[rs columnNameForIndex:1] isEqualToString:@"a"])
  77. ) {
  78. NSLog(@"WHOA THERE BUDDY, columnNameForIndex ISN'T WORKING!");
  79. return 7;
  80. }
  81. }
  82. // close the result set.
  83. // it'll also close when it's dealloc'd, but we're closing the database before
  84. // the autorelease pool closes, so sqlite will complain about it.
  85. [rs close];
  86. // ----------------------------------------------------------------------------------------
  87. // blob support.
  88. [db executeUpdate:@"create table blobTable (a text, b blob)"];
  89. // let's read in an image from safari's app bundle.
  90. NSData *safariCompass = [NSData dataWithContentsOfFile:@"/Applications/Safari.app/Contents/Resources/compass.icns"];
  91. if (safariCompass) {
  92. [db executeUpdate:@"insert into blobTable (a, b) values (?,?)", @"safari's compass", safariCompass];
  93. rs = [db executeQuery:@"select b from blobTable where a = ?", @"safari's compass"];
  94. if ([rs next]) {
  95. safariCompass = [rs dataForColumn:@"b"];
  96. [safariCompass writeToFile:@"/tmp/compass.icns" atomically:NO];
  97. // let's look at our fancy image that we just wrote out..
  98. system("/usr/bin/open /tmp/compass.icns");
  99. // ye shall read the header for this function, or suffer the consequences.
  100. safariCompass = [rs dataNoCopyForColumn:@"b"];
  101. [safariCompass writeToFile:@"/tmp/compass_data_no_copy.icns" atomically:NO];
  102. system("/usr/bin/open /tmp/compass_data_no_copy.icns");
  103. }
  104. else {
  105. NSLog(@"Could not select image.");
  106. }
  107. [rs close];
  108. }
  109. else {
  110. NSLog(@"Can't find compass image..");
  111. }
  112. // test out the convenience methods in +Additions
  113. [db executeUpdate:@"create table t1 (a integer)"];
  114. [db executeUpdate:@"insert into t1 values (?)", [NSNumber numberWithInt:5]];
  115. NSLog(@"Count of changes (should be 1): %d", [db changes]);
  116. FMDBQuickCheck([db changes] == 1);
  117. int a = [db intForQuery:@"select a from t1 where a = ?", [NSNumber numberWithInt:5]];
  118. if (a != 5) {
  119. NSLog(@"intForQuery didn't work (a != 5)");
  120. }
  121. // test the busy rety timeout schtuff.
  122. [db setBusyRetryTimeout:50000];
  123. FMDatabase *newDb = [FMDatabase databaseWithPath:dbPath];
  124. [newDb open];
  125. rs = [newDb executeQuery:@"select rowid,* from test where a = ?", @"hi'"];
  126. [rs next]; // just grab one... which will keep the db locked.
  127. NSLog(@"Testing the busy timeout");
  128. BOOL success = [db executeUpdate:@"insert into t1 values (5)"];
  129. if (success) {
  130. NSLog(@"Whoa- the database didn't stay locked!");
  131. return 7;
  132. }
  133. else {
  134. NSLog(@"Hurray, our timeout worked");
  135. }
  136. [rs close];
  137. [newDb close];
  138. success = [db executeUpdate:@"insert into t1 values (5)"];
  139. if (!success) {
  140. NSLog(@"Whoa- the database shouldn't be locked!");
  141. return 8;
  142. }
  143. else {
  144. NSLog(@"Hurray, we can insert again!");
  145. }
  146. // test some nullness.
  147. [db executeUpdate:@"create table t2 (a integer, b integer)"];
  148. if (![db executeUpdate:@"insert into t2 values (?, ?)", nil, [NSNumber numberWithInt:5]]) {
  149. NSLog(@"UH OH, can't insert a nil value for some reason...");
  150. }
  151. rs = [db executeQuery:@"select * from t2"];
  152. while ([rs next]) {
  153. NSString *a = [rs stringForColumnIndex:0];
  154. NSString *b = [rs stringForColumnIndex:1];
  155. if (a != nil) {
  156. NSLog(@"%s:%d", __FUNCTION__, __LINE__);
  157. NSLog(@"OH OH, PROBLEMO!");
  158. return 10;
  159. }
  160. else {
  161. NSLog(@"YAY, NULL VALUES");
  162. }
  163. if (![b isEqualToString:@"5"]) {
  164. NSLog(@"%s:%d", __FUNCTION__, __LINE__);
  165. NSLog(@"OH OH, PROBLEMO!");
  166. return 10;
  167. }
  168. }
  169. // test some inner loop funkness.
  170. [db executeUpdate:@"create table t3 (a somevalue)"];
  171. // do it again, just because
  172. [db beginTransaction];
  173. i = 0;
  174. while (i++ < 20) {
  175. [db executeUpdate:@"insert into t3 (a) values (?)" , [NSNumber numberWithInt:i]];
  176. }
  177. [db commit];
  178. rs = [db executeQuery:@"select * from t3"];
  179. while ([rs next]) {
  180. int foo = [rs intForColumnIndex:0];
  181. int newVal = foo + 100;
  182. [db executeUpdate:@"update t3 set a = ? where a = ?" , [NSNumber numberWithInt:newVal], [NSNumber numberWithInt:foo]];
  183. FMResultSet *rs2 = [db executeQuery:@"select a from t3 where a = ?", [NSNumber numberWithInt:newVal]];
  184. [rs2 next];
  185. if ([rs2 intForColumnIndex:0] != newVal) {
  186. NSLog(@"Oh crap, our update didn't work out!");
  187. return 9;
  188. }
  189. [rs2 close];
  190. }
  191. // NSNull tests
  192. [db executeUpdate:@"create table nulltest (a text, b text)"];
  193. [db executeUpdate:@"insert into nulltest (a, b) values (?, ?)" , [NSNull null], @"a"];
  194. [db executeUpdate:@"insert into nulltest (a, b) values (?, ?)" , nil, @"b"];
  195. rs = [db executeQuery:@"select * from nulltest"];
  196. while ([rs next]) {
  197. NSString *a = [rs stringForColumnIndex:0];
  198. NSString *b = [rs stringForColumnIndex:1];
  199. if (!b) {
  200. NSLog(@"Oh crap, the nil / null inserts didn't work!");
  201. return 10;
  202. }
  203. if (a) {
  204. NSLog(@"Oh crap, the nil / null inserts didn't work (son of error message)!");
  205. return 11;
  206. }
  207. else {
  208. NSLog(@"HURRAH FOR NSNULL (and nil)!");
  209. }
  210. }
  211. // null dates
  212. NSDate *date = [NSDate date];
  213. [db executeUpdate:@"create table datetest (a double, b double, c double)"];
  214. [db executeUpdate:@"insert into datetest (a, b, c) values (?, ?, 0)" , [NSNull null], date];
  215. rs = [db executeQuery:@"select * from datetest"];
  216. while ([rs next]) {
  217. NSDate *a = [rs dateForColumnIndex:0];
  218. NSDate *b = [rs dateForColumnIndex:1];
  219. NSDate *c = [rs dateForColumnIndex:2];
  220. if (a) {
  221. NSLog(@"Oh crap, the null date insert didn't work!");
  222. return 12;
  223. }
  224. if (!c) {
  225. NSLog(@"Oh crap, the 0 date insert didn't work!");
  226. return 12;
  227. }
  228. NSTimeInterval dti = fabs([b timeIntervalSinceDate:date]);
  229. if (floor(dti) > 0.0) {
  230. NSLog(@"Date matches didn't really happen... time difference of %f", dti);
  231. return 13;
  232. }
  233. dti = fabs([c timeIntervalSinceDate:[NSDate dateWithTimeIntervalSince1970:0]]);
  234. if (floor(dti) > 0.0) {
  235. NSLog(@"Date matches didn't really happen... time difference of %f", dti);
  236. return 13;
  237. }
  238. }
  239. NSDate *foo = [db dateForQuery:@"select b from datetest where c = 0"];
  240. assert(foo);
  241. NSTimeInterval dti = fabs([foo timeIntervalSinceDate:date]);
  242. if (floor(dti) > 0.0) {
  243. NSLog(@"Date matches didn't really happen... time difference of %f", dti);
  244. return 14;
  245. }
  246. [db executeUpdate:@"create table nulltest2 (s text, d data, i integer, f double, b integer)"];
  247. [db executeUpdate:@"insert into nulltest2 (s, d, i, f, b) values (?, ?, ?, ?, ?)" , @"Hi", safariCompass, [NSNumber numberWithInt:12], [NSNumber numberWithFloat:4.4f], [NSNumber numberWithBool:YES]];
  248. [db executeUpdate:@"insert into nulltest2 (s, d, i, f, b) values (?, ?, ?, ?, ?)" , nil, nil, nil, nil, [NSNull null]];
  249. rs = [db executeQuery:@"select * from nulltest2"];
  250. while ([rs next]) {
  251. int i = [rs intForColumnIndex:2];
  252. if (i == 12) {
  253. // it's the first row we inserted.
  254. FMDBQuickCheck(![rs columnIndexIsNull:0]);
  255. FMDBQuickCheck(![rs columnIndexIsNull:1]);
  256. FMDBQuickCheck(![rs columnIndexIsNull:2]);
  257. FMDBQuickCheck(![rs columnIndexIsNull:3]);
  258. FMDBQuickCheck(![rs columnIndexIsNull:4]);
  259. FMDBQuickCheck( [rs columnIndexIsNull:5]);
  260. FMDBQuickCheck([[rs dataForColumn:@"d"] length] == [safariCompass length]);
  261. FMDBQuickCheck(![rs dataForColumn:@"notthere"]);
  262. FMDBQuickCheck(![rs stringForColumnIndex:-2]);
  263. FMDBQuickCheck([rs boolForColumnIndex:4]);
  264. FMDBQuickCheck([rs boolForColumn:@"b"]);
  265. FMDBQuickCheck(fabs(4.4 - [rs doubleForColumn:@"f"]) < 0.0000001);
  266. FMDBQuickCheck(12 == [rs intForColumn:@"i"]);
  267. FMDBQuickCheck(12 == [rs intForColumnIndex:2]);
  268. FMDBQuickCheck(0 == [rs intForColumnIndex:12]); // there is no 12
  269. FMDBQuickCheck(0 == [rs intForColumn:@"notthere"]);
  270. FMDBQuickCheck(12 == [rs longForColumn:@"i"]);
  271. FMDBQuickCheck(12 == [rs longLongIntForColumn:@"i"]);
  272. }
  273. else {
  274. // let's test various null things.
  275. FMDBQuickCheck([rs columnIndexIsNull:0]);
  276. FMDBQuickCheck([rs columnIndexIsNull:1]);
  277. FMDBQuickCheck([rs columnIndexIsNull:2]);
  278. FMDBQuickCheck([rs columnIndexIsNull:3]);
  279. FMDBQuickCheck([rs columnIndexIsNull:4]);
  280. FMDBQuickCheck([rs columnIndexIsNull:5]);
  281. FMDBQuickCheck(![rs dataForColumn:@"d"]);
  282. }
  283. }
  284. {
  285. [db executeUpdate:@"create table testOneHundredTwelvePointTwo (a text, b integer)"];
  286. [db executeUpdate:@"insert into testOneHundredTwelvePointTwo values (?, ?)" withArgumentsInArray:[NSArray arrayWithObjects:@"one", [NSNumber numberWithInteger:2], nil]];
  287. [db executeUpdate:@"insert into testOneHundredTwelvePointTwo values (?, ?)" withArgumentsInArray:[NSArray arrayWithObjects:@"one", [NSNumber numberWithInteger:3], nil]];
  288. rs = [db executeQuery:@"select * from testOneHundredTwelvePointTwo where b > ?" withArgumentsInArray:[NSArray arrayWithObject:[NSNumber numberWithInteger:1]]];
  289. FMDBQuickCheck([rs next]);
  290. FMDBQuickCheck([rs hasAnotherRow]);
  291. FMDBQuickCheck(![db hadError]);
  292. FMDBQuickCheck([[rs stringForColumnIndex:0] isEqualToString:@"one"]);
  293. FMDBQuickCheck([rs intForColumnIndex:1] == 2);
  294. FMDBQuickCheck([rs next]);
  295. FMDBQuickCheck([rs intForColumnIndex:1] == 3);
  296. FMDBQuickCheck(![rs next]);
  297. FMDBQuickCheck(![rs hasAnotherRow]);
  298. }
  299. {
  300. FMDBQuickCheck([db executeUpdate:@"create table t4 (a text, b text)"]);
  301. FMDBQuickCheck(([db executeUpdate:@"insert into t4 (a, b) values (?, ?)", @"one", @"two"]));
  302. rs = [db executeQuery:@"select t4.a as 't4.a', t4.b from t4;"];
  303. FMDBQuickCheck((rs != nil));
  304. [rs next];
  305. FMDBQuickCheck([[rs stringForColumn:@"t4.a"] isEqualToString:@"one"]);
  306. FMDBQuickCheck([[rs stringForColumn:@"b"] isEqualToString:@"two"]);
  307. FMDBQuickCheck(strcmp((const char*)[rs UTF8StringForColumnName:@"b"], "two") == 0);
  308. [rs close];
  309. // let's try these again, with the withArgumentsInArray: variation
  310. FMDBQuickCheck([db executeUpdate:@"drop table t4;" withArgumentsInArray:[NSArray array]]);
  311. FMDBQuickCheck([db executeUpdate:@"create table t4 (a text, b text)" withArgumentsInArray:[NSArray array]]);
  312. FMDBQuickCheck(([db executeUpdate:@"insert into t4 (a, b) values (?, ?)" withArgumentsInArray:[NSArray arrayWithObjects:@"one", @"two", nil]]));
  313. rs = [db executeQuery:@"select t4.a as 't4.a', t4.b from t4;" withArgumentsInArray:[NSArray array]];
  314. FMDBQuickCheck((rs != nil));
  315. [rs next];
  316. FMDBQuickCheck([[rs stringForColumn:@"t4.a"] isEqualToString:@"one"]);
  317. FMDBQuickCheck([[rs stringForColumn:@"b"] isEqualToString:@"two"]);
  318. FMDBQuickCheck(strcmp((const char*)[rs UTF8StringForColumnName:@"b"], "two") == 0);
  319. [rs close];
  320. }
  321. {
  322. FMDBQuickCheck([db tableExists:@"t4"]);
  323. FMDBQuickCheck(![db tableExists:@"thisdoesntexist"]);
  324. rs = [db getSchema];
  325. while ([rs next]) {
  326. FMDBQuickCheck([[rs stringForColumn:@"type"] isEqualToString:@"table"]);
  327. }
  328. }
  329. {
  330. FMDBQuickCheck([db executeUpdate:@"create table t5 (a text, b int, c blob, d text, e text)"]);
  331. FMDBQuickCheck(([db executeUpdateWithFormat:@"insert into t5 values (%s, %d, %@, %c, %lld)", "text", 42, @"BLOB", 'd', 12345678901234]));
  332. rs = [db executeQueryWithFormat:@"select * from t5 where a = %s", "text"];
  333. FMDBQuickCheck((rs != nil));
  334. [rs next];
  335. FMDBQuickCheck([[rs stringForColumn:@"a"] isEqualToString:@"text"]);
  336. FMDBQuickCheck(([rs intForColumn:@"b"] == 42));
  337. FMDBQuickCheck([[rs stringForColumn:@"c"] isEqualToString:@"BLOB"]);
  338. FMDBQuickCheck([[rs stringForColumn:@"d"] isEqualToString:@"d"]);
  339. FMDBQuickCheck(([rs longLongIntForColumn:@"e"] == 12345678901234));
  340. [rs close];
  341. }
  342. {
  343. FMDBQuickCheck([db executeUpdate:@"create table t55 (a text, b int, c float)"]);
  344. short testShort = -4;
  345. float testFloat = 5.5;
  346. FMDBQuickCheck(([db executeUpdateWithFormat:@"insert into t55 values (%c, %hi, %g)", 'a', testShort, testFloat]));
  347. unsigned short testUShort = 6;
  348. FMDBQuickCheck(([db executeUpdateWithFormat:@"insert into t55 values (%c, %hu, %g)", 'a', testUShort, testFloat]));
  349. rs = [db executeQueryWithFormat:@"select * from t55 where a = %s order by 2", "a"];
  350. FMDBQuickCheck((rs != nil));
  351. [rs next];
  352. FMDBQuickCheck([[rs stringForColumn:@"a"] isEqualToString:@"a"]);
  353. FMDBQuickCheck(([rs intForColumn:@"b"] == -4));
  354. FMDBQuickCheck([[rs stringForColumn:@"c"] isEqualToString:@"5.5"]);
  355. [rs next];
  356. FMDBQuickCheck([[rs stringForColumn:@"a"] isEqualToString:@"a"]);
  357. FMDBQuickCheck(([rs intForColumn:@"b"] == 6));
  358. FMDBQuickCheck([[rs stringForColumn:@"c"] isEqualToString:@"5.5"]);
  359. [rs close];
  360. }
  361. {
  362. NSError *err;
  363. FMDBQuickCheck(([db update:@"insert into t5 values (?, ?, ?, ?, ?)" withErrorAndBindings:&err, @"text", [NSNumber numberWithInt:42], @"BLOB", @"d", [NSNumber numberWithInt:0]]));
  364. }
  365. {
  366. // -------------------------------------------------------------------------------
  367. // Named parameters.
  368. FMDBQuickCheck([db executeUpdate:@"create table namedparamtest (a text, b text, c integer, d double)"]);
  369. NSMutableDictionary *dictionaryArgs = [NSMutableDictionary dictionary];
  370. [dictionaryArgs setObject:@"Text1" forKey:@"a"];
  371. [dictionaryArgs setObject:@"Text2" forKey:@"b"];
  372. [dictionaryArgs setObject:[NSNumber numberWithInt:1] forKey:@"c"];
  373. [dictionaryArgs setObject:[NSNumber numberWithDouble:2.0] forKey:@"d"];
  374. FMDBQuickCheck([db executeUpdate:@"insert into namedparamtest values (:a, :b, :c, :d)" withParameterDictionary:dictionaryArgs]);
  375. rs = [db executeQuery:@"select * from namedparamtest"];
  376. FMDBQuickCheck((rs != nil));
  377. [rs next];
  378. FMDBQuickCheck([[rs stringForColumn:@"a"] isEqualToString:@"Text1"]);
  379. FMDBQuickCheck([[rs stringForColumn:@"b"] isEqualToString:@"Text2"]);
  380. FMDBQuickCheck([rs intForColumn:@"c"] == 1);
  381. FMDBQuickCheck([rs doubleForColumn:@"d"] == 2.0);
  382. [rs close];
  383. dictionaryArgs = [NSMutableDictionary dictionary];
  384. [dictionaryArgs setObject:@"Text2" forKey:@"blah"];
  385. rs = [db executeQuery:@"select * from namedparamtest where b = :blah" withParameterDictionary:dictionaryArgs];
  386. FMDBQuickCheck((rs != nil));
  387. FMDBQuickCheck([rs next]);
  388. FMDBQuickCheck([[rs stringForColumn:@"b"] isEqualToString:@"Text2"]);
  389. [rs close];
  390. }
  391. // just for fun.
  392. rs = [db executeQuery:@"PRAGMA database_list"];
  393. while ([rs next]) {
  394. NSString *file = [rs stringForColumn:@"file"];
  395. NSLog(@"database_list: %@", file);
  396. }
  397. // print out some stats if we are using cached statements.
  398. if ([db shouldCacheStatements]) {
  399. NSEnumerator *e = [[db cachedStatements] objectEnumerator];;
  400. FMStatement *statement;
  401. while ((statement = [e nextObject])) {
  402. NSLog(@"%@", statement);
  403. }
  404. }
  405. [db close];
  406. FMDatabasePool *dbPool = [FMDatabasePool databasePoolWithPath:dbPath];
  407. FMDBQuickCheck([dbPool countOfOpenDatabases] == 0);
  408. db = [dbPool db];
  409. FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);
  410. FMDBQuickCheck([db tableExists:@"t4"]);
  411. FMDBQuickCheck(![db pool]);
  412. FMDatabase *db2 = [dbPool db];
  413. FMDBQuickCheck(db2 == db);
  414. db = [dbPool db];
  415. FMDBQuickCheck(db2 != db);
  416. FMDBQuickCheck([db pool]);
  417. FMDBQuickCheck([db2 pool]);
  418. FMDBQuickCheck([dbPool countOfOpenDatabases] == 2);
  419. FMDBQuickCheck([db executeUpdate:@"create table easy (a text)"]);
  420. FMDBQuickCheck([db2 executeUpdate:@"create table easy2 (a text)"]);
  421. db = [dbPool db];
  422. FMDBQuickCheck([dbPool countOfOpenDatabases] == 2);
  423. [db pushToPool];
  424. [[dbPool db] pushToPool];
  425. [[dbPool db] pushToPool];
  426. FMDBQuickCheck([dbPool countOfOpenDatabases] == 2);
  427. [dbPool releaseAllDatabases];
  428. FMDBQuickCheck([dbPool countOfOpenDatabases] == 0);
  429. [dbPool inDatabase:^(FMDatabase *aDb) {
  430. FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 0);
  431. FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 1);
  432. FMDBQuickCheck([aDb tableExists:@"t4"]);
  433. FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 0);
  434. FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 1);
  435. FMDBQuickCheck(([aDb executeUpdate:@"insert into easy (a) values (?)", @"hi"]));
  436. // just for fun.
  437. FMResultSet *rs2 = [aDb executeQuery:@"select * from easy"];
  438. FMDBQuickCheck([rs2 next]);
  439. while ([rs2 next]) { ; } // whatevers.
  440. FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);
  441. FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 0);
  442. FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 1);
  443. }];
  444. FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);
  445. {
  446. db = [[dbPool db] popFromPool];
  447. [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1]];
  448. [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:2]];
  449. [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:3]];
  450. FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 0);
  451. FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 1);
  452. [db pushToPool];
  453. }
  454. {
  455. // double pop!
  456. db = [[dbPool db] popFromPool];
  457. [db popFromPool];
  458. [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1]];
  459. FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 0);
  460. FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 1);
  461. [db pushToPool];
  462. [db pushToPool];
  463. FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 1);
  464. FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 0);
  465. }
  466. [[dbPool db] pushToPool];
  467. FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);
  468. [dbPool setMaximumNumberOfDatabasesToCreate:2];
  469. FMDatabase *adb = [dbPool db];
  470. FMDatabase *bbd = [dbPool db];
  471. FMDBQuickCheck(![dbPool db]);
  472. FMDBQuickCheck([adb tableExists:@"t4"]);
  473. FMDBQuickCheck([bbd tableExists:@"t4"]);
  474. FMDBQuickCheck([dbPool countOfOpenDatabases] == 2);
  475. [dbPool setMaximumNumberOfDatabasesToCreate:0];
  476. adb = [dbPool db];
  477. bbd = [dbPool db];
  478. FMDatabase *cbd = [dbPool db];
  479. FMDBQuickCheck([adb tableExists:@"t4"]);
  480. FMDBQuickCheck([bbd tableExists:@"t4"]);
  481. FMDBQuickCheck([cbd tableExists:@"t4"]);
  482. [dbPool releaseAllDatabases];
  483. FMDBQuickCheck([dbPool countOfOpenDatabases] == 0);
  484. {
  485. db = [dbPool db];
  486. [db beginTransaction];
  487. [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1]];
  488. [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:2]];
  489. [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:3]];
  490. FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 0);
  491. FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 1);
  492. [db popFromPool];
  493. [db commit];
  494. [db pushToPool];
  495. FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 1);
  496. FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 0);
  497. }
  498. [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:3]];
  499. FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);
  500. [dbPool inTransaction:^(FMDatabase *adb, BOOL *rollback) {
  501. [adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1001]];
  502. [adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1002]];
  503. [adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1003]];
  504. FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);
  505. FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 0);
  506. FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 1);
  507. }];
  508. FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);
  509. FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 1);
  510. FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 0);
  511. FMResultSet *rs2 = [[dbPool db] executeQuery:@"select * from easy where a = ?", [NSNumber numberWithInt:1001]];
  512. FMDBQuickCheck([rs2 next]);
  513. FMDBQuickCheck(![rs2 next]);
  514. [dbPool inDeferredTransaction:^(FMDatabase *adb, BOOL *rollback) {
  515. [adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1004]];
  516. [adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1005]];
  517. *rollback = YES;
  518. }];
  519. FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);
  520. FMDBQuickCheck([dbPool countOfCheckedInDatabases] == 1);
  521. FMDBQuickCheck([dbPool countOfCheckedOutDatabases] == 0);
  522. rs2 = [[dbPool db] executeQuery:@"select * from easy where a = ?", [NSNumber numberWithInt:1004]];
  523. FMDBQuickCheck(![rs2 next]);
  524. rs2 = [[dbPool db] executeQuery:@"select * from easy where a = ?", [NSNumber numberWithInt:1005]];
  525. FMDBQuickCheck(![rs2 next]);
  526. FMDBQuickCheck([dbPool countOfOpenDatabases] == 1);
  527. err = [dbPool inSavePoint:^(FMDatabase *db, BOOL *rollback) {
  528. FMDBQuickCheck(![adb hadError]);
  529. [adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1006]];
  530. }];
  531. rs2 = [[dbPool db] executeQuery:@"select * from easy where a = ?", [NSNumber numberWithInt:1006]];
  532. FMDBQuickCheck([rs2 next]);
  533. [rs2 close];
  534. {
  535. db = [dbPool db];
  536. FMDBQuickCheck([db startSavePointWithName:@"a" error:nil]);
  537. [db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1007]];
  538. FMDBQuickCheck([db startSavePointWithName:@"b" error:nil]);
  539. FMDBQuickCheck(([db executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1008]]));
  540. FMDBQuickCheck([db releaseSavePointWithName:@"b" error:nil]);
  541. FMDBQuickCheck([db releaseSavePointWithName:@"a" error:nil]);
  542. rs2 = [[dbPool db] executeQuery:@"select * from easy where a = ?", [NSNumber numberWithInt:1007]];
  543. FMDBQuickCheck([rs2 next]);
  544. FMDBQuickCheck(![rs2 next]); // close it out.
  545. rs2 = [[dbPool db] executeQuery:@"select * from easy where a = ?", [NSNumber numberWithInt:1008]];
  546. FMDBQuickCheck([rs2 next]);
  547. FMDBQuickCheck(![rs2 next]); // close it out.
  548. }
  549. {
  550. err = [dbPool inSavePoint:^(FMDatabase *adb, BOOL *rollback) {
  551. FMDBQuickCheck(![adb hadError]);
  552. [adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1009]];
  553. [adb inSavePoint:^(BOOL *rollback) {
  554. FMDBQuickCheck(([adb executeUpdate:@"insert into easy values (?)", [NSNumber numberWithInt:1010]]));
  555. *rollback = YES;
  556. }];
  557. }];
  558. rs2 = [[dbPool db] executeQuery:@"select * from easy where a = ?", [NSNumber numberWithInt:1009]];
  559. FMDBQuickCheck([rs2 next]);
  560. FMDBQuickCheck(![rs2 next]); // close it out.
  561. rs2 = [[dbPool db] executeQuery:@"select * from easy where a = ?", [NSNumber numberWithInt:1010]];
  562. FMDBQuickCheck(![rs2 next]);
  563. }
  564. {
  565. [dbPool inDatabase:^(FMDatabase *db) {
  566. [db executeUpdate:@"create table likefoo (foo text)"];
  567. [db executeUpdate:@"insert into likefoo values ('hi')"];
  568. [db executeUpdate:@"insert into likefoo values ('hello')"];
  569. [db executeUpdate:@"insert into likefoo values ('not')"];
  570. int count = 0;
  571. FMResultSet *rsl = [db executeQuery:@"select * from likefoo where foo like 'h%'"];
  572. while ([rsl next]) {
  573. count++;
  574. }
  575. FMDBQuickCheck(count == 2);
  576. count = 0;
  577. rsl = [db executeQuery:@"select * from likefoo where foo like ?", @"h%"];
  578. while ([rsl next]) {
  579. count++;
  580. }
  581. FMDBQuickCheck(count == 2);
  582. }];
  583. }
  584. NSLog(@"That was version %@ of sqlite", [FMDatabase sqliteLibVersion]);
  585. [pool release];
  586. return 0;
  587. }