Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 949 lines (751 sloc) 25.402 kb
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
1 #import "FMDatabase.h"
2 #import "unistd.h"
3
4843fe1 Changed the FMDatabase class to "JSTDatabase" - since folks who were alr...
August Mueller authored
4 @implementation JSTDatabase
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
5
6 + (id)databaseWithPath:(NSString*)aPath {
4843fe1 Changed the FMDatabase class to "JSTDatabase" - since folks who were alr...
August Mueller authored
7 return [[[self alloc] initWithPath:aPath] autorelease];
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
8 }
9
10 - (id)initWithPath:(NSString*)aPath {
11 self = [super init];
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
12
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
13 if (self) {
14 databasePath = [aPath copy];
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
15 openResultSets = [[NSMutableSet alloc] init];
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
16 db = 0x00;
17 logsErrors = 0x00;
18 crashOnErrors = 0x00;
19 busyRetryTimeout = 0x00;
20 }
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
21
22 return self;
23 }
24
25 - (void)finalize {
26 [self close];
27 [super finalize];
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
28 }
29
30 - (void)dealloc {
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
31 [self close];
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
32
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
33 [openResultSets release];
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
34 [cachedStatements release];
35 [databasePath release];
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
36
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
37 [super dealloc];
38 }
39
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
40 + (NSString*)sqliteLibVersion {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
41 return [NSString stringWithFormat:@"%s", sqlite3_libversion()];
42 }
43
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
44 - (NSString *)databasePath {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
45 return databasePath;
46 }
47
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
48 - (sqlite3*)sqliteHandle {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
49 return db;
50 }
51
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
52 - (BOOL)open {
53 if (db) {
54 return YES;
55 }
56
57 int err = sqlite3_open((databasePath ? [databasePath fileSystemRepresentation] : ":memory:"), &db );
58 if(err != SQLITE_OK) {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
59 NSLog(@"error opening!: %d", err);
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
60 return NO;
61 }
62
63 return YES;
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
64 }
65
4843fe1 Changed the FMDatabase class to "JSTDatabase" - since folks who were alr...
August Mueller authored
66 #if SQLITE_VERSION_NUMBER >= 3005000
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
67 - (BOOL)openWithFlags:(int)flags {
68 int err = sqlite3_open_v2((databasePath ? [databasePath fileSystemRepresentation] : ":memory:"), &db, flags, NULL /* Name of VFS module to use */);
69 if(err != SQLITE_OK) {
70 NSLog(@"error opening!: %d", err);
71 return NO;
72 }
73 return YES;
4843fe1 Changed the FMDatabase class to "JSTDatabase" - since folks who were alr...
August Mueller authored
74 }
75 #endif
76
77
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
78 - (BOOL)close {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
79
80 [self clearCachedStatements];
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
81 [self closeOpenResultSets];
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
82
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
83 if (!db) {
84 return YES;
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
85 }
86
87 int rc;
88 BOOL retry;
89 int numberOfRetries = 0;
90 do {
91 retry = NO;
92 rc = sqlite3_close(db);
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
93 if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
94 retry = YES;
95 usleep(20);
96 if (busyRetryTimeout && (numberOfRetries++ > busyRetryTimeout)) {
97 NSLog(@"%s:%d", __FUNCTION__, __LINE__);
98 NSLog(@"Database busy, unable to close");
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
99 return NO;
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
100 }
101 }
102 else if (SQLITE_OK != rc) {
103 NSLog(@"error closing!: %d", rc);
104 }
105 }
106 while (retry);
107
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
108 db = nil;
109 return YES;
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
110 }
111
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
112 - (void)clearCachedStatements {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
113
114 NSEnumerator *e = [cachedStatements objectEnumerator];
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
115 JSTStatement *cachedStmt;
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
116
117 while ((cachedStmt = [e nextObject])) {
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
118 [cachedStmt close];
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
119 }
120
121 [cachedStatements removeAllObjects];
122 }
123
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
124 - (void)closeOpenResultSets {
125 //Copy the set so we don't get mutation errors
126 NSSet *resultSets = [[openResultSets copy] autorelease];
127
128 NSEnumerator *e = [resultSets objectEnumerator];
129 NSValue *returnedResultSet = nil;
130
131 while((returnedResultSet = [e nextObject])) {
132 JSTResultSet *rs = (JSTResultSet *)[returnedResultSet pointerValue];
133 if ([rs respondsToSelector:@selector(close)]) {
134 [rs close];
135 }
136 }
137 }
138
139 - (void)resultSetDidClose:(JSTResultSet *)resultSet {
140 NSValue *setValue = [NSValue valueWithNonretainedObject:resultSet];
141 [openResultSets removeObject:setValue];
142 }
143
144 - (JSTStatement*)cachedStatementForQuery:(NSString*)query {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
145 return [cachedStatements objectForKey:query];
146 }
147
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
148 - (void)setCachedStatement:(JSTStatement*)statement forQuery:(NSString*)query {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
149 //NSLog(@"setting query: %@", query);
150 query = [query copy]; // in case we got handed in a mutable string...
151 [statement setQuery:query];
152 [cachedStatements setObject:statement forKey:query];
153 [query release];
154 }
155
156
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
157 - (BOOL)rekey:(NSString*)key {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
158 #ifdef SQLITE_HAS_CODEC
159 if (!key) {
160 return NO;
161 }
162
163 int rc = sqlite3_rekey(db, [key UTF8String], strlen([key UTF8String]));
164
165 if (rc != SQLITE_OK) {
166 NSLog(@"error on rekey: %d", rc);
167 NSLog(@"%@", [self lastErrorMessage]);
168 }
169
170 return (rc == SQLITE_OK);
171 #else
172 return NO;
173 #endif
174 }
175
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
176 - (BOOL)setKey:(NSString*)key {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
177 #ifdef SQLITE_HAS_CODEC
178 if (!key) {
179 return NO;
180 }
181
182 int rc = sqlite3_key(db, [key UTF8String], strlen([key UTF8String]));
183
184 return (rc == SQLITE_OK);
185 #else
186 return NO;
187 #endif
188 }
189
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
190 - (BOOL)goodConnection {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
191
192 if (!db) {
193 return NO;
194 }
195
4843fe1 Changed the FMDatabase class to "JSTDatabase" - since folks who were alr...
August Mueller authored
196 JSTResultSet *rs = [self executeQuery:@"select name from sqlite_master where type='table'"];
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
197
198 if (rs) {
199 [rs close];
200 return YES;
201 }
202
203 return NO;
204 }
205
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
206 - (void)compainAboutInUse {
4843fe1 Changed the FMDatabase class to "JSTDatabase" - since folks who were alr...
August Mueller authored
207 NSLog(@"The JSTDatabase %@ is currently in use.", self);
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
208
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
209 #ifndef NS_BLOCK_ASSERTIONS
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
210 if (crashOnErrors) {
4843fe1 Changed the FMDatabase class to "JSTDatabase" - since folks who were alr...
August Mueller authored
211 NSAssert1(false, @"The JSTDatabase %@ is currently in use.", self);
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
212 }
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
213 #endif
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
214 }
215
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
216 - (NSString*)lastErrorMessage {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
217 return [NSString stringWithUTF8String:sqlite3_errmsg(db)];
218 }
219
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
220 - (BOOL)hadError {
4843fe1 Changed the FMDatabase class to "JSTDatabase" - since folks who were alr...
August Mueller authored
221 int lastErrCode = [self lastErrorCode];
222
223 return (lastErrCode > SQLITE_OK && lastErrCode < SQLITE_ROW);
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
224 }
225
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
226 - (int)lastErrorCode {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
227 return sqlite3_errcode(db);
228 }
229
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
230 - (sqlite_int64)lastInsertRowId {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
231
232 if (inUse) {
233 [self compainAboutInUse];
234 return NO;
235 }
236 [self setInUse:YES];
237
238 sqlite_int64 ret = sqlite3_last_insert_rowid(db);
239
240 [self setInUse:NO];
241
242 return ret;
243 }
244
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
245 - (int)changes {
246 if (inUse) {
247 [self compainAboutInUse];
248 return 0;
249 }
250
251 [self setInUse:YES];
252 int ret = sqlite3_changes(db);
253 [self setInUse:NO];
254
255 return ret;
256 }
257
258 - (void)bindObject:(id)obj toColumn:(int)idx inStatement:(sqlite3_stmt*)pStmt {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
259
260 if ((!obj) || ((NSNull *)obj == [NSNull null])) {
261 sqlite3_bind_null(pStmt, idx);
262 }
263
264 // FIXME - someday check the return codes on these binds.
265 else if ([obj isKindOfClass:[NSData class]]) {
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
266 sqlite3_bind_blob(pStmt, idx, [obj bytes], (int)[obj length], SQLITE_STATIC);
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
267 }
268 else if ([obj isKindOfClass:[NSDate class]]) {
269 sqlite3_bind_double(pStmt, idx, [obj timeIntervalSince1970]);
270 }
271 else if ([obj isKindOfClass:[NSNumber class]]) {
272
273 if (strcmp([obj objCType], @encode(BOOL)) == 0) {
274 sqlite3_bind_int(pStmt, idx, ([obj boolValue] ? 1 : 0));
275 }
276 else if (strcmp([obj objCType], @encode(int)) == 0) {
277 sqlite3_bind_int64(pStmt, idx, [obj longValue]);
278 }
279 else if (strcmp([obj objCType], @encode(long)) == 0) {
280 sqlite3_bind_int64(pStmt, idx, [obj longValue]);
281 }
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
282 else if (strcmp([obj objCType], @encode(long long)) == 0) {
283 sqlite3_bind_int64(pStmt, idx, [obj longLongValue]);
284 }
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
285 else if (strcmp([obj objCType], @encode(float)) == 0) {
286 sqlite3_bind_double(pStmt, idx, [obj floatValue]);
287 }
288 else if (strcmp([obj objCType], @encode(double)) == 0) {
289 sqlite3_bind_double(pStmt, idx, [obj doubleValue]);
290 }
291 else {
292 sqlite3_bind_text(pStmt, idx, [[obj description] UTF8String], -1, SQLITE_STATIC);
293 }
294 }
295 else {
296 sqlite3_bind_text(pStmt, idx, [[obj description] UTF8String], -1, SQLITE_STATIC);
297 }
298 }
299
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
300 - (void)_extractSQL:(NSString *)sql argumentsList:(va_list)args intoString:(NSMutableString *)cleanedSQL arguments:(NSMutableArray *)arguments {
301
302 NSUInteger length = [sql length];
303 unichar last = '\0';
304 for (NSUInteger i = 0; i < length; ++i) {
305 id arg = nil;
306 unichar current = [sql characterAtIndex:i];
307 unichar add = current;
308 if (last == '%') {
309 switch (current) {
310 case '@':
311 arg = va_arg(args, id); break;
312 case 'c':
313 arg = [NSString stringWithFormat:@"%c", va_arg(args, char)]; break;
314 case 's':
315 arg = [NSString stringWithUTF8String:va_arg(args, char*)]; break;
316 case 'd':
317 case 'D':
318 case 'i':
319 arg = [NSNumber numberWithInt:va_arg(args, int)]; break;
320 case 'u':
321 case 'U':
322 arg = [NSNumber numberWithUnsignedInt:va_arg(args, unsigned int)]; break;
323 case 'h':
324 i++;
325 if (i < length && [sql characterAtIndex:i] == 'i') {
326 arg = [NSNumber numberWithShort:va_arg(args, short)];
327 }
328 else if (i < length && [sql characterAtIndex:i] == 'u') {
329 arg = [NSNumber numberWithUnsignedShort:va_arg(args, unsigned short)];
330 }
331 else {
332 i--;
333 }
334 break;
335 case 'q':
336 i++;
337 if (i < length && [sql characterAtIndex:i] == 'i') {
338 arg = [NSNumber numberWithLongLong:va_arg(args, long long)];
339 }
340 else if (i < length && [sql characterAtIndex:i] == 'u') {
341 arg = [NSNumber numberWithUnsignedLongLong:va_arg(args, unsigned long long)];
342 }
343 else {
344 i--;
345 }
346 break;
347 case 'f':
348 arg = [NSNumber numberWithDouble:va_arg(args, double)]; break;
349 case 'g':
350 arg = [NSNumber numberWithFloat:va_arg(args, float)]; break;
351 case 'l':
352 i++;
353 if (i < length) {
354 unichar next = [sql characterAtIndex:i];
355 if (next == 'l') {
356 i++;
357 if (i < length && [sql characterAtIndex:i] == 'd') {
358 //%lld
359 arg = [NSNumber numberWithLongLong:va_arg(args, long long)];
360 }
361 else if (i < length && [sql characterAtIndex:i] == 'u') {
362 //%llu
363 arg = [NSNumber numberWithUnsignedLongLong:va_arg(args, unsigned long long)];
364 }
365 else {
366 i--;
367 }
368 }
369 else if (next == 'd') {
370 //%ld
371 arg = [NSNumber numberWithLong:va_arg(args, long)];
372 }
373 else if (next == 'u') {
374 //%lu
375 arg = [NSNumber numberWithUnsignedLong:va_arg(args, unsigned long)];
376 }
377 else {
378 i--;
379 }
380 }
381 else {
382 i--;
383 }
384 break;
385 default:
386 // something else that we can't interpret. just pass it on through like normal
387 break;
388 }
389 }
390 else if (current == '%') {
391 // percent sign; skip this character
392 add = '\0';
393 }
394
395 if (arg != nil) {
396 [cleanedSQL appendString:@"?"];
397 [arguments addObject:arg];
398 }
399 else if (add != '\0') {
400 [cleanedSQL appendFormat:@"%C", add];
401 }
402 last = current;
403 }
404
405 }
406
407 - (JSTResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray*)arrayArgs orVAList:(va_list)args {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
408
409 if (inUse) {
410 [self compainAboutInUse];
411 return nil;
412 }
413
414 [self setInUse:YES];
415
4843fe1 Changed the FMDatabase class to "JSTDatabase" - since folks who were alr...
August Mueller authored
416 JSTResultSet *rs = nil;
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
417
418 int rc = 0x00;;
419 sqlite3_stmt *pStmt = 0x00;;
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
420 JSTStatement *statement = 0x00;
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
421
422 if (traceExecution && sql) {
423 NSLog(@"%@ executeQuery: %@", self, sql);
424 }
425
426 if (shouldCacheStatements) {
427 statement = [self cachedStatementForQuery:sql];
428 pStmt = statement ? [statement statement] : 0x00;
429 }
430
431 int numberOfRetries = 0;
432 BOOL retry = NO;
433
434 if (!pStmt) {
435 do {
436 retry = NO;
4843fe1 Changed the FMDatabase class to "JSTDatabase" - since folks who were alr...
August Mueller authored
437 rc = sqlite3_prepare_v2(db, [sql UTF8String], -1, &pStmt, 0);
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
438
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
439 if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
440 retry = YES;
441 usleep(20);
442
443 if (busyRetryTimeout && (numberOfRetries++ > busyRetryTimeout)) {
444 NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [self databasePath]);
445 NSLog(@"Database busy");
446 sqlite3_finalize(pStmt);
447 [self setInUse:NO];
448 return nil;
449 }
450 }
451 else if (SQLITE_OK != rc) {
452
453
454 if (logsErrors) {
455 NSLog(@"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]);
456 NSLog(@"DB Query: %@", sql);
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
457 #ifndef NS_BLOCK_ASSERTIONS
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
458 if (crashOnErrors) {
459 NSAssert2(false, @"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]);
460 }
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
461 #endif
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
462 }
463
464 sqlite3_finalize(pStmt);
465
466 [self setInUse:NO];
467 return nil;
468 }
469 }
470 while (retry);
471 }
472
473 id obj;
474 int idx = 0;
475 int queryCount = sqlite3_bind_parameter_count(pStmt); // pointed out by Dominic Yu (thanks!)
476
477 while (idx < queryCount) {
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
478
479 if (arrayArgs) {
480 obj = [arrayArgs objectAtIndex:idx];
481 }
482 else {
483 obj = va_arg(args, id);
484 }
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
485
486 if (traceExecution) {
487 NSLog(@"obj: %@", obj);
488 }
489
490 idx++;
491
492 [self bindObject:obj toColumn:idx inStatement:pStmt];
493 }
494
495 if (idx != queryCount) {
496 NSLog(@"Error: the bind count is not correct for the # of variables (executeQuery)");
497 sqlite3_finalize(pStmt);
498 [self setInUse:NO];
499 return nil;
500 }
501
502 [statement retain]; // to balance the release below
503
504 if (!statement) {
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
505 statement = [[JSTStatement alloc] init];
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
506 [statement setStatement:pStmt];
507
508 if (shouldCacheStatements) {
509 [self setCachedStatement:statement forQuery:sql];
510 }
511 }
512
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
513 // the statement gets closed in rs's dealloc or [rs close];
4843fe1 Changed the FMDatabase class to "JSTDatabase" - since folks who were alr...
August Mueller authored
514 rs = [JSTResultSet resultSetWithStatement:statement usingParentDatabase:self];
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
515 [rs setQuery:sql];
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
516 NSValue *openResultSet = [NSValue valueWithNonretainedObject:rs];
517 [openResultSets addObject:openResultSet];
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
518
519 statement.useCount = statement.useCount + 1;
520
521 [statement release];
522
523 [self setInUse:NO];
524
525 return rs;
526 }
527
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
528 - (JSTResultSet *)executeQuery:(NSString*)sql, ... {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
529 va_list args;
530 va_start(args, sql);
531
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
532 id result = [self executeQuery:sql withArgumentsInArray:nil orVAList:args];
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
533
534 va_end(args);
535 return result;
536 }
537
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
538 - (JSTResultSet *)executeQueryWithFormat:(NSString*)format, ... {
539 va_list args;
540 va_start(args, format);
541
542 NSMutableString *sql = [NSMutableString stringWithCapacity:[format length]];
543 NSMutableArray *arguments = [NSMutableArray array];
544 [self _extractSQL:format argumentsList:args intoString:sql arguments:arguments];
545
546 va_end(args);
547
548 return [self executeQuery:sql withArgumentsInArray:arguments];
549 }
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
550
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
551 - (JSTResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray *)arguments {
552 return [self executeQuery:sql withArgumentsInArray:arguments orVAList:nil];
553 }
554
555 - (BOOL)executeUpdate:(NSString*)sql error:(NSError**)outErr withArgumentsInArray:(NSArray*)arrayArgs orVAList:(va_list)args {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
556
557 if (inUse) {
558 [self compainAboutInUse];
559 return NO;
560 }
561
562 [self setInUse:YES];
563
564 int rc = 0x00;
565 sqlite3_stmt *pStmt = 0x00;
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
566 JSTStatement *cachedStmt = 0x00;
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
567
568 if (traceExecution && sql) {
569 NSLog(@"%@ executeUpdate: %@", self, sql);
570 }
571
572 if (shouldCacheStatements) {
573 cachedStmt = [self cachedStatementForQuery:sql];
574 pStmt = cachedStmt ? [cachedStmt statement] : 0x00;
575 }
576
577 int numberOfRetries = 0;
578 BOOL retry = NO;
579
580 if (!pStmt) {
581
582 do {
583 retry = NO;
4843fe1 Changed the FMDatabase class to "JSTDatabase" - since folks who were alr...
August Mueller authored
584 rc = sqlite3_prepare_v2(db, [sql UTF8String], -1, &pStmt, 0);
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
585 if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
586 retry = YES;
587 usleep(20);
588
589 if (busyRetryTimeout && (numberOfRetries++ > busyRetryTimeout)) {
590 NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [self databasePath]);
591 NSLog(@"Database busy");
592 sqlite3_finalize(pStmt);
593 [self setInUse:NO];
594 return NO;
595 }
596 }
597 else if (SQLITE_OK != rc) {
598
599
600 if (logsErrors) {
601 NSLog(@"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]);
602 NSLog(@"DB Query: %@", sql);
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
603 #ifndef NS_BLOCK_ASSERTIONS
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
604 if (crashOnErrors) {
605 NSAssert2(false, @"DB Error: %d \"%@\"", [self lastErrorCode], [self lastErrorMessage]);
606 }
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
607 #endif
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
608 }
609
610 sqlite3_finalize(pStmt);
611 [self setInUse:NO];
612
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
613 if (outErr) {
614 *outErr = [NSError errorWithDomain:[NSString stringWithUTF8String:sqlite3_errmsg(db)] code:rc userInfo:nil];
615 }
616
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
617 return NO;
618 }
619 }
620 while (retry);
621 }
622
623
624 id obj;
625 int idx = 0;
626 int queryCount = sqlite3_bind_parameter_count(pStmt);
627
628 while (idx < queryCount) {
629
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
630 if (arrayArgs) {
631 obj = [arrayArgs objectAtIndex:idx];
632 }
633 else {
634 obj = va_arg(args, id);
635 }
636
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
637
638 if (traceExecution) {
639 NSLog(@"obj: %@", obj);
640 }
641
642 idx++;
643
644 [self bindObject:obj toColumn:idx inStatement:pStmt];
645 }
646
647 if (idx != queryCount) {
648 NSLog(@"Error: the bind count is not correct for the # of variables (%@) (executeUpdate)", sql);
649 sqlite3_finalize(pStmt);
650 [self setInUse:NO];
651 return NO;
652 }
653
654 /* Call sqlite3_step() to run the virtual machine. Since the SQL being
655 ** executed is not a SELECT statement, we assume no data will be returned.
656 */
657 numberOfRetries = 0;
658 do {
659 rc = sqlite3_step(pStmt);
660 retry = NO;
661
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
662 if (SQLITE_BUSY == rc || SQLITE_LOCKED == rc) {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
663 // this will happen if the db is locked, like if we are doing an update or insert.
664 // in that case, retry the step... and maybe wait just 10 milliseconds.
665 retry = YES;
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
666 if (SQLITE_LOCKED == rc) {
667 rc = sqlite3_reset(pStmt);
668 if (rc != SQLITE_LOCKED) {
669 NSLog(@"Unexpected result from sqlite3_reset (%d) eu", rc);
670 }
671 }
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
672 usleep(20);
673
674 if (busyRetryTimeout && (numberOfRetries++ > busyRetryTimeout)) {
675 NSLog(@"%s:%d Database busy (%@)", __FUNCTION__, __LINE__, [self databasePath]);
676 NSLog(@"Database busy");
677 retry = NO;
678 }
679 }
680 else if (SQLITE_DONE == rc || SQLITE_ROW == rc) {
681 // all is well, let's return.
682 }
683 else if (SQLITE_ERROR == rc) {
684 NSLog(@"Error calling sqlite3_step (%d: %s) SQLITE_ERROR", rc, sqlite3_errmsg(db));
685 NSLog(@"DB Query: %@", sql);
686 }
687 else if (SQLITE_MISUSE == rc) {
688 // uh oh.
689 NSLog(@"Error calling sqlite3_step (%d: %s) SQLITE_MISUSE", rc, sqlite3_errmsg(db));
690 NSLog(@"DB Query: %@", sql);
691 }
692 else {
693 // wtf?
694 NSLog(@"Unknown error calling sqlite3_step (%d: %s) eu", rc, sqlite3_errmsg(db));
695 NSLog(@"DB Query: %@", sql);
696 }
697
698 } while (retry);
699
700 assert( rc!=SQLITE_ROW );
701
702
703 if (shouldCacheStatements && !cachedStmt) {
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
704 cachedStmt = [[JSTStatement alloc] init];
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
705
706 [cachedStmt setStatement:pStmt];
707
708 [self setCachedStatement:cachedStmt forQuery:sql];
709
710 [cachedStmt release];
711 }
712
713 if (cachedStmt) {
714 cachedStmt.useCount = cachedStmt.useCount + 1;
715 rc = sqlite3_reset(pStmt);
716 }
717 else {
718 /* Finalize the virtual machine. This releases all memory and other
719 ** resources allocated by the sqlite3_prepare() call above.
720 */
721 rc = sqlite3_finalize(pStmt);
722 }
723
724 [self setInUse:NO];
725
726 return (rc == SQLITE_OK);
727 }
728
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
729
730 - (BOOL)executeUpdate:(NSString*)sql, ... {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
731 va_list args;
732 va_start(args, sql);
733
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
734 BOOL result = [self executeUpdate:sql error:nil withArgumentsInArray:nil orVAList:args];
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
735
736 va_end(args);
737 return result;
738 }
739
740
741
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
742 - (BOOL)executeUpdate:(NSString*)sql withArgumentsInArray:(NSArray *)arguments {
743 return [self executeUpdate:sql error:nil withArgumentsInArray:arguments orVAList:nil];
744 }
745
746 - (BOOL)executeUpdateWithFormat:(NSString*)format, ... {
747 va_list args;
748 va_start(args, format);
749
750 NSMutableString *sql = [NSMutableString stringWithCapacity:[format length]];
751 NSMutableArray *arguments = [NSMutableArray array];
752 [self _extractSQL:format argumentsList:args intoString:sql arguments:arguments];
753
754 va_end(args);
755
756 return [self executeUpdate:sql withArgumentsInArray:arguments];
757 }
758
759 - (BOOL)update:(NSString*)sql error:(NSError**)outErr bind:(id)bindArgs, ... {
760 va_list args;
761 va_start(args, bindArgs);
762
763 BOOL result = [self executeUpdate:sql error:outErr withArgumentsInArray:nil orVAList:args];
764
765 va_end(args);
766 return result;
767 }
768
769 - (BOOL)rollback {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
770 BOOL b = [self executeUpdate:@"ROLLBACK TRANSACTION;"];
771 if (b) {
772 inTransaction = NO;
773 }
774 return b;
775 }
776
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
777 - (BOOL)commit {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
778 BOOL b = [self executeUpdate:@"COMMIT TRANSACTION;"];
779 if (b) {
780 inTransaction = NO;
781 }
782 return b;
783 }
784
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
785 - (BOOL)beginDeferredTransaction {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
786 BOOL b = [self executeUpdate:@"BEGIN DEFERRED TRANSACTION;"];
787 if (b) {
788 inTransaction = YES;
789 }
790 return b;
791 }
792
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
793 - (BOOL)beginTransaction {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
794 BOOL b = [self executeUpdate:@"BEGIN EXCLUSIVE TRANSACTION;"];
795 if (b) {
796 inTransaction = YES;
797 }
798 return b;
799 }
800
801 - (BOOL)logsErrors {
802 return logsErrors;
803 }
804 - (void)setLogsErrors:(BOOL)flag {
805 logsErrors = flag;
806 }
807
808 - (BOOL)crashOnErrors {
809 return crashOnErrors;
810 }
811 - (void)setCrashOnErrors:(BOOL)flag {
812 crashOnErrors = flag;
813 }
814
815 - (BOOL)inUse {
816 return inUse || inTransaction;
817 }
818
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
819 - (void)setInUse:(BOOL)b {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
820 inUse = b;
821 }
822
823 - (BOOL)inTransaction {
824 return inTransaction;
825 }
826 - (void)setInTransaction:(BOOL)flag {
827 inTransaction = flag;
828 }
829
830 - (BOOL)traceExecution {
831 return traceExecution;
832 }
833 - (void)setTraceExecution:(BOOL)flag {
834 traceExecution = flag;
835 }
836
837 - (BOOL)checkedOut {
838 return checkedOut;
839 }
840 - (void)setCheckedOut:(BOOL)flag {
841 checkedOut = flag;
842 }
843
844
845 - (int)busyRetryTimeout {
846 return busyRetryTimeout;
847 }
848 - (void)setBusyRetryTimeout:(int)newBusyRetryTimeout {
849 busyRetryTimeout = newBusyRetryTimeout;
850 }
851
852
853 - (BOOL)shouldCacheStatements {
854 return shouldCacheStatements;
855 }
856
857 - (void)setShouldCacheStatements:(BOOL)value {
858
859 shouldCacheStatements = value;
860
861 if (shouldCacheStatements && !cachedStatements) {
862 [self setCachedStatements:[NSMutableDictionary dictionary]];
863 }
864
865 if (!shouldCacheStatements) {
866 [self setCachedStatements:nil];
867 }
868 }
869
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
870 - (NSMutableDictionary *)cachedStatements {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
871 return cachedStatements;
872 }
873
874 - (void)setCachedStatements:(NSMutableDictionary *)value {
875 if (cachedStatements != value) {
876 [cachedStatements release];
877 cachedStatements = [value retain];
878 }
879 }
880
881
882 @end
883
884
885
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
886 @implementation JSTStatement
887
888 - (void)finalize {
889 [self close];
890 [super finalize];
891 }
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
892
893 - (void)dealloc {
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
894 [self close];
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
895 [query release];
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
896 [super dealloc];
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
897 }
898
899
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
900 - (void)close {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
901 if (statement) {
902 sqlite3_finalize(statement);
903 statement = 0x00;
904 }
905 }
906
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
907 - (void)reset {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
908 if (statement) {
909 sqlite3_reset(statement);
910 }
911 }
912
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
913 - (sqlite3_stmt *)statement {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
914 return statement;
915 }
916
917 - (void)setStatement:(sqlite3_stmt *)value {
918 statement = value;
919 }
920
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
921 - (NSString *)query {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
922 return query;
923 }
924
925 - (void)setQuery:(NSString *)value {
926 if (query != value) {
927 [query release];
928 query = [value retain];
929 }
930 }
931
932 - (long)useCount {
933 return useCount;
934 }
935
936 - (void)setUseCount:(long)value {
937 if (useCount != value) {
938 useCount = value;
939 }
940 }
941
3ba2fc0 @ccgus Updated to the latest release of FMDatabase
authored
942 - (NSString*)description {
d24bd62 @ccgus added a new jstalk extra, using fmdb, as well as adding support to load ...
authored
943 return [NSString stringWithFormat:@"%@ %d hit(s) for query %@", [super description], useCount, query];
944 }
945
946
947 @end
948
Something went wrong with that request. Please try again.