FMDatabase.m 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596
  1. #import "FMDatabase.h"
  2. #import "unistd.h"
  3. #import <objc/runtime.h>
  4. #if FMDB_SQLITE_STANDALONE
  5. #import <sqlite3/sqlite3.h>
  6. #else
  7. #import <sqlite3.h>
  8. #endif
  9. @interface FMDatabase () {
  10. void* _db;
  11. BOOL _isExecutingStatement;
  12. NSTimeInterval _startBusyRetryTime;
  13. NSMutableSet *_openResultSets;
  14. NSMutableSet *_openFunctions;
  15. NSDateFormatter *_dateFormat;
  16. }
  17. NS_ASSUME_NONNULL_BEGIN
  18. - (FMResultSet * _Nullable)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray * _Nullable)arrayArgs orDictionary:(NSDictionary * _Nullable)dictionaryArgs orVAList:(va_list)args;
  19. - (BOOL)executeUpdate:(NSString *)sql error:(NSError * _Nullable *)outErr withArgumentsInArray:(NSArray * _Nullable)arrayArgs orDictionary:(NSDictionary * _Nullable)dictionaryArgs orVAList:(va_list)args;
  20. NS_ASSUME_NONNULL_END
  21. @end
  22. @implementation FMDatabase
  23. // Because these two properties have all of their accessor methods implemented,
  24. // we have to synthesize them to get the corresponding ivars. The rest of the
  25. // properties have their ivars synthesized automatically for us.
  26. @synthesize shouldCacheStatements = _shouldCacheStatements;
  27. @synthesize maxBusyRetryTimeInterval = _maxBusyRetryTimeInterval;
  28. #pragma mark FMDatabase instantiation and deallocation
  29. + (instancetype)databaseWithPath:(NSString *)aPath {
  30. return FMDBReturnAutoreleased([[self alloc] initWithPath:aPath]);
  31. }
  32. + (instancetype)databaseWithURL:(NSURL *)url {
  33. return FMDBReturnAutoreleased([[self alloc] initWithURL:url]);
  34. }
  35. - (instancetype)init {
  36. return [self initWithPath:nil];
  37. }
  38. - (instancetype)initWithURL:(NSURL *)url {
  39. return [self initWithPath:url.path];
  40. }
  41. - (instancetype)initWithPath:(NSString *)path {
  42. assert(sqlite3_threadsafe()); // whoa there big boy- gotta make sure sqlite it happy with what we're going to do.
  43. self = [super init];
  44. if (self) {
  45. _databasePath = [path copy];
  46. _openResultSets = [[NSMutableSet alloc] init];
  47. _db = nil;
  48. _logsErrors = YES;
  49. _crashOnErrors = NO;
  50. _maxBusyRetryTimeInterval = 2;
  51. }
  52. return self;
  53. }
  54. #if ! __has_feature(objc_arc)
  55. - (void)finalize {
  56. [self close];
  57. [super finalize];
  58. }
  59. #endif
  60. - (void)dealloc {
  61. [self close];
  62. FMDBRelease(_openResultSets);
  63. FMDBRelease(_cachedStatements);
  64. FMDBRelease(_dateFormat);
  65. FMDBRelease(_databasePath);
  66. FMDBRelease(_openFunctions);
  67. #if ! __has_feature(objc_arc)
  68. [super dealloc];
  69. #endif
  70. }
  71. - (NSURL *)databaseURL {
  72. return _databasePath ? [NSURL fileURLWithPath:_databasePath] : nil;
  73. }
  74. + (NSString*)FMDBUserVersion {
  75. return @"2.7.2";
  76. }
  77. // returns 0x0240 for version 2.4. This makes it super easy to do things like:
  78. // /* need to make sure to do X with FMDB version 2.4 or later */
  79. // if ([FMDatabase FMDBVersion] >= 0x0240) { … }
  80. + (SInt32)FMDBVersion {
  81. // we go through these hoops so that we only have to change the version number in a single spot.
  82. static dispatch_once_t once;
  83. static SInt32 FMDBVersionVal = 0;
  84. dispatch_once(&once, ^{
  85. NSString *prodVersion = [self FMDBUserVersion];
  86. if ([[prodVersion componentsSeparatedByString:@"."] count] < 3) {
  87. prodVersion = [prodVersion stringByAppendingString:@".0"];
  88. }
  89. NSString *junk = [prodVersion stringByReplacingOccurrencesOfString:@"." withString:@""];
  90. char *e = nil;
  91. FMDBVersionVal = (int) strtoul([junk UTF8String], &e, 16);
  92. });
  93. return FMDBVersionVal;
  94. }
  95. #pragma mark SQLite information
  96. + (NSString*)sqliteLibVersion {
  97. return [NSString stringWithFormat:@"%s", sqlite3_libversion()];
  98. }
  99. + (BOOL)isSQLiteThreadSafe {
  100. // make sure to read the sqlite headers on this guy!
  101. return sqlite3_threadsafe() != 0;
  102. }
  103. - (void*)sqliteHandle {
  104. return _db;
  105. }
  106. - (const char*)sqlitePath {
  107. if (!_databasePath) {
  108. return ":memory:";
  109. }
  110. if ([_databasePath length] == 0) {
  111. return ""; // this creates a temporary database (it's an sqlite thing).
  112. }
  113. return [_databasePath fileSystemRepresentation];
  114. }
  115. #pragma mark Open and close database
  116. - (BOOL)open {
  117. if (_db) {
  118. return YES;
  119. }
  120. int err = sqlite3_open([self sqlitePath], (sqlite3**)&_db );
  121. if(err != SQLITE_OK) {
  122. NSLog(@"error opening!: %d", err);
  123. return NO;
  124. }
  125. if (_maxBusyRetryTimeInterval > 0.0) {
  126. // set the handler
  127. [self setMaxBusyRetryTimeInterval:_maxBusyRetryTimeInterval];
  128. }
  129. return YES;
  130. }
  131. - (BOOL)openWithFlags:(int)flags {
  132. return [self openWithFlags:flags vfs:nil];
  133. }
  134. - (BOOL)openWithFlags:(int)flags vfs:(NSString *)vfsName {
  135. #if SQLITE_VERSION_NUMBER >= 3005000
  136. if (_db) {
  137. return YES;
  138. }
  139. int err = sqlite3_open_v2([self sqlitePath], (sqlite3**)&_db, flags, [vfsName UTF8String]);
  140. if(err != SQLITE_OK) {
  141. NSLog(@"error opening!: %d", err);
  142. return NO;
  143. }
  144. if (_maxBusyRetryTimeInterval > 0.0) {
  145. // set the handler
  146. [self setMaxBusyRetryTimeInterval:_maxBusyRetryTimeInterval];
  147. }
  148. return YES;
  149. #else
  150. NSLog(@"openWithFlags requires SQLite 3.5");
  151. return NO;
  152. #endif
  153. }
  154. - (BOOL)close {
  155. [self clearCachedStatements];
  156. [self closeOpenResultSets];
  157. if (!_db) {
  158. return YES;
  159. }
  160. int rc;
  161. BOOL retry;
  162. BOOL triedFinalizingOpenStatements = NO;
  163. do {
  164. retry = NO;
  165. rc = sqlite3_close(_db);
  166. if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) {
  167. if (!triedFinalizingOpenStatements) {
  168. triedFinalizingOpenStatements = YES;
  169. sqlite3_stmt *pStmt;
  170. while ((pStmt = sqlite3_next_stmt(_db, nil)) !=0) {
  171. NSLog(@"Closing leaked statement");
  172. sqlite3_finalize(pStmt);
  173. retry = YES;
  174. }
  175. }
  176. }
  177. else if (SQLITE_OK != rc) {
  178. NSLog(@"error closing!: %d", rc);
  179. }
  180. }
  181. while (retry);
  182. _db = nil;
  183. return YES;
  184. }
  185. #pragma mark Busy handler routines
  186. // NOTE: appledoc seems to choke on this function for some reason;
  187. // so when generating documentation, you might want to ignore the
  188. // .m files so that it only documents the public interfaces outlined
  189. // in the .h files.
  190. //
  191. // This is a known appledoc bug that it has problems with C functions
  192. // within a class implementation, but for some reason, only this
  193. // C function causes problems; the rest don't. Anyway, ignoring the .m
  194. // files with appledoc will prevent this problem from occurring.
  195. static int FMDBDatabaseBusyHandler(void *f, int count) {
  196. FMDatabase *self = (__bridge FMDatabase*)f;
  197. if (count == 0) {
  198. self->_startBusyRetryTime = [NSDate timeIntervalSinceReferenceDate];
  199. return 1;
  200. }
  201. NSTimeInterval delta = [NSDate timeIntervalSinceReferenceDate] - (self->_startBusyRetryTime);
  202. if (delta < [self maxBusyRetryTimeInterval]) {
  203. int requestedSleepInMillseconds = (int) arc4random_uniform(50) + 50;
  204. int actualSleepInMilliseconds = sqlite3_sleep(requestedSleepInMillseconds);
  205. if (actualSleepInMilliseconds != requestedSleepInMillseconds) {
  206. NSLog(@"WARNING: Requested sleep of %i milliseconds, but SQLite returned %i. Maybe SQLite wasn't built with HAVE_USLEEP=1?", requestedSleepInMillseconds, actualSleepInMilliseconds);
  207. }
  208. return 1;
  209. }
  210. return 0;
  211. }
  212. - (void)setMaxBusyRetryTimeInterval:(NSTimeInterval)timeout {
  213. _maxBusyRetryTimeInterval = timeout;
  214. if (!_db) {
  215. return;
  216. }
  217. if (timeout > 0) {
  218. sqlite3_busy_handler(_db, &FMDBDatabaseBusyHandler, (__bridge void *)(self));
  219. }
  220. else {
  221. // turn it off otherwise
  222. sqlite3_busy_handler(_db, nil, nil);
  223. }
  224. }
  225. - (NSTimeInterval)maxBusyRetryTimeInterval {
  226. return _maxBusyRetryTimeInterval;
  227. }
  228. // we no longer make busyRetryTimeout public
  229. // but for folks who don't bother noticing that the interface to FMDatabase changed,
  230. // we'll still implement the method so they don't get suprise crashes
  231. - (int)busyRetryTimeout {
  232. NSLog(@"%s:%d", __FUNCTION__, __LINE__);
  233. NSLog(@"FMDB: busyRetryTimeout no longer works, please use maxBusyRetryTimeInterval");
  234. return -1;
  235. }
  236. - (void)setBusyRetryTimeout:(int)i {
  237. #pragma unused(i)
  238. NSLog(@"%s:%d", __FUNCTION__, __LINE__);
  239. NSLog(@"FMDB: setBusyRetryTimeout does nothing, please use setMaxBusyRetryTimeInterval:");
  240. }
  241. #pragma mark Result set functions
  242. - (BOOL)hasOpenResultSets {
  243. return [_openResultSets count] > 0;
  244. }
  245. - (void)closeOpenResultSets {
  246. //Copy the set so we don't get mutation errors
  247. NSSet *openSetCopy = FMDBReturnAutoreleased([_openResultSets copy]);
  248. for (NSValue *rsInWrappedInATastyValueMeal in openSetCopy) {
  249. FMResultSet *rs = (FMResultSet *)[rsInWrappedInATastyValueMeal pointerValue];
  250. [rs setParentDB:nil];
  251. [rs close];
  252. [_openResultSets removeObject:rsInWrappedInATastyValueMeal];
  253. }
  254. }
  255. - (void)resultSetDidClose:(FMResultSet *)resultSet {
  256. NSValue *setValue = [NSValue valueWithNonretainedObject:resultSet];
  257. [_openResultSets removeObject:setValue];
  258. }
  259. #pragma mark Cached statements
  260. - (void)clearCachedStatements {
  261. for (NSMutableSet *statements in [_cachedStatements objectEnumerator]) {
  262. for (FMStatement *statement in [statements allObjects]) {
  263. [statement close];
  264. }
  265. }
  266. [_cachedStatements removeAllObjects];
  267. }
  268. - (FMStatement*)cachedStatementForQuery:(NSString*)query {
  269. NSMutableSet* statements = [_cachedStatements objectForKey:query];
  270. return [[statements objectsPassingTest:^BOOL(FMStatement* statement, BOOL *stop) {
  271. *stop = ![statement inUse];
  272. return *stop;
  273. }] anyObject];
  274. }
  275. - (void)setCachedStatement:(FMStatement*)statement forQuery:(NSString*)query {
  276. query = [query copy]; // in case we got handed in a mutable string...
  277. [statement setQuery:query];
  278. NSMutableSet* statements = [_cachedStatements objectForKey:query];
  279. if (!statements) {
  280. statements = [NSMutableSet set];
  281. }
  282. [statements addObject:statement];
  283. [_cachedStatements setObject:statements forKey:query];
  284. FMDBRelease(query);
  285. }
  286. #pragma mark Key routines
  287. - (BOOL)rekey:(NSString*)key {
  288. NSData *keyData = [NSData dataWithBytes:(void *)[key UTF8String] length:(NSUInteger)strlen([key UTF8String])];
  289. return [self rekeyWithData:keyData];
  290. }
  291. - (BOOL)rekeyWithData:(NSData *)keyData {
  292. #ifdef SQLITE_HAS_CODEC
  293. if (!keyData) {
  294. return NO;
  295. }
  296. int rc = sqlite3_rekey(_db, [keyData bytes], (int)[keyData length]);
  297. if (rc != SQLITE_OK) {
  298. NSLog(@"error on rekey: %d", rc);
  299. NSLog(@"%@", [self lastErrorMessage]);
  300. }
  301. return (rc == SQLITE_OK);
  302. #else
  303. #pragma unused(keyData)
  304. return NO;
  305. #endif
  306. }
  307. - (BOOL)setKey:(NSString*)key {
  308. NSData *keyData = [NSData dataWithBytes:[key UTF8String] length:(NSUInteger)strlen([key UTF8String])];
  309. return [self setKeyWithData:keyData];
  310. }
  311. - (BOOL)setKeyWithData:(NSData *)keyData {
  312. #ifdef SQLITE_HAS_CODEC
  313. if (!keyData) {
  314. return NO;
  315. }
  316. int rc = sqlite3_key(_db, [keyData bytes], (int)[keyData length]);
  317. return (rc == SQLITE_OK);
  318. #else
  319. #pragma unused(keyData)
  320. return NO;
  321. #endif
  322. }
  323. #pragma mark Date routines
  324. + (NSDateFormatter *)storeableDateFormat:(NSString *)format {
  325. NSDateFormatter *result = FMDBReturnAutoreleased([[NSDateFormatter alloc] init]);
  326. result.dateFormat = format;
  327. result.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
  328. result.locale = FMDBReturnAutoreleased([[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]);
  329. return result;
  330. }
  331. - (BOOL)hasDateFormatter {
  332. return _dateFormat != nil;
  333. }
  334. - (void)setDateFormat:(NSDateFormatter *)format {
  335. FMDBAutorelease(_dateFormat);
  336. _dateFormat = FMDBReturnRetained(format);
  337. }
  338. - (NSDate *)dateFromString:(NSString *)s {
  339. return [_dateFormat dateFromString:s];
  340. }
  341. - (NSString *)stringFromDate:(NSDate *)date {
  342. return [_dateFormat stringFromDate:date];
  343. }
  344. #pragma mark State of database
  345. - (BOOL)goodConnection {
  346. if (!_db) {
  347. return NO;
  348. }
  349. FMResultSet *rs = [self executeQuery:@"select name from sqlite_master where type='table'"];
  350. if (rs) {
  351. [rs close];
  352. return YES;
  353. }
  354. return NO;
  355. }
  356. - (void)warnInUse {
  357. NSLog(@"The FMDatabase %@ is currently in use.", self);
  358. #ifndef NS_BLOCK_ASSERTIONS
  359. if (_crashOnErrors) {
  360. NSAssert(false, @"The FMDatabase %@ is currently in use.", self);
  361. abort();
  362. }
  363. #endif
  364. }
  365. - (BOOL)databaseExists {
  366. if (!_db) {
  367. NSLog(@"The FMDatabase %@ is not open.", self);
  368. #ifndef NS_BLOCK_ASSERTIONS
  369. if (_crashOnErrors) {
  370. NSAssert(false, @"The FMDatabase %@ is not open.", self);
  371. abort();
  372. }
  373. #endif
  374. return NO;
  375. }
  376. return YES;
  377. }
  378. #pragma mark Error routines
  379. - (NSString *)lastErrorMessage {
  380. return [NSString stringWithUTF8String:sqlite3_errmsg(_db)];
  381. }
  382. - (BOOL)hadError {
  383. int lastErrCode = [self lastErrorCode];
  384. return (lastErrCode > SQLITE_OK && lastErrCode < SQLITE_ROW);
  385. }
  386. - (int)lastErrorCode {
  387. return sqlite3_errcode(_db);
  388. }
  389. - (int)lastExtendedErrorCode {
  390. return sqlite3_extended_errcode(_db);
  391. }
  392. - (NSError*)errorWithMessage:(NSString *)message {
  393. NSDictionary* errorMessage = [NSDictionary dictionaryWithObject:message forKey:NSLocalizedDescriptionKey];
  394. return [NSError errorWithDomain:@"FMDatabase" code:sqlite3_errcode(_db) userInfo:errorMessage];
  395. }
  396. - (NSError*)lastError {
  397. return [self errorWithMessage:[self lastErrorMessage]];
  398. }
  399. #pragma mark Update information routines
  400. - (sqlite_int64)lastInsertRowId {
  401. if (_isExecutingStatement) {
  402. [self warnInUse];
  403. return NO;
  404. }
  405. _isExecutingStatement = YES;
  406. sqlite_int64 ret = sqlite3_last_insert_rowid(_db);
  407. _isExecutingStatement = NO;
  408. return ret;
  409. }
  410. - (int)changes {
  411. if (_isExecutingStatement) {
  412. [self warnInUse];
  413. return 0;
  414. }
  415. _isExecutingStatement = YES;
  416. int ret = sqlite3_changes(_db);
  417. _isExecutingStatement = NO;
  418. return ret;
  419. }
  420. #pragma mark SQL manipulation
  421. - (void)bindObject:(id)obj toColumn:(int)idx inStatement:(sqlite3_stmt*)pStmt {
  422. if ((!obj) || ((NSNull *)obj == [NSNull null])) {
  423. sqlite3_bind_null(pStmt, idx);
  424. }
  425. // FIXME - someday check the return codes on these binds.
  426. else if ([obj isKindOfClass:[NSData class]]) {
  427. const void *bytes = [obj bytes];
  428. if (!bytes) {
  429. // it's an empty NSData object, aka [NSData data].
  430. // Don't pass a NULL pointer, or sqlite will bind a SQL null instead of a blob.
  431. bytes = "";
  432. }
  433. sqlite3_bind_blob(pStmt, idx, bytes, (int)[obj length], SQLITE_STATIC);
  434. }
  435. else if ([obj isKindOfClass:[NSDate class]]) {
  436. if (self.hasDateFormatter)
  437. sqlite3_bind_text(pStmt, idx, [[self stringFromDate:obj] UTF8String], -1, SQLITE_STATIC);
  438. else
  439. sqlite3_bind_double(pStmt, idx, [obj timeIntervalSince1970]);
  440. }
  441. else if ([obj isKindOfClass:[NSNumber class]]) {
  442. if (strcmp([obj objCType], @encode(char)) == 0) {
  443. sqlite3_bind_int(pStmt, idx, [obj charValue]);
  444. }
  445. else if (strcmp([obj objCType], @encode(unsigned char)) == 0) {
  446. sqlite3_bind_int(pStmt, idx, [obj unsignedCharValue]);
  447. }
  448. else if (strcmp([obj objCType], @encode(short)) == 0) {
  449. sqlite3_bind_int(pStmt, idx, [obj shortValue]);
  450. }
  451. else if (strcmp([obj objCType], @encode(unsigned short)) == 0) {
  452. sqlite3_bind_int(pStmt, idx, [obj unsignedShortValue]);
  453. }
  454. else if (strcmp([obj objCType], @encode(int)) == 0) {
  455. sqlite3_bind_int(pStmt, idx, [obj intValue]);
  456. }
  457. else if (strcmp([obj objCType], @encode(unsigned int)) == 0) {
  458. sqlite3_bind_int64(pStmt, idx, (long long)[obj unsignedIntValue]);
  459. }
  460. else if (strcmp([obj objCType], @encode(long)) == 0) {
  461. sqlite3_bind_int64(pStmt, idx, [obj longValue]);
  462. }
  463. else if (strcmp([obj objCType], @encode(unsigned long)) == 0) {
  464. sqlite3_bind_int64(pStmt, idx, (long long)[obj unsignedLongValue]);
  465. }
  466. else if (strcmp([obj objCType], @encode(long long)) == 0) {
  467. sqlite3_bind_int64(pStmt, idx, [obj longLongValue]);
  468. }
  469. else if (strcmp([obj objCType], @encode(unsigned long long)) == 0) {
  470. sqlite3_bind_int64(pStmt, idx, (long long)[obj unsignedLongLongValue]);
  471. }
  472. else if (strcmp([obj objCType], @encode(float)) == 0) {
  473. sqlite3_bind_double(pStmt, idx, [obj floatValue]);
  474. }
  475. else if (strcmp([obj objCType], @encode(double)) == 0) {
  476. sqlite3_bind_double(pStmt, idx, [obj doubleValue]);
  477. }
  478. else if (strcmp([obj objCType], @encode(BOOL)) == 0) {
  479. sqlite3_bind_int(pStmt, idx, ([obj boolValue] ? 1 : 0));
  480. }
  481. else {
  482. sqlite3_bind_text(pStmt, idx, [[obj description] UTF8String], -1, SQLITE_STATIC);
  483. }
  484. }
  485. else {
  486. sqlite3_bind_text(pStmt, idx, [[obj description] UTF8String], -1, SQLITE_STATIC);
  487. }
  488. }
  489. - (void)extractSQL:(NSString *)sql argumentsList:(va_list)args intoString:(NSMutableString *)cleanedSQL arguments:(NSMutableArray *)arguments {
  490. NSUInteger length = [sql length];
  491. unichar last = '\0';
  492. for (NSUInteger i = 0; i < length; ++i) {
  493. id arg = nil;
  494. unichar current = [sql characterAtIndex:i];
  495. unichar add = current;
  496. if (last == '%') {
  497. switch (current) {
  498. case '@':
  499. arg = va_arg(args, id);
  500. break;
  501. case 'c':
  502. // warning: second argument to 'va_arg' is of promotable type 'char'; this va_arg has undefined behavior because arguments will be promoted to 'int'
  503. arg = [NSString stringWithFormat:@"%c", va_arg(args, int)];
  504. break;
  505. case 's':
  506. arg = [NSString stringWithUTF8String:va_arg(args, char*)];
  507. break;
  508. case 'd':
  509. case 'D':
  510. case 'i':
  511. arg = [NSNumber numberWithInt:va_arg(args, int)];
  512. break;
  513. case 'u':
  514. case 'U':
  515. arg = [NSNumber numberWithUnsignedInt:va_arg(args, unsigned int)];
  516. break;
  517. case 'h':
  518. i++;
  519. if (i < length && [sql characterAtIndex:i] == 'i') {
  520. // warning: second argument to 'va_arg' is of promotable type 'short'; this va_arg has undefined behavior because arguments will be promoted to 'int'
  521. arg = [NSNumber numberWithShort:(short)(va_arg(args, int))];
  522. }
  523. else if (i < length && [sql characterAtIndex:i] == 'u') {
  524. // warning: second argument to 'va_arg' is of promotable type 'unsigned short'; this va_arg has undefined behavior because arguments will be promoted to 'int'
  525. arg = [NSNumber numberWithUnsignedShort:(unsigned short)(va_arg(args, uint))];
  526. }
  527. else {
  528. i--;
  529. }
  530. break;
  531. case 'q':
  532. i++;
  533. if (i < length && [sql characterAtIndex:i] == 'i') {
  534. arg = [NSNumber numberWithLongLong:va_arg(args, long long)];
  535. }
  536. else if (i < length && [sql characterAtIndex:i] == 'u') {
  537. arg = [NSNumber numberWithUnsignedLongLong:va_arg(args, unsigned long long)];
  538. }
  539. else {
  540. i--;
  541. }
  542. break;
  543. case 'f':
  544. arg = [NSNumber numberWithDouble:va_arg(args, double)];
  545. break;
  546. case 'g':
  547. // warning: second argument to 'va_arg' is of promotable type 'float'; this va_arg has undefined behavior because arguments will be promoted to 'double'
  548. arg = [NSNumber numberWithFloat:(float)(va_arg(args, double))];
  549. break;
  550. case 'l':
  551. i++;
  552. if (i < length) {
  553. unichar next = [sql characterAtIndex:i];
  554. if (next == 'l') {
  555. i++;
  556. if (i < length && [sql characterAtIndex:i] == 'd') {
  557. //%lld
  558. arg = [NSNumber numberWithLongLong:va_arg(args, long long)];
  559. }
  560. else if (i < length && [sql characterAtIndex:i] == 'u') {
  561. //%llu
  562. arg = [NSNumber numberWithUnsignedLongLong:va_arg(args, unsigned long long)];
  563. }
  564. else {
  565. i--;
  566. }
  567. }
  568. else if (next == 'd') {
  569. //%ld
  570. arg = [NSNumber numberWithLong:va_arg(args, long)];
  571. }
  572. else if (next == 'u') {
  573. //%lu
  574. arg = [NSNumber numberWithUnsignedLong:va_arg(args, unsigned long)];
  575. }
  576. else {
  577. i--;
  578. }
  579. }
  580. else {
  581. i--;
  582. }
  583. break;
  584. default:
  585. // something else that we can't interpret. just pass it on through like normal
  586. break;
  587. }
  588. }
  589. else if (current == '%') {
  590. // percent sign; skip this character
  591. add = '\0';
  592. }
  593. if (arg != nil) {
  594. [cleanedSQL appendString:@"?"];
  595. [arguments addObject:arg];
  596. }
  597. else if (add == (unichar)'@' && last == (unichar) '%') {
  598. [cleanedSQL appendFormat:@"NULL"];
  599. }
  600. else if (add != '\0') {
  601. [cleanedSQL appendFormat:@"%C", add];
  602. }
  603. last = current;
  604. }
  605. }
  606. #pragma mark Execute queries
  607. - (FMResultSet *)executeQuery:(NSString *)sql withParameterDictionary:(NSDictionary *)arguments {
  608. return [self executeQuery:sql withArgumentsInArray:nil orDictionary:arguments orVAList:nil];
  609. }
  610. - (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args {
  611. if (![self databaseExists]) {
  612. return 0x00;
  613. }
  614. if (_isExecutingStatement) {
  615. [self warnInUse];
  616. return 0x00;
  617. }
  618. _isExecutingStatement = YES;
  619. int rc = 0x00;
  620. sqlite3_stmt *pStmt = 0x00;
  621. FMStatement *statement = 0x00;
  622. FMResultSet *rs = 0x00;
  623. if (_traceExecution && sql) {
  624. NSLog(@"%@ executeQuery: %@", self, sql);
  625. }
  626. if (_shouldCacheStatements) {
  627. statement = [self cachedStatementForQuery:sql];
  628. pStmt = statement ? [statement statement] : 0x00;
  629. [statement reset];
  630. }
  631. if (!pStmt) {
  632. rc = sqlite3_prepare_v2(_db, [sql UTF8String], -1, &pStmt, 0);
  633. if (SQLITE_OK != rc) {
  634. if (_logsErrors) {
  635. NSLog(@"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]);
  636. NSLog(@"DB Query: %@", sql);
  637. NSLog(@"DB Path: %@", _databasePath);
  638. }
  639. if (_crashOnErrors) {
  640. NSAssert(false, @"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]);
  641. abort();
  642. }
  643. sqlite3_finalize(pStmt);
  644. _isExecutingStatement = NO;
  645. return nil;
  646. }
  647. }
  648. id obj;
  649. int idx = 0;
  650. int queryCount = sqlite3_bind_parameter_count(pStmt); // pointed out by Dominic Yu (thanks!)
  651. // If dictionaryArgs is passed in, that means we are using sqlite's named parameter support
  652. if (dictionaryArgs) {
  653. for (NSString *dictionaryKey in [dictionaryArgs allKeys]) {
  654. // Prefix the key with a colon.
  655. NSString *parameterName = [[NSString alloc] initWithFormat:@":%@", dictionaryKey];
  656. if (_traceExecution) {
  657. NSLog(@"%@ = %@", parameterName, [dictionaryArgs objectForKey:dictionaryKey]);
  658. }
  659. // Get the index for the parameter name.
  660. int namedIdx = sqlite3_bind_parameter_index(pStmt, [parameterName UTF8String]);
  661. FMDBRelease(parameterName);
  662. if (namedIdx > 0) {
  663. // Standard binding from here.
  664. [self bindObject:[dictionaryArgs objectForKey:dictionaryKey] toColumn:namedIdx inStatement:pStmt];
  665. // increment the binding count, so our check below works out
  666. idx++;
  667. }
  668. else {
  669. NSLog(@"Could not find index for %@", dictionaryKey);
  670. }
  671. }
  672. }
  673. else {
  674. while (idx < queryCount) {
  675. if (arrayArgs && idx < (int)[arrayArgs count]) {
  676. obj = [arrayArgs objectAtIndex:(NSUInteger)idx];
  677. }
  678. else if (args) {
  679. obj = va_arg(args, id);
  680. }
  681. else {
  682. //We ran out of arguments
  683. break;
  684. }
  685. if (_traceExecution) {
  686. if ([obj isKindOfClass:[NSData class]]) {
  687. NSLog(@"data: %ld bytes", (unsigned long)[(NSData*)obj length]);
  688. }
  689. else {
  690. NSLog(@"obj: %@", obj);
  691. }
  692. }
  693. idx++;
  694. [self bindObject:obj toColumn:idx inStatement:pStmt];
  695. }
  696. }
  697. if (idx != queryCount) {
  698. NSLog(@"Error: the bind count is not correct for the # of variables (executeQuery)");
  699. sqlite3_finalize(pStmt);
  700. _isExecutingStatement = NO;
  701. return nil;
  702. }
  703. FMDBRetain(statement); // to balance the release below
  704. if (!statement) {
  705. statement = [[FMStatement alloc] init];
  706. [statement setStatement:pStmt];
  707. if (_shouldCacheStatements && sql) {
  708. [self setCachedStatement:statement forQuery:sql];
  709. }
  710. }
  711. // the statement gets closed in rs's dealloc or [rs close];
  712. rs = [FMResultSet resultSetWithStatement:statement usingParentDatabase:self];
  713. [rs setQuery:sql];
  714. NSValue *openResultSet = [NSValue valueWithNonretainedObject:rs];
  715. [_openResultSets addObject:openResultSet];
  716. [statement setUseCount:[statement useCount] + 1];
  717. FMDBRelease(statement);
  718. _isExecutingStatement = NO;
  719. return rs;
  720. }
  721. - (FMResultSet *)executeQuery:(NSString*)sql, ... {
  722. va_list args;
  723. va_start(args, sql);
  724. id result = [self executeQuery:sql withArgumentsInArray:nil orDictionary:nil orVAList:args];
  725. va_end(args);
  726. return result;
  727. }
  728. - (FMResultSet *)executeQueryWithFormat:(NSString*)format, ... {
  729. va_list args;
  730. va_start(args, format);
  731. NSMutableString *sql = [NSMutableString stringWithCapacity:[format length]];
  732. NSMutableArray *arguments = [NSMutableArray array];
  733. [self extractSQL:format argumentsList:args intoString:sql arguments:arguments];
  734. va_end(args);
  735. return [self executeQuery:sql withArgumentsInArray:arguments];
  736. }
  737. - (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments {
  738. return [self executeQuery:sql withArgumentsInArray:arguments orDictionary:nil orVAList:nil];
  739. }
  740. - (FMResultSet *)executeQuery:(NSString *)sql values:(NSArray *)values error:(NSError * __autoreleasing *)error {
  741. FMResultSet *rs = [self executeQuery:sql withArgumentsInArray:values orDictionary:nil orVAList:nil];
  742. if (!rs && error) {
  743. *error = [self lastError];
  744. }
  745. return rs;
  746. }
  747. - (FMResultSet *)executeQuery:(NSString*)sql withVAList:(va_list)args {
  748. return [self executeQuery:sql withArgumentsInArray:nil orDictionary:nil orVAList:args];
  749. }
  750. #pragma mark Execute updates
  751. - (BOOL)executeUpdate:(NSString*)sql error:(NSError**)outErr withArgumentsInArray:(NSArray*)arrayArgs orDictionary:(NSDictionary *)dictionaryArgs orVAList:(va_list)args {
  752. if (![self databaseExists]) {
  753. return NO;
  754. }
  755. if (_isExecutingStatement) {
  756. [self warnInUse];
  757. return NO;
  758. }
  759. _isExecutingStatement = YES;
  760. int rc = 0x00;
  761. sqlite3_stmt *pStmt = 0x00;
  762. FMStatement *cachedStmt = 0x00;
  763. if (_traceExecution && sql) {
  764. NSLog(@"%@ executeUpdate: %@", self, sql);
  765. }
  766. if (_shouldCacheStatements) {
  767. cachedStmt = [self cachedStatementForQuery:sql];
  768. pStmt = cachedStmt ? [cachedStmt statement] : 0x00;
  769. [cachedStmt reset];
  770. }
  771. if (!pStmt) {
  772. rc = sqlite3_prepare_v2(_db, [sql UTF8String], -1, &pStmt, 0);
  773. if (SQLITE_OK != rc) {
  774. if (_logsErrors) {
  775. NSLog(@"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]);
  776. NSLog(@"DB Query: %@", sql);
  777. NSLog(@"DB Path: %@", _databasePath);
  778. }
  779. if (_crashOnErrors) {
  780. NSAssert(false, @"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]);
  781. abort();
  782. }
  783. if (outErr) {
  784. *outErr = [self errorWithMessage:[NSString stringWithUTF8String:sqlite3_errmsg(_db)]];
  785. }
  786. sqlite3_finalize(pStmt);
  787. _isExecutingStatement = NO;
  788. return NO;
  789. }
  790. }
  791. id obj;
  792. int idx = 0;
  793. int queryCount = sqlite3_bind_parameter_count(pStmt);
  794. // If dictionaryArgs is passed in, that means we are using sqlite's named parameter support
  795. if (dictionaryArgs) {
  796. for (NSString *dictionaryKey in [dictionaryArgs allKeys]) {
  797. // Prefix the key with a colon.
  798. NSString *parameterName = [[NSString alloc] initWithFormat:@":%@", dictionaryKey];
  799. if (_traceExecution) {
  800. NSLog(@"%@ = %@", parameterName, [dictionaryArgs objectForKey:dictionaryKey]);
  801. }
  802. // Get the index for the parameter name.
  803. int namedIdx = sqlite3_bind_parameter_index(pStmt, [parameterName UTF8String]);
  804. FMDBRelease(parameterName);
  805. if (namedIdx > 0) {
  806. // Standard binding from here.
  807. [self bindObject:[dictionaryArgs objectForKey:dictionaryKey] toColumn:namedIdx inStatement:pStmt];
  808. // increment the binding count, so our check below works out
  809. idx++;
  810. }
  811. else {
  812. NSString *message = [NSString stringWithFormat:@"Could not find index for %@", dictionaryKey];
  813. if (_logsErrors) {
  814. NSLog(@"%@", message);
  815. }
  816. if (outErr) {
  817. *outErr = [self errorWithMessage:message];
  818. }
  819. }
  820. }
  821. }
  822. else {
  823. while (idx < queryCount) {
  824. if (arrayArgs && idx < (int)[arrayArgs count]) {
  825. obj = [arrayArgs objectAtIndex:(NSUInteger)idx];
  826. }
  827. else if (args) {
  828. obj = va_arg(args, id);
  829. }
  830. else {
  831. //We ran out of arguments
  832. break;
  833. }
  834. if (_traceExecution) {
  835. if ([obj isKindOfClass:[NSData class]]) {
  836. NSLog(@"data: %ld bytes", (unsigned long)[(NSData*)obj length]);
  837. }
  838. else {
  839. NSLog(@"obj: %@", obj);
  840. }
  841. }
  842. idx++;
  843. [self bindObject:obj toColumn:idx inStatement:pStmt];
  844. }
  845. }
  846. if (idx != queryCount) {
  847. NSString *message = [NSString stringWithFormat:@"Error: the bind count (%d) is not correct for the # of variables in the query (%d) (%@) (executeUpdate)", idx, queryCount, sql];
  848. if (_logsErrors) {
  849. NSLog(@"%@", message);
  850. }
  851. if (outErr) {
  852. *outErr = [self errorWithMessage:message];
  853. }
  854. sqlite3_finalize(pStmt);
  855. _isExecutingStatement = NO;
  856. return NO;
  857. }
  858. /* Call sqlite3_step() to run the virtual machine. Since the SQL being
  859. ** executed is not a SELECT statement, we assume no data will be returned.
  860. */
  861. rc = sqlite3_step(pStmt);
  862. if (SQLITE_DONE == rc) {
  863. // all is well, let's return.
  864. }
  865. else if (SQLITE_INTERRUPT == rc) {
  866. if (_logsErrors) {
  867. NSLog(@"Error calling sqlite3_step. Query was interrupted (%d: %s) SQLITE_INTERRUPT", rc, sqlite3_errmsg(_db));
  868. NSLog(@"DB Query: %@", sql);
  869. }
  870. }
  871. else if (rc == SQLITE_ROW) {
  872. NSString *message = [NSString stringWithFormat:@"A executeUpdate is being called with a query string '%@'", sql];
  873. if (_logsErrors) {
  874. NSLog(@"%@", message);
  875. NSLog(@"DB Query: %@", sql);
  876. }
  877. if (outErr) {
  878. *outErr = [self errorWithMessage:message];
  879. }
  880. }
  881. else {
  882. if (outErr) {
  883. *outErr = [self errorWithMessage:[NSString stringWithUTF8String:sqlite3_errmsg(_db)]];
  884. }
  885. if (SQLITE_ERROR == rc) {
  886. if (_logsErrors) {
  887. NSLog(@"Error calling sqlite3_step (%d: %s) SQLITE_ERROR", rc, sqlite3_errmsg(_db));
  888. NSLog(@"DB Query: %@", sql);
  889. }
  890. }
  891. else if (SQLITE_MISUSE == rc) {
  892. // uh oh.
  893. if (_logsErrors) {
  894. NSLog(@"Error calling sqlite3_step (%d: %s) SQLITE_MISUSE", rc, sqlite3_errmsg(_db));
  895. NSLog(@"DB Query: %@", sql);
  896. }
  897. }
  898. else {
  899. // wtf?
  900. if (_logsErrors) {
  901. NSLog(@"Unknown error calling sqlite3_step (%d: %s) eu", rc, sqlite3_errmsg(_db));
  902. NSLog(@"DB Query: %@", sql);
  903. }
  904. }
  905. }
  906. if (_shouldCacheStatements && !cachedStmt) {
  907. cachedStmt = [[FMStatement alloc] init];
  908. [cachedStmt setStatement:pStmt];
  909. [self setCachedStatement:cachedStmt forQuery:sql];
  910. FMDBRelease(cachedStmt);
  911. }
  912. int closeErrorCode;
  913. if (cachedStmt) {
  914. [cachedStmt setUseCount:[cachedStmt useCount] + 1];
  915. closeErrorCode = sqlite3_reset(pStmt);
  916. }
  917. else {
  918. /* Finalize the virtual machine. This releases all memory and other
  919. ** resources allocated by the sqlite3_prepare() call above.
  920. */
  921. closeErrorCode = sqlite3_finalize(pStmt);
  922. }
  923. if (closeErrorCode != SQLITE_OK) {
  924. if (_logsErrors) {
  925. NSLog(@"Unknown error finalizing or resetting statement (%d: %s)", closeErrorCode, sqlite3_errmsg(_db));
  926. NSLog(@"DB Query: %@", sql);
  927. }
  928. }
  929. _isExecutingStatement = NO;
  930. return (rc == SQLITE_DONE || rc == SQLITE_OK);
  931. }
  932. - (BOOL)executeUpdate:(NSString*)sql, ... {
  933. va_list args;
  934. va_start(args, sql);
  935. BOOL result = [self executeUpdate:sql error:nil withArgumentsInArray:nil orDictionary:nil orVAList:args];
  936. va_end(args);
  937. return result;
  938. }
  939. - (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments {
  940. return [self executeUpdate:sql error:nil withArgumentsInArray:arguments orDictionary:nil orVAList:nil];
  941. }
  942. - (BOOL)executeUpdate:(NSString*)sql values:(NSArray *)values error:(NSError * __autoreleasing *)error {
  943. return [self executeUpdate:sql error:error withArgumentsInArray:values orDictionary:nil orVAList:nil];
  944. }
  945. - (BOOL)executeUpdate:(NSString*)sql withParameterDictionary:(NSDictionary *)arguments {
  946. return [self executeUpdate:sql error:nil withArgumentsInArray:nil orDictionary:arguments orVAList:nil];
  947. }
  948. - (BOOL)executeUpdate:(NSString*)sql withVAList:(va_list)args {
  949. return [self executeUpdate:sql error:nil withArgumentsInArray:nil orDictionary:nil orVAList:args];
  950. }
  951. - (BOOL)executeUpdateWithFormat:(NSString*)format, ... {
  952. va_list args;
  953. va_start(args, format);
  954. NSMutableString *sql = [NSMutableString stringWithCapacity:[format length]];
  955. NSMutableArray *arguments = [NSMutableArray array];
  956. [self extractSQL:format argumentsList:args intoString:sql arguments:arguments];
  957. va_end(args);
  958. return [self executeUpdate:sql withArgumentsInArray:arguments];
  959. }
  960. int FMDBExecuteBulkSQLCallback(void *theBlockAsVoid, int columns, char **values, char **names); // shhh clang.
  961. int FMDBExecuteBulkSQLCallback(void *theBlockAsVoid, int columns, char **values, char **names) {
  962. if (!theBlockAsVoid) {
  963. return SQLITE_OK;
  964. }
  965. int (^execCallbackBlock)(NSDictionary *resultsDictionary) = (__bridge int (^)(NSDictionary *__strong))(theBlockAsVoid);
  966. NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:(NSUInteger)columns];
  967. for (NSInteger i = 0; i < columns; i++) {
  968. NSString *key = [NSString stringWithUTF8String:names[i]];
  969. id value = values[i] ? [NSString stringWithUTF8String:values[i]] : [NSNull null];
  970. [dictionary setObject:value forKey:key];
  971. }
  972. return execCallbackBlock(dictionary);
  973. }
  974. - (BOOL)executeStatements:(NSString *)sql {
  975. return [self executeStatements:sql withResultBlock:nil];
  976. }
  977. - (BOOL)executeStatements:(NSString *)sql withResultBlock:(FMDBExecuteStatementsCallbackBlock)block {
  978. int rc;
  979. char *errmsg = nil;
  980. rc = sqlite3_exec([self sqliteHandle], [sql UTF8String], block ? FMDBExecuteBulkSQLCallback : nil, (__bridge void *)(block), &errmsg);
  981. if (errmsg && [self logsErrors]) {
  982. NSLog(@"Error inserting batch: %s", errmsg);
  983. sqlite3_free(errmsg);
  984. }
  985. return (rc == SQLITE_OK);
  986. }
  987. - (BOOL)executeUpdate:(NSString*)sql withErrorAndBindings:(NSError**)outErr, ... {
  988. va_list args;
  989. va_start(args, outErr);
  990. BOOL result = [self executeUpdate:sql error:outErr withArgumentsInArray:nil orDictionary:nil orVAList:args];
  991. va_end(args);
  992. return result;
  993. }
  994. #pragma clang diagnostic push
  995. #pragma clang diagnostic ignored "-Wdeprecated-implementations"
  996. - (BOOL)update:(NSString*)sql withErrorAndBindings:(NSError**)outErr, ... {
  997. va_list args;
  998. va_start(args, outErr);
  999. BOOL result = [self executeUpdate:sql error:outErr withArgumentsInArray:nil orDictionary:nil orVAList:args];
  1000. va_end(args);
  1001. return result;
  1002. }
  1003. #pragma clang diagnostic pop
  1004. #pragma mark Transactions
  1005. - (BOOL)rollback {
  1006. BOOL b = [self executeUpdate:@"rollback transaction"];
  1007. if (b) {
  1008. _isInTransaction = NO;
  1009. }
  1010. return b;
  1011. }
  1012. - (BOOL)commit {
  1013. BOOL b = [self executeUpdate:@"commit transaction"];
  1014. if (b) {
  1015. _isInTransaction = NO;
  1016. }
  1017. return b;
  1018. }
  1019. - (BOOL)beginDeferredTransaction {
  1020. BOOL b = [self executeUpdate:@"begin deferred transaction"];
  1021. if (b) {
  1022. _isInTransaction = YES;
  1023. }
  1024. return b;
  1025. }
  1026. - (BOOL)beginTransaction {
  1027. BOOL b = [self executeUpdate:@"begin exclusive transaction"];
  1028. if (b) {
  1029. _isInTransaction = YES;
  1030. }
  1031. return b;
  1032. }
  1033. - (BOOL)inTransaction {
  1034. return _isInTransaction;
  1035. }
  1036. - (BOOL)interrupt
  1037. {
  1038. if (_db) {
  1039. sqlite3_interrupt([self sqliteHandle]);
  1040. return YES;
  1041. }
  1042. return NO;
  1043. }
  1044. static NSString *FMDBEscapeSavePointName(NSString *savepointName) {
  1045. return [savepointName stringByReplacingOccurrencesOfString:@"'" withString:@"''"];
  1046. }
  1047. - (BOOL)startSavePointWithName:(NSString*)name error:(NSError**)outErr {
  1048. #if SQLITE_VERSION_NUMBER >= 3007000
  1049. NSParameterAssert(name);
  1050. NSString *sql = [NSString stringWithFormat:@"savepoint '%@';", FMDBEscapeSavePointName(name)];
  1051. return [self executeUpdate:sql error:outErr withArgumentsInArray:nil orDictionary:nil orVAList:nil];
  1052. #else
  1053. NSString *errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil);
  1054. if (self.logsErrors) NSLog(@"%@", errorMessage);
  1055. return NO;
  1056. #endif
  1057. }
  1058. - (BOOL)releaseSavePointWithName:(NSString*)name error:(NSError**)outErr {
  1059. #if SQLITE_VERSION_NUMBER >= 3007000
  1060. NSParameterAssert(name);
  1061. NSString *sql = [NSString stringWithFormat:@"release savepoint '%@';", FMDBEscapeSavePointName(name)];
  1062. return [self executeUpdate:sql error:outErr withArgumentsInArray:nil orDictionary:nil orVAList:nil];
  1063. #else
  1064. NSString *errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil);
  1065. if (self.logsErrors) NSLog(@"%@", errorMessage);
  1066. return NO;
  1067. #endif
  1068. }
  1069. - (BOOL)rollbackToSavePointWithName:(NSString*)name error:(NSError**)outErr {
  1070. #if SQLITE_VERSION_NUMBER >= 3007000
  1071. NSParameterAssert(name);
  1072. NSString *sql = [NSString stringWithFormat:@"rollback transaction to savepoint '%@';", FMDBEscapeSavePointName(name)];
  1073. return [self executeUpdate:sql error:outErr withArgumentsInArray:nil orDictionary:nil orVAList:nil];
  1074. #else
  1075. NSString *errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil);
  1076. if (self.logsErrors) NSLog(@"%@", errorMessage);
  1077. return NO;
  1078. #endif
  1079. }
  1080. - (NSError*)inSavePoint:(void (^)(BOOL *rollback))block {
  1081. #if SQLITE_VERSION_NUMBER >= 3007000
  1082. static unsigned long savePointIdx = 0;
  1083. NSString *name = [NSString stringWithFormat:@"dbSavePoint%ld", savePointIdx++];
  1084. BOOL shouldRollback = NO;
  1085. NSError *err = 0x00;
  1086. if (![self startSavePointWithName:name error:&err]) {
  1087. return err;
  1088. }
  1089. if (block) {
  1090. block(&shouldRollback);
  1091. }
  1092. if (shouldRollback) {
  1093. // We need to rollback and release this savepoint to remove it
  1094. [self rollbackToSavePointWithName:name error:&err];
  1095. }
  1096. [self releaseSavePointWithName:name error:&err];
  1097. return err;
  1098. #else
  1099. NSString *errorMessage = NSLocalizedString(@"Save point functions require SQLite 3.7", nil);
  1100. if (self.logsErrors) NSLog(@"%@", errorMessage);
  1101. return [NSError errorWithDomain:@"FMDatabase" code:0 userInfo:@{NSLocalizedDescriptionKey : errorMessage}];
  1102. #endif
  1103. }
  1104. #pragma mark Cache statements
  1105. - (BOOL)shouldCacheStatements {
  1106. return _shouldCacheStatements;
  1107. }
  1108. - (void)setShouldCacheStatements:(BOOL)value {
  1109. _shouldCacheStatements = value;
  1110. if (_shouldCacheStatements && !_cachedStatements) {
  1111. [self setCachedStatements:[NSMutableDictionary dictionary]];
  1112. }
  1113. if (!_shouldCacheStatements) {
  1114. [self setCachedStatements:nil];
  1115. }
  1116. }
  1117. #pragma mark Callback function
  1118. void FMDBBlockSQLiteCallBackFunction(sqlite3_context *context, int argc, sqlite3_value **argv); // -Wmissing-prototypes
  1119. void FMDBBlockSQLiteCallBackFunction(sqlite3_context *context, int argc, sqlite3_value **argv) {
  1120. #if ! __has_feature(objc_arc)
  1121. void (^block)(sqlite3_context *context, int argc, sqlite3_value **argv) = (id)sqlite3_user_data(context);
  1122. #else
  1123. void (^block)(sqlite3_context *context, int argc, sqlite3_value **argv) = (__bridge id)sqlite3_user_data(context);
  1124. #endif
  1125. if (block) {
  1126. @autoreleasepool {
  1127. block(context, argc, argv);
  1128. }
  1129. }
  1130. }
  1131. // deprecated because "arguments" parameter is not maximum argument count, but actual argument count.
  1132. - (void)makeFunctionNamed:(NSString *)name maximumArguments:(int)arguments withBlock:(void (^)(void *context, int argc, void **argv))block {
  1133. [self makeFunctionNamed:name arguments:arguments block:block];
  1134. }
  1135. - (void)makeFunctionNamed:(NSString *)name arguments:(int)arguments block:(void (^)(void *context, int argc, void **argv))block {
  1136. if (!_openFunctions) {
  1137. _openFunctions = [NSMutableSet new];
  1138. }
  1139. id b = FMDBReturnAutoreleased([block copy]);
  1140. [_openFunctions addObject:b];
  1141. /* I tried adding custom functions to release the block when the connection is destroyed- but they seemed to never be called, so we use _openFunctions to store the values instead. */
  1142. #if ! __has_feature(objc_arc)
  1143. sqlite3_create_function([self sqliteHandle], [name UTF8String], arguments, SQLITE_UTF8, (void*)b, &FMDBBlockSQLiteCallBackFunction, 0x00, 0x00);
  1144. #else
  1145. sqlite3_create_function([self sqliteHandle], [name UTF8String], arguments, SQLITE_UTF8, (__bridge void*)b, &FMDBBlockSQLiteCallBackFunction, 0x00, 0x00);
  1146. #endif
  1147. }
  1148. - (SqliteValueType)valueType:(void *)value {
  1149. return sqlite3_value_type(value);
  1150. }
  1151. - (int)valueInt:(void *)value {
  1152. return sqlite3_value_int(value);
  1153. }
  1154. - (long long)valueLong:(void *)value {
  1155. return sqlite3_value_int64(value);
  1156. }
  1157. - (double)valueDouble:(void *)value {
  1158. return sqlite3_value_double(value);
  1159. }
  1160. - (NSData *)valueData:(void *)value {
  1161. const void *bytes = sqlite3_value_blob(value);
  1162. int length = sqlite3_value_bytes(value);
  1163. return bytes ? [NSData dataWithBytes:bytes length:length] : nil;
  1164. }
  1165. - (NSString *)valueString:(void *)value {
  1166. const char *cString = (const char *)sqlite3_value_text(value);
  1167. return cString ? [NSString stringWithUTF8String:cString] : nil;
  1168. }
  1169. - (void)resultNullInContext:(void *)context {
  1170. sqlite3_result_null(context);
  1171. }
  1172. - (void)resultInt:(int) value context:(void *)context {
  1173. sqlite3_result_int(context, value);
  1174. }
  1175. - (void)resultLong:(long long)value context:(void *)context {
  1176. sqlite3_result_int64(context, value);
  1177. }
  1178. - (void)resultDouble:(double)value context:(void *)context {
  1179. sqlite3_result_double(context, value);
  1180. }
  1181. - (void)resultData:(NSData *)data context:(void *)context {
  1182. sqlite3_result_blob(context, data.bytes, (int)data.length, SQLITE_TRANSIENT);
  1183. }
  1184. - (void)resultString:(NSString *)value context:(void *)context {
  1185. sqlite3_result_text(context, [value UTF8String], -1, SQLITE_TRANSIENT);
  1186. }
  1187. - (void)resultError:(NSString *)error context:(void *)context {
  1188. sqlite3_result_error(context, [error UTF8String], -1);
  1189. }
  1190. - (void)resultErrorCode:(int)errorCode context:(void *)context {
  1191. sqlite3_result_error_code(context, errorCode);
  1192. }
  1193. - (void)resultErrorNoMemoryInContext:(void *)context {
  1194. sqlite3_result_error_nomem(context);
  1195. }
  1196. - (void)resultErrorTooBigInContext:(void *)context {
  1197. sqlite3_result_error_toobig(context);
  1198. }
  1199. @end
  1200. @implementation FMStatement
  1201. #if ! __has_feature(objc_arc)
  1202. - (void)finalize {
  1203. [self close];
  1204. [super finalize];
  1205. }
  1206. #endif
  1207. - (void)dealloc {
  1208. [self close];
  1209. FMDBRelease(_query);
  1210. #if ! __has_feature(objc_arc)
  1211. [super dealloc];
  1212. #endif
  1213. }
  1214. - (void)close {
  1215. if (_statement) {
  1216. sqlite3_finalize(_statement);
  1217. _statement = 0x00;
  1218. }
  1219. _inUse = NO;
  1220. }
  1221. - (void)reset {
  1222. if (_statement) {
  1223. sqlite3_reset(_statement);
  1224. }
  1225. _inUse = NO;
  1226. }
  1227. - (NSString*)description {
  1228. return [NSString stringWithFormat:@"%@ %ld hit(s) for query %@", [super description], _useCount, _query];
  1229. }
  1230. @end