nano-store 0.3.8 → 0.3.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/Gemfile.lock +3 -3
  2. data/Rakefile +1 -1
  3. data/lib/nano_store/finder.rb +12 -6
  4. data/lib/nano_store/version.rb +1 -1
  5. data/vendor/Podfile.lock +2 -2
  6. data/vendor/Pods/Headers/NanoStore/NSFNanoBag.h +8 -2
  7. data/vendor/Pods/Headers/NanoStore/NSFNanoSearch.h +2 -0
  8. data/vendor/Pods/Headers/NanoStore/NSFNanoStore_Private.h +1 -1
  9. data/vendor/Pods/NanoStore/Classes/Private/NSFNanoStore_Private.h +1 -1
  10. data/vendor/Pods/NanoStore/Classes/Public/NSFNanoBag.h +8 -2
  11. data/vendor/Pods/NanoStore/Classes/Public/NSFNanoBag.m +7 -4
  12. data/vendor/Pods/NanoStore/Classes/Public/NSFNanoExpression.m +2 -6
  13. data/vendor/Pods/NanoStore/Classes/Public/NSFNanoSearch.h +2 -0
  14. data/vendor/Pods/NanoStore/Classes/Public/NSFNanoSearch.m +9 -7
  15. data/vendor/Pods/NanoStore/Classes/Public/NSFNanoStore.m +14 -4
  16. data/vendor/Pods/Pods.bridgesupport +8 -1
  17. metadata +8 -43
  18. data/vendor/NanoStore/Classes/Advanced/NSFNanoEngine.h +0 -542
  19. data/vendor/NanoStore/Classes/Advanced/NSFNanoEngine.m +0 -1781
  20. data/vendor/NanoStore/Classes/Advanced/NSFNanoResult.h +0 -137
  21. data/vendor/NanoStore/Classes/Advanced/NSFNanoResult.m +0 -265
  22. data/vendor/NanoStore/Classes/Private/NSFNanoBag_Private.h +0 -37
  23. data/vendor/NanoStore/Classes/Private/NSFNanoEngine_Private.h +0 -69
  24. data/vendor/NanoStore/Classes/Private/NSFNanoExpression_Private.h +0 -35
  25. data/vendor/NanoStore/Classes/Private/NSFNanoGlobals_Private.h +0 -99
  26. data/vendor/NanoStore/Classes/Private/NSFNanoObject_Private.h +0 -35
  27. data/vendor/NanoStore/Classes/Private/NSFNanoPredicate_Private.h +0 -35
  28. data/vendor/NanoStore/Classes/Private/NSFNanoResult_Private.h +0 -43
  29. data/vendor/NanoStore/Classes/Private/NSFNanoSearch_Private.h +0 -48
  30. data/vendor/NanoStore/Classes/Private/NSFNanoStore_Private.h +0 -57
  31. data/vendor/NanoStore/Classes/Private/NanoStore_Private.h +0 -37
  32. data/vendor/NanoStore/Classes/Public/NSFNanoBag.h +0 -306
  33. data/vendor/NanoStore/Classes/Public/NSFNanoBag.m +0 -485
  34. data/vendor/NanoStore/Classes/Public/NSFNanoExpression.h +0 -125
  35. data/vendor/NanoStore/Classes/Public/NSFNanoExpression.m +0 -103
  36. data/vendor/NanoStore/Classes/Public/NSFNanoGlobals.h +0 -323
  37. data/vendor/NanoStore/Classes/Public/NSFNanoGlobals.m +0 -145
  38. data/vendor/NanoStore/Classes/Public/NSFNanoObject.h +0 -298
  39. data/vendor/NanoStore/Classes/Public/NSFNanoObject.m +0 -187
  40. data/vendor/NanoStore/Classes/Public/NSFNanoObjectProtocol.h +0 -119
  41. data/vendor/NanoStore/Classes/Public/NSFNanoPredicate.h +0 -123
  42. data/vendor/NanoStore/Classes/Public/NSFNanoPredicate.m +0 -130
  43. data/vendor/NanoStore/Classes/Public/NSFNanoSearch.h +0 -381
  44. data/vendor/NanoStore/Classes/Public/NSFNanoSearch.m +0 -835
  45. data/vendor/NanoStore/Classes/Public/NSFNanoSortDescriptor.h +0 -124
  46. data/vendor/NanoStore/Classes/Public/NSFNanoSortDescriptor.m +0 -79
  47. data/vendor/NanoStore/Classes/Public/NSFNanoStore.h +0 -475
  48. data/vendor/NanoStore/Classes/Public/NSFNanoStore.m +0 -1375
  49. data/vendor/NanoStore/Classes/Public/NanoStore.h +0 -463
  50. data/vendor/NanoStore/LICENSE +0 -25
  51. data/vendor/NanoStore/NanoStore.bridgesupport +0 -1215
  52. data/vendor/NanoStore/README.md +0 -411
@@ -1,1781 +0,0 @@
1
- /*
2
- NSFNanoEngine.m
3
- NanoStore
4
-
5
- Copyright (c) 2010 Webbo, L.L.C. All rights reserved.
6
-
7
- Redistribution and use in source and binary forms, with or without modification, are permitted
8
- provided that the following conditions are met:
9
-
10
- * Redistributions of source code must retain the above copyright notice, this list of conditions
11
- and the following disclaimer.
12
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
13
- and the following disclaimer in the documentation and/or other materials provided with the distribution.
14
- * Neither the name of Webbo nor the names of its contributors may be used to endorse or promote
15
- products derived from this software without specific prior written permission.
16
-
17
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
18
- WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19
- PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
20
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
23
- OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
- SUCH DAMAGE.
25
- */
26
-
27
- #import "NanoStore.h"
28
- #import "NanoStore_Private.h"
29
-
30
- #import <stdio.h>
31
- #import <stdlib.h>
32
- #import <unistd.h>
33
-
34
- #pragma mark// ==================================
35
- #pragma mark// NSFNanoEngine C Declarations
36
- #pragma mark// ==================================
37
-
38
- int NSFP_commitCallback(void* nsfdb);
39
-
40
- static char __NSFP_base64Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
41
- static NSArray *__NSFP_SQLCommandsReturningData = nil;
42
- static NSArray *__NSFPSharedROWIDKeywords = nil;
43
- static NSSet *__NSFPSharedNanoStoreEngineDatatypes = nil;
44
-
45
- #pragma mark -
46
-
47
- @implementation NSFNanoEngine
48
- {
49
- @protected
50
- sqlite3 *sqlite;
51
- NSString *path;
52
- NSFCacheMethod cacheMethod;
53
-
54
- /** \cond */
55
- NSMutableDictionary *schema;
56
- BOOL willCommitChangeSchema;
57
- unsigned int busyTimeout;
58
- /** \endcond */
59
- }
60
-
61
- @synthesize sqlite;
62
- @synthesize path;
63
- @synthesize cacheMethod;
64
-
65
- #pragma mark -
66
-
67
- #pragma mark// ==================================
68
- #pragma mark// Initialization/Cleanup Methods
69
- #pragma mark// ==================================
70
-
71
- + (id)databaseWithPath:(NSString *)thePath
72
- {
73
- if (nil == thePath)
74
- [[NSException exceptionWithName:NSFUnexpectedParameterException
75
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: thePath is nil.", [self class], _cmd]
76
- userInfo:nil]raise];
77
-
78
- return [[self alloc]initWithPath:thePath];
79
- }
80
-
81
- - (id)initWithPath:(NSString *)thePath
82
- {
83
- if (nil == thePath)
84
- [[NSException exceptionWithName:NSFUnexpectedParameterException
85
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: thePath is nil.", [self class], _cmd]
86
- userInfo:nil]raise];
87
-
88
- if ((self = [self init])) {
89
- path = [thePath copy];
90
- }
91
-
92
- return self;
93
- }
94
-
95
- /** \cond */
96
-
97
- + (void)initialize
98
- {
99
- __NSFP_SQLCommandsReturningData = [[NSArray alloc]initWithObjects:@"SELECT", @"PRAGMA", @"EXPLAIN", nil];
100
- }
101
-
102
- - (id)init
103
- {
104
- if ((self = [super init])) {
105
- path = nil;
106
- schema = nil;
107
- }
108
- return self;
109
- }
110
-
111
- - (void)dealloc
112
- {
113
- [self close];
114
-
115
-
116
- }
117
-
118
- /** \endcond */
119
-
120
- - (NSString*)description
121
- {
122
- return [self NSFP_nestedDescriptionWithPrefixedSpace:@""];
123
- }
124
-
125
- #pragma mark// ==================================
126
- #pragma mark// Opening & Closing Methods
127
- #pragma mark// ==================================
128
-
129
- - (BOOL)openWithCacheMethod:(NSFCacheMethod)theCacheMethod useFastMode:(BOOL)useFastMode
130
- {
131
- int status = sqlite3_open_v2( [path UTF8String], &sqlite,
132
- SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_AUTOPROXY | SQLITE_OPEN_FULLMUTEX, NULL);
133
-
134
- // Set NanoStoreEngine's page size to match the system current page size
135
- if (0 == [[self tables]count]) {
136
- NSUInteger systemPageSize = [NSFNanoEngine systemPageSize];
137
- [self setPageSize:systemPageSize];
138
- }
139
-
140
- // Since we're operating with extended result code support, extract the bits
141
- // and obtain the regular result code
142
- // For more info check: http://www.sqlite.org/c3ref/c_ioerr_access.html
143
-
144
- status = [NSFNanoEngine NSFP_stripBitsFromExtendedResultCode:status];
145
-
146
- if ((SQLITE_OK != status) || (sqlite3_extended_result_codes(self.sqlite, 1) != SQLITE_OK))
147
- return NO;
148
-
149
- if ([[path lowercaseString]isEqualToString:NSFMemoryDatabase] == YES) {
150
-
151
- sqlite3_exec(self.sqlite, "PRAGMA fullfsync = OFF;", NULL, NULL, NULL);
152
- sqlite3_exec(self.sqlite, "PRAGMA temp_store = MEMORY", NULL, NULL, NULL);
153
- sqlite3_exec(self.sqlite, "PRAGMA synchronous = OFF;", NULL, NULL, NULL);
154
- sqlite3_exec(self.sqlite, "PRAGMA journal_mode = MEMORY;", NULL, NULL, NULL);
155
- sqlite3_exec(self.sqlite, "PRAGMA temp_store = MEMORY", NULL, NULL, NULL);
156
-
157
- } else {
158
-
159
- // Set FastMode accordingly...
160
- if (YES == useFastMode) {
161
- sqlite3_exec(self.sqlite, "PRAGMA fullfsync = OFF;", NULL, NULL, NULL);
162
- sqlite3_exec(self.sqlite, "PRAGMA synchronous = OFF;", NULL, NULL, NULL);
163
- sqlite3_exec(self.sqlite, "PRAGMA journal_mode = MEMORY;", NULL, NULL, NULL);
164
- sqlite3_exec(self.sqlite, "PRAGMA temp_store = MEMORY", NULL, NULL, NULL);
165
- } else {
166
- sqlite3_exec(self.sqlite, "PRAGMA fullfsync = OFF;", NULL, NULL, NULL);
167
- sqlite3_exec(self.sqlite, "PRAGMA synchronous = FULL;", NULL, NULL, NULL);
168
- sqlite3_exec(self.sqlite, "PRAGMA journal_mode = DELETE", NULL, NULL, NULL);
169
- sqlite3_exec(self.sqlite, "PRAGMA temp_store = DEFAULT", NULL, NULL, NULL);
170
- }
171
-
172
- }
173
-
174
- // Save whether we want data to be fetched lazily
175
- cacheMethod = theCacheMethod;
176
-
177
- [self setBusyTimeout:250];
178
-
179
- // Refresh the schema cache
180
- [self NSFP_rebuildDatatypeCache];
181
-
182
- [self NSFP_installCommitCallback];
183
-
184
- return YES;
185
- }
186
-
187
-
188
- - (BOOL)close
189
- {
190
- if (NO == self.sqlite) {
191
- return NO;
192
- }
193
-
194
- if (YES == [self isTransactionActive]) {
195
- [self rollbackTransaction];
196
- }
197
-
198
- // Make sure we clear the temporary data from schema
199
- NSArray *tempTables = [self temporaryTables];
200
-
201
- if ([tempTables count] > 0) {
202
- [self beginTransaction];
203
-
204
- for (NSString *table in tempTables) {
205
- [self dropTable:table];
206
- }
207
-
208
- [self commitTransaction];
209
- }
210
-
211
- int status = sqlite3_close(self.sqlite);
212
- sqlite = NULL;
213
-
214
- // Since we're operating with extended result code support, extract the bits
215
- // and obtain the regular result code
216
- // For more info check: http://www.sqlite.org/c3ref/c_ioerr_access.html
217
-
218
- status = [NSFNanoEngine NSFP_stripBitsFromExtendedResultCode:status];
219
-
220
- return (SQLITE_OK == status);
221
- }
222
-
223
- - (BOOL)isDatabaseOpen
224
- {
225
- return (NULL != self.sqlite);
226
- }
227
-
228
- #pragma mark Transaction Methods
229
-
230
- - (BOOL)beginTransaction
231
- {
232
- if (YES == [self isTransactionActive])
233
- return NO;
234
-
235
- willCommitChangeSchema = NO;
236
-
237
- return [self beginDeferredTransaction];
238
- }
239
-
240
- - (BOOL)beginDeferredTransaction
241
- {
242
- if (YES == [self isTransactionActive])
243
- return NO;
244
-
245
- willCommitChangeSchema = NO;
246
-
247
- return [self NSFP_beginTransactionMode:@"BEGIN DEFERRED TRANSACTION;"];
248
- }
249
-
250
- - (BOOL)commitTransaction
251
- {
252
- if (NO == [self isTransactionActive]) {
253
- willCommitChangeSchema = NO;
254
- return NO;
255
- }
256
-
257
- if (NO == willCommitChangeSchema)
258
- [self NSFP_uninstallCommitCallback];
259
-
260
- BOOL success = (nil == [[self executeSQL:@"COMMIT TRANSACTION;"]error]);
261
-
262
- if (NO == willCommitChangeSchema)
263
- [self NSFP_installCommitCallback];
264
-
265
- willCommitChangeSchema = NO;
266
-
267
- return success;
268
- }
269
-
270
- - (BOOL)rollbackTransaction
271
- {
272
- if ([self isTransactionActive] == NO) {
273
- willCommitChangeSchema = NO;
274
- return NO;
275
- }
276
-
277
- BOOL success = (nil == [[self executeSQL:@"ROLLBACK TRANSACTION;"]error]);
278
-
279
- willCommitChangeSchema = NO;
280
-
281
- return success;
282
- }
283
-
284
- - (BOOL)isTransactionActive
285
- {
286
- sqlite3* myDB = self.sqlite;
287
-
288
- int status = sqlite3_get_autocommit(myDB);
289
-
290
- // Since we're operating with extended result code support, extract the bits
291
- // and obtain the regular result code
292
- // For more info check: http://www.sqlite.org/c3ref/c_ioerr_access.html
293
-
294
- status = [NSFNanoEngine NSFP_stripBitsFromExtendedResultCode:status];
295
-
296
- return (0 == status);
297
- }
298
-
299
- #pragma mark// ==================================
300
- #pragma mark// Utility Methods
301
- #pragma mark// ==================================
302
-
303
- + (NSString *)stringWithUUID
304
- {
305
- CFUUIDRef uuidCF = CFUUIDCreate(NULL);
306
- NSString *uuid = (__bridge_transfer NSString *)CFUUIDCreateString(NULL, uuidCF);
307
- CFRelease(uuidCF);
308
- return uuid;
309
- }
310
-
311
- - (BOOL)compact
312
- {
313
- if (NO == [self isTransactionActive])
314
- return (nil == [[self executeSQL:@"VACUUM;"]error]);
315
-
316
- return NO;
317
- }
318
-
319
- - (BOOL)integrityCheck
320
- {
321
- if (NO == [self isTransactionActive]) {
322
- NSFNanoResult* result = [self executeSQL:@"PRAGMA integrity_check"];
323
-
324
- // SQLite returns the status as 'ok'. Let's code defensively and lowercase the result.
325
- return ([[[[result valuesForColumn:@"integrity_check"]lastObject]lowercaseString]isEqualToString:@"ok"]);
326
- }
327
-
328
- return NO;
329
- }
330
-
331
- + (NSString *)nanoStoreEngineVersion
332
- {
333
- return NSFVersionKey;
334
- }
335
-
336
- + (NSString *)sqliteVersion
337
- {
338
- return [NSString stringWithUTF8String: sqlite3_libversion()];
339
- }
340
-
341
- + (NSSet*)sharedNanoStoreEngineDatatypes
342
- {
343
- if (nil == __NSFPSharedNanoStoreEngineDatatypes)
344
- __NSFPSharedNanoStoreEngineDatatypes = [[NSSet alloc]initWithObjects:NSFStringFromNanoDataType(NSFNanoTypeRowUID),
345
- NSFStringFromNanoDataType(NSFNanoTypeString),
346
- NSFStringFromNanoDataType(NSFNanoTypeData),
347
- NSFStringFromNanoDataType(NSFNanoTypeDate),
348
- NSFStringFromNanoDataType(NSFNanoTypeNumber),
349
- nil];
350
-
351
- return __NSFPSharedNanoStoreEngineDatatypes;
352
- }
353
-
354
- #pragma mark// ==================================
355
- #pragma mark// Table and Introspection Methods
356
- #pragma mark// ==================================
357
-
358
- - (BOOL)createTable:(NSString *)table withColumns:(NSArray *)columns datatypes:(NSArray *)datatypes
359
- {
360
- if (nil == table)
361
- [[NSException exceptionWithName:NSFUnexpectedParameterException
362
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: table is nil.", [self class], _cmd]
363
- userInfo:nil]raise];
364
-
365
- if (nil == columns)
366
- [[NSException exceptionWithName:NSFUnexpectedParameterException
367
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: columns is nil.", [self class], _cmd]
368
- userInfo:nil]raise];
369
-
370
- if (nil == datatypes)
371
- [[NSException exceptionWithName:NSFUnexpectedParameterException
372
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: datatypes is nil.", [self class], _cmd]
373
- userInfo:nil]raise];
374
-
375
- return [self NSFP_createTable:table withColumns:columns datatypes:datatypes isTemporary:NO];
376
- }
377
-
378
- - (BOOL)dropTable:(NSString *)table
379
- {
380
- if (nil == table)
381
- [[NSException exceptionWithName:NSFUnexpectedParameterException
382
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: table is nil.", [self class], _cmd]
383
- userInfo:nil]raise];
384
-
385
- BOOL transactionSetHere = NO;
386
- if ([self isTransactionActive] == NO)
387
- transactionSetHere = [self beginTransaction];
388
-
389
- NSString *theSQLStatement = [[NSString alloc]initWithFormat:@"DROP TABLE %@;", table];
390
- BOOL everythingIsFine = (nil == [[self executeSQL:theSQLStatement]error]);
391
-
392
- if (everythingIsFine) {
393
- theSQLStatement = [[NSString alloc]initWithFormat:@"DELETE FROM %@ WHERE %@ = '%@';", NSFP_SchemaTable, NSFP_TableIdentifier, table];
394
- everythingIsFine = (nil == [[self executeSQL:theSQLStatement]error]);
395
- }
396
-
397
- if (transactionSetHere) {
398
- if (everythingIsFine)
399
- [self commitTransaction];
400
- else
401
- [self rollbackTransaction];
402
- }
403
-
404
- if (everythingIsFine)
405
- [self NSFP_rebuildDatatypeCache];
406
-
407
- return everythingIsFine;
408
- }
409
-
410
- - (BOOL)createIndexForColumn:(NSString *)column table:(NSString *)table isUnique:(BOOL)flag
411
- {
412
- if (nil == column)
413
- [[NSException exceptionWithName:NSFUnexpectedParameterException
414
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: column is nil.", [self class], _cmd]
415
- userInfo:nil]raise];
416
- if (nil == table)
417
- [[NSException exceptionWithName:NSFUnexpectedParameterException
418
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: table is nil.", [self class], _cmd]
419
- userInfo:nil]raise];
420
-
421
- NSString *theSQLStatement = nil;
422
-
423
- if (flag)
424
- theSQLStatement = [[NSString alloc]initWithFormat:@"CREATE UNIQUE INDEX %@_%@_IDX ON %@ (%@);", table, column, table, column];
425
- else
426
- theSQLStatement = [[NSString alloc]initWithFormat:@"CREATE INDEX %@_%@_IDX ON %@ (%@);", table, column, table, column];
427
-
428
- BOOL indexWasCreated = (nil == [[self executeSQL:theSQLStatement]error]);
429
-
430
- return indexWasCreated;
431
- }
432
-
433
- - (void)dropIndex:(NSString *)indexName
434
- {
435
- if (nil == indexName)
436
- [[NSException exceptionWithName:NSFUnexpectedParameterException
437
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: indexName is nil.", [self class], _cmd]
438
- userInfo:nil]raise];
439
-
440
- NSString *theSQLStatement = [[NSString alloc]initWithFormat:@"DROP INDEX %@;", indexName];
441
-
442
- [self executeSQL:theSQLStatement];
443
- }
444
-
445
- - (NSArray *)tables
446
- {
447
- NSArray *allTables = [self NSFP_flattenAllTables];
448
- if ([allTables count] == 0)
449
- return allTables;
450
-
451
- // Remove NSF's private table
452
- NSMutableArray *tempTables = [NSMutableArray arrayWithArray:allTables];
453
- [tempTables removeObject:NSFP_SchemaTable];
454
-
455
- return tempTables;
456
- }
457
-
458
- - (NSDictionary *)allTables
459
- {
460
- NSMutableDictionary *allTables = [NSMutableDictionary dictionary];
461
-
462
- // Make sure we obtain full column names
463
- [self NSFP_setFullColumnNamesEnabled];
464
-
465
- NSFNanoResult *databasesResult = [self executeSQL:@"PRAGMA database_list"];
466
- NSArray *databases = [databasesResult valuesForColumn:@"name"];
467
-
468
- for (NSString *database in databases) {
469
- NSString *theSQLStatement = [NSString stringWithFormat:@"SELECT * FROM %@.sqlite_master;", database];
470
- NSFNanoResult* result = [self executeSQL:theSQLStatement];
471
- if (nil == [result error]) {
472
- // Get all tables in the database
473
- NSArray *databaseTables = [result valuesForColumn:@"sqlite_master.tbl_name"];
474
- NSSet *tablesPerDatabase = [NSSet setWithArray:databaseTables];
475
- [allTables setObject: [tablesPerDatabase allObjects] forKey: database];
476
- }
477
- }
478
-
479
- return allTables;
480
- }
481
-
482
- - (NSArray *)columnsForTable:(NSString *)table
483
- {
484
- if (nil == table)
485
- [[NSException exceptionWithName:NSFUnexpectedParameterException
486
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: table is nil.", [self class], _cmd]
487
- userInfo:nil]raise];
488
-
489
- NSString *theSQLStatement = nil;
490
- NSString *database = [self NSFP_prefixWithDotDelimiter:table];
491
-
492
- if ([database isEqualToString:table] == NO) {
493
- database = [NSString stringWithFormat:@"%@.", database];
494
- table = [self NSFP_suffixWithDotDelimiter:table];
495
- theSQLStatement = [NSString stringWithFormat:@"PRAGMA %@.table_info ('%@');", database, table];
496
- } else {
497
- theSQLStatement = [NSString stringWithFormat:@"PRAGMA table_info ('%@');", table];
498
- }
499
-
500
- NSFNanoResult *result = [self executeSQL:theSQLStatement];
501
-
502
- return [result valuesForColumn:@"name"];
503
- }
504
-
505
- - (NSArray *)datatypesForTable:(NSString *)table
506
- {
507
- if (nil == table)
508
- [[NSException exceptionWithName:NSFUnexpectedParameterException
509
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: table is nil.", [self class], _cmd]
510
- userInfo:nil]raise];
511
-
512
- NSString *theSQLStatement = nil;
513
- NSString *database = [self NSFP_prefixWithDotDelimiter:table];
514
-
515
- if ([database isEqualToString:table] == NO) {
516
- database = [NSString stringWithFormat:@"%@.", database];
517
- table = [self NSFP_suffixWithDotDelimiter:table];
518
- theSQLStatement = [NSString stringWithFormat:@"PRAGMA %@.table_info ('%@');", database, table];
519
- } else {
520
- theSQLStatement = [NSString stringWithFormat:@"PRAGMA table_info ('%@');", table];
521
- }
522
-
523
- NSFNanoResult *result = [self executeSQL:theSQLStatement];
524
-
525
- return [result valuesForColumn:@"type"];
526
- }
527
-
528
- - (NSArray *)indexes
529
- {
530
- NSFNanoResult* result = [self executeSQL:@"SELECT name FROM sqlite_master WHERE type='index' ORDER BY name"];
531
-
532
- return [result valuesForColumn:@"sqlite_master.name"];
533
- }
534
-
535
- - (NSArray *)indexedColumnsForTable:(NSString *)table
536
- {
537
- if (nil == table)
538
- [[NSException exceptionWithName:NSFUnexpectedParameterException
539
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: table is nil.", [self class], _cmd]
540
- userInfo:nil]raise];
541
-
542
- NSFNanoResult* result = [self executeSQL:[NSString stringWithFormat:@"SELECT sqlite_master.name FROM sqlite_master WHERE type = 'index' AND sqlite_master.tbl_name = '%@';", table]];
543
- if ([result numberOfRows] == 0) {
544
- result = [self executeSQL:[NSString stringWithFormat:@"SELECT sqlite_temp_master.name FROM sqlite_temp_master WHERE type = 'index' AND sqlite_temp_master.tbl_name = '%@';", table]];
545
- return [result valuesForColumn:@"sqlite_temp_master.name"];
546
- }
547
-
548
- return [result valuesForColumn:@"sqlite_master.name"];
549
- }
550
-
551
- - (NSArray *)temporaryTables
552
- {
553
- NSFNanoResult* result = [self executeSQL:@"SELECT * FROM sqlite_temp_master"];
554
- return [[NSSet setWithArray:[result valuesForColumn:@"sqlite_temp_master.tbl_name"]]allObjects];
555
- }
556
-
557
- - (NSFNanoResult *)executeSQL:(NSString *)theSQLStatement
558
- {
559
- if (nil == theSQLStatement)
560
- [[NSException exceptionWithName:NSFUnexpectedParameterException
561
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: theSQLStatement is nil.", [self class], _cmd]
562
- userInfo:nil]raise];
563
-
564
- if ([theSQLStatement length] == 0)
565
- [[NSException exceptionWithName:NSFUnexpectedParameterException
566
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: theSQLStatement is empty.", [self class], _cmd]
567
- userInfo:nil]raise];
568
-
569
- // Check whether we will need to return a dictionary with results
570
- sqlite3 *sqliteStore = self.sqlite;
571
- NSMutableDictionary *info = [NSMutableDictionary dictionary];
572
- BOOL returnInfo = NO;
573
-
574
- for (NSString *sqlCommand in __NSFP_SQLCommandsReturningData) {
575
- if ([theSQLStatement compare:sqlCommand options:NSCaseInsensitiveSearch range:NSMakeRange(0, [sqlCommand length])] == NSOrderedSame) {
576
- returnInfo = YES;
577
- break;
578
- }
579
- }
580
-
581
- int status = SQLITE_OK;
582
- char *errorMessage = NULL;
583
-
584
- if (returnInfo) {
585
- sqlite3_stmt *theSQLiteStatement = NULL;
586
-
587
- status = sqlite3_prepare_v2 (sqliteStore, [theSQLStatement UTF8String], -1, &theSQLiteStatement, NULL );
588
-
589
- status = [NSFNanoEngine NSFP_stripBitsFromExtendedResultCode:status];
590
-
591
- if (SQLITE_OK == status) {
592
- info = [NSMutableDictionary dictionary];
593
- int columnIndex, numColumns = sqlite3_column_count (theSQLiteStatement);
594
-
595
- while (SQLITE_ROW == sqlite3_step (theSQLiteStatement)) {
596
- for (columnIndex = 0; columnIndex < numColumns; columnIndex++) {
597
- // Safety check: obtain the column and value. If the column is NULL, skip the iteration.
598
- char *columnUTF8 = (char *)sqlite3_column_name (theSQLiteStatement, columnIndex);
599
- if (NULL == columnUTF8) {
600
- continue;
601
- }
602
- NSString *column = [[NSString alloc]initWithUTF8String:columnUTF8];
603
-
604
- // Sanity check: some queries return NULL, which would cause a crash below.
605
- char *valueUTF8 = (char *)sqlite3_column_text (theSQLiteStatement, columnIndex);
606
- NSString *value = nil;
607
- if (NULL != valueUTF8) {
608
- value = [[NSString alloc]initWithUTF8String:valueUTF8];
609
- } else {
610
- value = [[NSNull null]description];
611
- }
612
-
613
- // Obtain the array to collect the values. If the array doesn't exist, create it.
614
- NSMutableArray *values = [info objectForKey:column];
615
- if (nil == values) {
616
- values = [NSMutableArray new];
617
- }
618
- [values addObject:value];
619
- [info setObject:values forKey:column];
620
-
621
- // Let's cleanup. This will keep the memory footprint low...
622
- }
623
-
624
- }
625
-
626
- sqlite3_finalize (theSQLiteStatement);
627
- }
628
- } else {
629
- status = sqlite3_exec(sqliteStore, [theSQLStatement UTF8String], NULL, NULL, &errorMessage);
630
-
631
- // Since we're operating with extended result code support, extract the bits
632
- // and obtain the regular result code
633
- // For more info check: http://www.sqlite.org/c3ref/c_ioerr_access.html
634
-
635
- status = [NSFNanoEngine NSFP_stripBitsFromExtendedResultCode:status];
636
- }
637
-
638
- NSFNanoResult *result = nil;
639
-
640
- if (SQLITE_OK != status) {
641
- NSString *msg = (NULL != errorMessage) ? [NSString stringWithUTF8String:errorMessage] : [NSString stringWithFormat:@"SQLite error ID: %ld", status];
642
- result = [NSFNanoResult _resultWithError:[NSError errorWithDomain:NSFDomainKey
643
- code:NSFNanoStoreErrorKey
644
- userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"*** -[%@ %s]: %@", [self class], _cmd, msg]
645
- forKey:NSLocalizedFailureReasonErrorKey]]];
646
- } else {
647
- result = [NSFNanoResult _resultWithDictionary:info];
648
- }
649
-
650
- // Cleanup
651
- if (NULL != errorMessage) {
652
- sqlite3_free (errorMessage);
653
- }
654
-
655
- return result;
656
- }
657
-
658
- - (long long)maxRowUIDForTable:(NSString *)table
659
- {
660
- if (nil == table) {
661
- [[NSException exceptionWithName:NSFUnexpectedParameterException
662
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: theSQLStatement is nil.", [self class], _cmd]
663
- userInfo:nil]raise];
664
- }
665
-
666
- NSString *sql = [[NSString alloc]initWithFormat:@"SELECT max(ROWID) FROM %@", table];
667
-
668
- NSFNanoResult *result = [self executeSQL:sql];
669
-
670
-
671
- return [[result firstValue]longLongValue];
672
- }
673
-
674
- #pragma mark// ==================================
675
- #pragma mark// SQLite Tunning Methods
676
- #pragma mark// ==================================
677
-
678
- - (void)setBusyTimeout:(unsigned int)theTimeout
679
- {
680
- // If the timeout is out-of-range, default the value
681
- if ((theTimeout < 100) || (theTimeout > 5 * 1000)) {
682
- theTimeout = 250;
683
- }
684
-
685
- busyTimeout = theTimeout;
686
-
687
- sqlite3_busy_timeout(self.sqlite, busyTimeout);
688
- }
689
-
690
- - (unsigned int)busyTimeout
691
- {
692
- return busyTimeout;
693
- }
694
-
695
- + (NSInteger)systemPageSize
696
- {
697
- static NSUInteger __sSystemPageSize = NSNotFound;
698
-
699
- if (NSNotFound == __sSystemPageSize) {
700
- __sSystemPageSize = getpagesize();
701
- }
702
-
703
- return __sSystemPageSize;
704
- }
705
-
706
- + (NSUInteger)recommendedCacheSize
707
- {
708
- static NSUInteger __sRecommendedCacheSize = NSNotFound;
709
-
710
- if (NSNotFound == __sRecommendedCacheSize) {
711
- NSUInteger defaultNanoStoreEngineCacheSize = 10000;
712
- unsigned long long physMem = [[NSProcessInfo processInfo] physicalMemory];
713
-
714
- physMem = physMem / (512 * 1024 * 1000);
715
- __sRecommendedCacheSize = (NSInteger)physMem * defaultNanoStoreEngineCacheSize;
716
- if (0 == __sRecommendedCacheSize) {
717
- __sRecommendedCacheSize = defaultNanoStoreEngineCacheSize;
718
- }
719
- }
720
-
721
- return __sRecommendedCacheSize;
722
- }
723
-
724
- - (BOOL)setCacheSize:(NSUInteger)numberOfPages
725
- {
726
- if (numberOfPages < 1000)
727
- numberOfPages = 1000;
728
-
729
- [self executeSQL:[NSString stringWithFormat:@"PRAGMA cache_size = %ld", numberOfPages]];
730
- NSUInteger cacheSize = [self cacheSize];
731
- return (cacheSize == numberOfPages);
732
- }
733
-
734
- - (NSUInteger)cacheSize
735
- {
736
- NSFNanoResult *result = [self executeSQL:@"PRAGMA cache_size;"];
737
- NSString *value = [result firstValue];
738
- return [value integerValue];
739
- }
740
-
741
- - (BOOL)setPageSize:(NSUInteger)numberOfBytes
742
- {
743
- [self executeSQL:[NSString stringWithFormat:@"PRAGMA page_size = %ld", numberOfBytes]];
744
- NSUInteger pageSize = [self pageSize];
745
- return (pageSize == numberOfBytes);
746
- }
747
-
748
- - (NSUInteger)pageSize
749
- {
750
- NSFNanoResult *result = [self executeSQL:@"PRAGMA page_size;"];
751
- NSString *value = [result firstValue];
752
- return [value integerValue];
753
- }
754
-
755
- - (BOOL)setEncodingType:(NSFEncodingType)theEncodingType
756
- {
757
- BOOL success = NO;
758
-
759
- if (NSFEncodingUTF8 == theEncodingType) {
760
- [self executeSQL:@"PRAGMA encoding = \"UTF-8\";"];
761
- NSFEncodingType encoding = [self encoding];
762
- success = (NSFEncodingUTF8 == encoding);
763
- } else if (NSFEncodingUTF16 == theEncodingType) {
764
- [self executeSQL:@"PRAGMA encoding = \"UTF-16\";"];
765
- NSFEncodingType encoding = [self encoding];
766
- success = (NSFEncodingUTF16 == encoding);
767
- }
768
-
769
- return success;
770
- }
771
-
772
- - (NSFEncodingType)encoding
773
- {
774
- NSFNanoResult *result = [self executeSQL:@"pragma encoding;"];
775
- NSString *value = [result firstValue];
776
- return [NSFNanoEngine NSStringToNSFEncodingType:value];
777
- }
778
-
779
- + (NSFEncodingType)NSStringToNSFEncodingType:(NSString *)value
780
- {
781
- NSFEncodingType convertedValue = NSFEncodingUnknown;
782
-
783
- if (YES == [value isEqualToString:@"UTF-8"]) {
784
- convertedValue = NSFEncodingUTF8;
785
- } else if (YES == [value isEqualToString:@"UTF-16"]) {
786
- convertedValue = NSFEncodingUTF16;
787
- }
788
-
789
- return convertedValue;
790
- }
791
-
792
- + (NSString *)NSFEncodingTypeToNSString:(NSFEncodingType)value
793
- {
794
- NSString *convertedValue = nil;
795
-
796
- if (NSFEncodingUTF8 == value) {
797
- convertedValue = @"UTF-8";
798
- } else if (NSFEncodingUTF16 == value) {
799
- convertedValue = @"UTF-16";
800
- }
801
-
802
- return convertedValue;
803
- }
804
-
805
- - (NSFSynchronousMode)synchronousMode
806
- {
807
- NSFNanoResult* result = [self executeSQL:@"PRAGMA synchronous"];
808
- return [[[result valuesForColumn:@"synchronous"]lastObject]intValue];
809
- }
810
-
811
- - (void)setSynchronousMode:(NSFSynchronousMode)mode
812
- {
813
- switch (mode) {
814
- case SynchronousModeOff:
815
- [self executeSQL:@"PRAGMA synchronous = OFF;"];
816
- break;
817
- case SynchronousModeFull:
818
- [self executeSQL:@"PRAGMA synchronous = FULL;"];
819
- break;
820
- default:
821
- [self executeSQL:@"PRAGMA synchronous = NORMAL;"];
822
- break;
823
- }
824
- }
825
-
826
- - (NSFTempStoreMode)tempStoreMode
827
- {
828
- NSFNanoResult* result = [self executeSQL:@"PRAGMA temp_store"];
829
-
830
- return [[[result valuesForColumn:@"temp_store"]lastObject]intValue];
831
- }
832
-
833
- - (void)setTempStoreMode:(NSFTempStoreMode)mode
834
- {
835
- switch (mode) {
836
- case TempStoreModeFile:
837
- [self executeSQL:@"PRAGMA temp_store = FILE"];
838
- break;
839
- case TempStoreModeMemory:
840
- [self executeSQL:@"PRAGMA temp_store = MEMORY"];
841
- break;
842
- default:
843
- [self executeSQL:@"PRAGMA temp_store = DEFAULT"];
844
- break;
845
- }
846
- }
847
-
848
- - (NSFJournalModeMode)journalModeAndReturnError:(out NSError **)outError
849
- {
850
- NSFNanoResult *result = [self executeSQL:@"PRAGMA journal_mode; "];
851
- if (nil != [result error]) {
852
- if (nil != outError) {
853
- *outError = [[result error]copy];
854
- return JournalModeDelete;
855
- }
856
- }
857
-
858
- NSString *journalModeString = [result firstValue];
859
- if ([journalModeString isEqualToString:@"TRUNCATE"]) return JournalModeDelete;
860
- else if ([journalModeString isEqualToString:@"TRUNCATE"]) return JournalModeTruncate;
861
- else if ([journalModeString isEqualToString:@"PERSIST"]) return JournalModePersist;
862
- else if ([journalModeString isEqualToString:@"MEMORY"]) return JournalModeMemory;
863
- else if ([journalModeString isEqualToString:@"WAL"]) return JournalModeWAL;
864
- else return JournalModeOFF;
865
- }
866
-
867
- - (BOOL)setJournalMode:(NSFJournalModeMode)theMode
868
- {
869
- if (YES == [self isTransactionActive]) {
870
- return NO;
871
- }
872
-
873
- NSString *theModeString = nil;
874
-
875
- switch (theMode) {
876
- case JournalModeTruncate:
877
- theModeString = @"TRUNCATE";
878
- break;
879
- case JournalModePersist:
880
- theModeString = @"PERSIST";
881
- break;
882
- case JournalModeMemory:
883
- theModeString = @"MEMORY";
884
- break;
885
- case JournalModeWAL:
886
- theModeString = @"WAL";
887
- break;
888
- case JournalModeOFF:
889
- theModeString = @"OFF";
890
- break;
891
- default:
892
- theModeString = @"DELETE";
893
- break;
894
- }
895
-
896
- [self executeSQL:[NSString stringWithFormat:@"PRAGMA journal_mode = %@", theModeString]];
897
-
898
- NSFJournalModeMode verificationMode = [self journalModeAndReturnError:nil];
899
-
900
- return (verificationMode == theMode);
901
- }
902
-
903
- #pragma mark// ==================================
904
- #pragma mark// Binary Data Methods
905
- #pragma mark// ==================================
906
-
907
- + (NSString *)encodeDataToBase64:(NSData*)data
908
- {
909
- if (nil == data)
910
- [[NSException exceptionWithName:NSFUnexpectedParameterException
911
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: data is nil.", [self class], _cmd]
912
- userInfo:nil]raise];
913
-
914
- NSInteger decodedDataSize = [data length];
915
- unsigned char *bytes = (unsigned char *)malloc(decodedDataSize);
916
-
917
- // Extract the bytes
918
- [data getBytes:bytes];
919
-
920
- unsigned char inBuffer[3];
921
- unsigned char outBuffer[4];
922
- NSInteger i;
923
- NSInteger segments;
924
- char *outputBuffer;
925
- char *base64Buffer;
926
-
927
- base64Buffer = outputBuffer = (char *)malloc (decodedDataSize * 4 / 3 + 4);
928
- if (NULL == outputBuffer) {
929
- free (bytes);
930
- return nil;
931
- }
932
-
933
- while (decodedDataSize > 0) {
934
- for (i = segments = 0; i < 3; i++) {
935
- if (decodedDataSize > 0) {
936
- segments++;
937
- inBuffer[i] = *(bytes + i);
938
- decodedDataSize--;
939
- } else
940
- inBuffer[i] = 0;
941
- }
942
-
943
- outBuffer [0] = (inBuffer [0] & 0xFC) >> 2;
944
- outBuffer [1] = ((inBuffer [0] & 0x03) << 4) | ((inBuffer [1] & 0xF0) >> 4);
945
- outBuffer [2] = ((inBuffer [1] & 0x0F) << 2) | ((inBuffer [2] & 0xC0) >> 6);
946
- outBuffer [3] = inBuffer [2] & 0x3F;
947
-
948
- switch (segments) {
949
- case 1:
950
- sprintf(outputBuffer, "%c%c==",
951
- __NSFP_base64Table[outBuffer[0]],
952
- __NSFP_base64Table[outBuffer[1]]);
953
- break;
954
- case 2:
955
- sprintf(outputBuffer, "%c%c%c=",
956
- __NSFP_base64Table[outBuffer[0]],
957
- __NSFP_base64Table[outBuffer[1]],
958
- __NSFP_base64Table[outBuffer[2]]);
959
- break;
960
- default:
961
- sprintf(outputBuffer, "%c%c%c%c",
962
- __NSFP_base64Table[outBuffer[0]],
963
- __NSFP_base64Table[outBuffer[1]],
964
- __NSFP_base64Table[outBuffer[2]],
965
- __NSFP_base64Table[outBuffer[3]] );
966
- break;
967
- }
968
-
969
- outputBuffer += 4;
970
- }
971
-
972
- *outputBuffer = 0;
973
-
974
- NSString *myBase64Data = [NSString stringWithUTF8String:base64Buffer];
975
-
976
- free (base64Buffer);
977
- free (bytes);
978
-
979
- return myBase64Data;
980
- }
981
-
982
- + (NSData*)decodeDataFromBase64:(NSString *)encodedData
983
- {
984
- if (nil == encodedData)
985
- [[NSException exceptionWithName:NSFUnexpectedParameterException
986
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: encodedData is nil.", [self class], _cmd]
987
- userInfo:nil]raise];
988
-
989
- const char* source = [encodedData UTF8String];
990
- NSUInteger sourceLength = strlen(source);
991
- char* destination = (char *)malloc(sourceLength * 3/4 + 8);
992
- char* destinationPtr = destination;
993
-
994
- NSInteger length = 0;
995
- NSInteger pivot = 0;
996
- NSInteger i;
997
- NSInteger numSegments;
998
- unsigned char lastSegment[3];
999
- NSUInteger decodedLength = 0;
1000
-
1001
- while ((source[length] != '=') && source[length])
1002
- length++;
1003
- while (source[length+pivot] == '=')
1004
- pivot++;
1005
-
1006
- numSegments = (length + pivot) / 4;
1007
-
1008
- decodedLength = (numSegments * 3) - pivot;
1009
-
1010
- for (i = 0; i < numSegments - 1; i++) {
1011
- [self NSFP_decodeQuantum:(unsigned char *)destination andSource:source];
1012
- destination += 3;
1013
- source += 4;
1014
- }
1015
-
1016
- [self NSFP_decodeQuantum:lastSegment andSource:source];
1017
-
1018
- for (i = 0; i < 3 - pivot; i++)
1019
- destination[i] = lastSegment[i];
1020
-
1021
- // Construct a NSData with the decoded data
1022
- NSData* myDummyData = [NSData dataWithBytes:destinationPtr length:decodedLength];
1023
-
1024
- // Cleanup
1025
- free (destinationPtr);
1026
-
1027
- return myDummyData;
1028
- }
1029
-
1030
- #pragma mark// ==================================
1031
- #pragma mark// NSFNanoEngine Private Methods
1032
- #pragma mark// ==================================
1033
-
1034
- /** \cond */
1035
-
1036
- + (NSArray *)NSFP_sharedROWIDKeywords
1037
- {
1038
- if (nil == __NSFPSharedROWIDKeywords)
1039
- __NSFPSharedROWIDKeywords = [[NSArray alloc]initWithObjects:@"ROWID", @"OID", @"_ROWID_", nil];
1040
-
1041
- return __NSFPSharedROWIDKeywords;
1042
- }
1043
-
1044
- - (NSString *)NSFP_cacheMethodToString
1045
- {
1046
- switch (cacheMethod) {
1047
- case CacheAllData:
1048
- return @"Cache all data";
1049
- break;
1050
- case CacheDataOnDemand:
1051
- return @"Cache data on demand";
1052
- break;
1053
- default:
1054
- return @"Do not cache data";
1055
- break;
1056
- }
1057
-
1058
- return @"<unknown cache method";
1059
- }
1060
-
1061
- + (int)NSFP_stripBitsFromExtendedResultCode:(int)extendedResult
1062
- {
1063
- return (extendedResult & 0x00FF);
1064
- }
1065
-
1066
- - (NSString*)NSFP_nestedDescriptionWithPrefixedSpace:(NSString *)prefixedSpace
1067
- {
1068
- if (nil == prefixedSpace) {
1069
- prefixedSpace = @"";
1070
- }
1071
-
1072
- NSMutableString *description = [NSMutableString string];
1073
- [description appendString:@"\n"];
1074
- [description appendString:[NSString stringWithFormat:@"%@SQLite address : 0x%x\n", prefixedSpace, self.sqlite]];
1075
- [description appendString:[NSString stringWithFormat:@"%@Database path : %@\n", prefixedSpace, path]];
1076
- [description appendString:[NSString stringWithFormat:@"%@Cache method : %@\n", prefixedSpace, [self NSFP_cacheMethodToString]]];
1077
-
1078
- return description;
1079
- }
1080
-
1081
- + (NSDictionary *)_plistToDictionary:(NSString *)aPlist
1082
- {
1083
- if (nil == aPlist)
1084
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1085
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: aPlist is nil.", [self class], _cmd]
1086
- userInfo:nil]raise];
1087
-
1088
- if ([aPlist length] == 0)
1089
- return nil;
1090
-
1091
- // Some sanity check...
1092
- if ([NSPropertyListSerialization propertyList:aPlist isValidForFormat:NSPropertyListXMLFormat_v1_0] == NO)
1093
- return nil;
1094
-
1095
- NSString *errorString = nil;
1096
- NSPropertyListFormat *format = nil;
1097
- NSData *data = [aPlist dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
1098
- NSDictionary *dict = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:NSPropertyListImmutable format:format errorDescription:&errorString];
1099
-
1100
- if (nil == dict) {
1101
- NSLog(@"*** -[%@ %@]: [NSPropertyListSerialization propertyListFromData] failure. %@", [self class], NSStringFromSelector(_cmd), errorString);
1102
- NSLog(@" Plist data: %@", aPlist);
1103
- return nil;
1104
- }
1105
-
1106
- return dict;
1107
- }
1108
-
1109
- + (void)NSFP_decodeQuantum:(unsigned char*)dest andSource:(const char *)src
1110
- {
1111
- if (nil == dest)
1112
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1113
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: dest is nil.", [self class], _cmd]
1114
- userInfo:nil]raise];
1115
-
1116
- if (nil == src)
1117
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1118
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: src is nil.", [self class], _cmd]
1119
- userInfo:nil]raise];
1120
-
1121
- NSUInteger x = 0;
1122
- NSInteger i;
1123
- for (i = 0; i < 4; i++) {
1124
- if (src[i] >= 'A' && src[i] <= 'Z')
1125
- x = (x << 6) + (NSUInteger)(src[i] - 'A' + 0);
1126
- else if (src[i] >= 'a' && src[i] <= 'z')
1127
- x = (x << 6) + (NSUInteger)(src[i] - 'a' + 26);
1128
- else if (src[i] >= '0' && src[i] <= '9')
1129
- x = (x << 6) + (NSUInteger)(src[i] - '0' + 52);
1130
- else if (src[i] == '+')
1131
- x = (x << 6) + 62;
1132
- else if (src[i] == '/')
1133
- x = (x << 6) + 63;
1134
- else if (src[i] == '=')
1135
- x = (x << 6);
1136
- }
1137
-
1138
- dest[2] = (unsigned char)(x & 255);
1139
- x >>= 8;
1140
- dest[1] = (unsigned char)(x & 255);
1141
- x >>= 8;
1142
- dest[0] = (unsigned char)(x & 255);
1143
- }
1144
-
1145
- - (NSFNanoDatatype)NSFP_datatypeForColumn:(NSString *)tableAndColumn
1146
- {
1147
- if (nil == tableAndColumn)
1148
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1149
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: tableAndColumn is nil.", [self class], _cmd]
1150
- userInfo:nil]raise];
1151
-
1152
- NSString *table = [self NSFP_prefixWithDotDelimiter:tableAndColumn];
1153
- NSString *column = [self NSFP_suffixWithDotDelimiter:tableAndColumn];
1154
-
1155
- return [self NSFP_datatypeForTable:(NSString *)table column:(NSString *)column];
1156
- }
1157
-
1158
- - (NSFNanoDatatype)NSFP_datatypeForTable:(NSString *)table column:(NSString *)column
1159
- {
1160
- if (nil == table)
1161
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1162
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: table is nil.", [self class], _cmd]
1163
- userInfo:nil]raise];
1164
-
1165
- if (nil == column)
1166
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1167
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: column is nil.", [self class], _cmd]
1168
- userInfo:nil]raise];
1169
-
1170
- NSString *datatype = nil;
1171
-
1172
- // Check to see if the schema has been cached; take advantage of it if possible...
1173
- if (nil != schema) {
1174
- datatype = [[schema objectForKey:table]objectForKey:column];
1175
- if (nil == datatype) datatype = NSFStringFromNanoDataType(NSFNanoTypeUnknown);
1176
- } else {
1177
- NSString *theSQLStatement = [NSString stringWithFormat:@"SELECT %@ from %@ WHERE %@ = '%@' AND %@ = '%@';", NSFP_DatatypeIdentifier, NSFP_SchemaTable, NSFP_TableIdentifier, table, NSFP_ColumnIdentifier, column];
1178
-
1179
- NSFNanoResult* result = [self executeSQL:theSQLStatement];
1180
-
1181
- datatype = [[result valuesForColumn:NSFP_FullDatatypeIdentifier]lastObject];
1182
-
1183
- if (nil == datatype) datatype = NSFStringFromNanoDataType(NSFNanoTypeUnknown);
1184
-
1185
- NSMutableDictionary *tempSchema = [schema objectForKey:table];
1186
- if (nil != tempSchema)
1187
- tempSchema = [[NSMutableDictionary alloc]init];
1188
- else
1189
- ;
1190
-
1191
- [tempSchema setObject:datatype forKey:column];
1192
- [schema setObject:tempSchema forKey:table];
1193
-
1194
- tempSchema = nil;
1195
- }
1196
-
1197
- return NSFNanoDatatypeFromString(datatype);
1198
- }
1199
-
1200
- - (void)NSFP_setFullColumnNamesEnabled
1201
- {
1202
- [self executeSQL:@"PRAGMA short_column_names = OFF;"];
1203
- [self executeSQL:@"PRAGMA full_column_names = ON;"];
1204
- }
1205
-
1206
- - (NSArray *)NSFP_flattenAllTables
1207
- {
1208
- NSMutableSet *flattenedTables = [[NSMutableSet alloc]init];
1209
- NSDictionary *allTables = [self allTables];
1210
- NSEnumerator *enumerator = [allTables keyEnumerator];
1211
- NSString *database;
1212
- BOOL addPrefix = ([allTables count] > 1);
1213
-
1214
- while ((database = [enumerator nextObject])) {
1215
- NSArray *databaseTables = [allTables objectForKey:database];
1216
-
1217
- if ((YES == addPrefix) && ([database hasPrefix:@"main"] == NO)) {
1218
- for (NSString *table in databaseTables) {
1219
- [flattenedTables addObject:[NSString stringWithFormat:@"%@.%@", database, table]];
1220
- }
1221
- } else {
1222
- [flattenedTables addObjectsFromArray:databaseTables];
1223
- }
1224
- }
1225
-
1226
- NSArray *immutableValues = [flattenedTables allObjects];
1227
-
1228
- flattenedTables = nil;
1229
-
1230
- return immutableValues;
1231
- }
1232
-
1233
- - (NSInteger)NSFP_prepareSQLite3Statement:(sqlite3_stmt **)aStatement theSQLStatement:(NSString *)aSQLQuery
1234
- {
1235
- if (nil == aSQLQuery)
1236
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1237
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: aSQLQuery is nil.", [self class], _cmd]
1238
- userInfo:nil]raise];
1239
-
1240
- // Prepare SQLite's VM. It's placed here so we can speed up stores...
1241
- int status = SQLITE_OK;
1242
- BOOL continueLooping = YES;
1243
- const char *query = [aSQLQuery UTF8String];
1244
-
1245
- do {
1246
- status = sqlite3_prepare_v2(self.sqlite, query, -1, aStatement, NULL);
1247
-
1248
- // Since we're operating with extended result code support, extract the bits
1249
- // and obtain the regular result code
1250
- // For more info check: http://www.sqlite.org/c3ref/c_ioerr_access.html
1251
-
1252
- status = [NSFNanoEngine NSFP_stripBitsFromExtendedResultCode:status];
1253
-
1254
- continueLooping = ((SQLITE_LOCKED == status) || (SQLITE_BUSY == status));
1255
- } while (continueLooping);
1256
-
1257
- return status;
1258
- }
1259
-
1260
- - (BOOL)NSFP_beginTransactionMode:(NSString *)theSQLStatement
1261
- {
1262
- if (nil == theSQLStatement)
1263
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1264
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: theSQLStatement is nil.", [self class], _cmd]
1265
- userInfo:nil]raise];
1266
-
1267
- if ([self isTransactionActive] == NO) {
1268
- sqlite3_stmt *NSF_sqliteVM;
1269
- const char *query_tail = [theSQLStatement UTF8String];
1270
-
1271
- int status = sqlite3_prepare_v2(self.sqlite, query_tail, -1, &NSF_sqliteVM, &query_tail);
1272
-
1273
- // Since we're operating with extended result code support, extract the bits
1274
- // and obtain the regular result code
1275
- // For more info check: http://www.sqlite.org/c3ref/c_ioerr_access.html
1276
-
1277
- status = [NSFNanoEngine NSFP_stripBitsFromExtendedResultCode:status];
1278
-
1279
- if (SQLITE_OK == status) {
1280
- BOOL continueTrying = YES;
1281
-
1282
- do {
1283
- status = sqlite3_step(NSF_sqliteVM);
1284
-
1285
- // Since we're operating with extended result code support, extract the bits
1286
- // and obtain the regular result code
1287
- // For more info check: http://www.sqlite.org/c3ref/c_ioerr_access.html
1288
-
1289
- status = [NSFNanoEngine NSFP_stripBitsFromExtendedResultCode:status];
1290
-
1291
- switch (status) {
1292
- case SQLITE_OK:
1293
- case SQLITE_DONE:
1294
- continueTrying = NO;
1295
- break;
1296
- case SQLITE_BUSY:
1297
- [self rollbackTransaction];
1298
- sqlite3_reset(NSF_sqliteVM);
1299
- continueTrying = YES;
1300
- break;
1301
- default:
1302
- [self rollbackTransaction];
1303
- continueTrying = NO;
1304
- break;
1305
- }
1306
- } while (continueTrying);
1307
-
1308
- return (SQLITE_OK == sqlite3_finalize(NSF_sqliteVM));
1309
- }
1310
- }
1311
-
1312
- return NO;
1313
- }
1314
-
1315
- - (BOOL)NSFP_createTable:(NSString *)table withColumns:(NSArray *)tableColumns datatypes:(NSArray *)tableDatatypes isTemporary:(BOOL)isTemporaryFlag
1316
- {
1317
- if (nil == table)
1318
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1319
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: table is nil.", [self class], _cmd]
1320
- userInfo:nil]raise];
1321
-
1322
- if (nil == tableColumns)
1323
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1324
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: tableColumns is nil.", [self class], _cmd]
1325
- userInfo:nil]raise];
1326
-
1327
- if (nil == tableDatatypes)
1328
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1329
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: tableDatatypes is nil.", [self class], _cmd]
1330
- userInfo:nil]raise];
1331
-
1332
- if ([tableColumns count] != [tableDatatypes count])
1333
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1334
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: number of columns and datatypes mismatch.", [self class], _cmd]
1335
- userInfo:nil]raise];
1336
-
1337
- NSSet *allowedDatatypes = [NSFNanoEngine sharedNanoStoreEngineDatatypes];
1338
- NSSet *specifiedDatatypes = [NSSet setWithArray:tableDatatypes];
1339
-
1340
- if (NO == [specifiedDatatypes isSubsetOfSet:allowedDatatypes])
1341
- return NO;
1342
-
1343
- // Make sure we have specified ROWID in the group of columns
1344
- NSMutableArray *revisedColumns = [[NSMutableArray alloc]initWithArray:tableColumns];
1345
- NSMutableArray *revisedDatatypes = [[NSMutableArray alloc]initWithArray:tableDatatypes];
1346
- NSInteger ROWIDIndex = [self NSFP_ROWIDPresenceLocation:tableColumns datatypes:tableDatatypes];
1347
- NSString *ROWIDDatatype = [[NSString alloc]initWithFormat:@"%@ PRIMARY KEY", NSFStringFromNanoDataType(NSFNanoTypeRowUID)];
1348
-
1349
- if (NSNotFound != ROWIDIndex) {
1350
- // Even though the ROWID has been specified by the user, we make sure the datatype is correct
1351
- [revisedDatatypes replaceObjectAtIndex:ROWIDIndex withObject:ROWIDDatatype];
1352
- } else {
1353
- // ROWID not found:add it manually
1354
- [revisedColumns insertObject:NSFRowIDColumnName atIndex:0];
1355
- [revisedDatatypes insertObject:ROWIDDatatype atIndex:0];
1356
- }
1357
-
1358
-
1359
- BOOL transactionSetHere = NO;
1360
- if (NO == [self isTransactionActive])
1361
- transactionSetHere = [self beginTransaction];
1362
-
1363
- BOOL everythingIsFine = YES;
1364
-
1365
- NSMutableString* theSQLStatement;
1366
- if (YES == isTemporaryFlag)
1367
- theSQLStatement = [[NSMutableString alloc]initWithString:[NSString stringWithFormat:@"CREATE TEMPORARY TABLE %@(", table]];
1368
- else
1369
- theSQLStatement = [[NSMutableString alloc]initWithString:[NSString stringWithFormat:@"CREATE TABLE %@(", table]];
1370
-
1371
- NSMutableArray *tableCreationDatatypes = [NSMutableArray arrayWithArray:revisedDatatypes];
1372
-
1373
- if (YES == [self NSFP_sqlString:theSQLStatement forTable:table withColumns:revisedColumns datatypes:tableCreationDatatypes]) {
1374
- [theSQLStatement appendString:@");"];
1375
-
1376
- everythingIsFine = (nil == [[self executeSQL:theSQLStatement]error]);
1377
-
1378
- if (everythingIsFine) {
1379
- // Now add the entries to NSFP_SchemaTable
1380
- NSInteger i, count = [revisedDatatypes count];
1381
-
1382
- for (i = 0; i < count; i++) {
1383
- if (NO == [self NSFP_insertStringValues:[NSArray arrayWithObjects:table, [revisedColumns objectAtIndex:i], [revisedDatatypes objectAtIndex:i], nil] forColumns:[NSArray arrayWithObjects:NSFP_TableIdentifier, NSFP_ColumnIdentifier, NSFP_DatatypeIdentifier, nil]table:NSFP_SchemaTable]) {
1384
- everythingIsFine = NO;
1385
- break;
1386
- }
1387
- }
1388
- }
1389
- } else {
1390
- everythingIsFine = NO;
1391
- }
1392
-
1393
- if (transactionSetHere) {
1394
- if (everythingIsFine)
1395
- [self commitTransaction];
1396
- else
1397
- [self rollbackTransaction];
1398
- }
1399
-
1400
- if (everythingIsFine)
1401
- [self NSFP_rebuildDatatypeCache];
1402
-
1403
- return everythingIsFine;
1404
- }
1405
-
1406
- - (BOOL)NSFP_removeColumn:(NSString *)column fromTable:(NSString *)table
1407
- {
1408
- // Obtain all current columns and datatypes for table
1409
- NSArray *tableInfoDatatypes = [self datatypesForTable:table];
1410
-
1411
- if (nil == column)
1412
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1413
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: column is nil.", [self class], _cmd]
1414
- userInfo:nil]raise];
1415
-
1416
- if (nil == table)
1417
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1418
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: table is nil.", [self class], _cmd]
1419
- userInfo:nil]raise];
1420
-
1421
- NSArray *tableInfoColumns = [self columnsForTable:table];
1422
-
1423
- NSInteger index = [tableInfoColumns indexOfObject:column];
1424
-
1425
- if (index == NSNotFound)
1426
- return NO;
1427
-
1428
- // Add the new column and data type to the list
1429
- NSMutableArray *tableColumns = [[NSMutableArray alloc]initWithArray:tableInfoColumns];
1430
- NSMutableArray *tableDatatypes = [[NSMutableArray alloc]initWithArray:tableInfoDatatypes];
1431
- [tableColumns removeObjectAtIndex:index];
1432
- [tableDatatypes removeObjectAtIndex:index];
1433
-
1434
- BOOL transactionSetHere = NO;
1435
- if (NO == [self isTransactionActive])
1436
- transactionSetHere = [self beginTransaction];
1437
-
1438
- // Create a backup table with the columns and datatypes
1439
- NSUInteger numberOfIssues = 0;
1440
-
1441
- BOOL isTableTemporary = [[self temporaryTables]containsObject:table];
1442
- if ([self NSFP_createTable:[NSString stringWithFormat:@"%@_backup", table] withColumns:tableColumns datatypes:tableDatatypes isTemporary:isTableTemporary]) {
1443
- // Insert all existing data
1444
- NSMutableString* query = [NSMutableString stringWithString:[NSString stringWithFormat:@"INSERT INTO %@_backup(", table]];
1445
-
1446
- [self NSFP_sqlString:query appendingTags:tableColumns];
1447
- [query appendString:@") SELECT "];
1448
- [self NSFP_sqlString:query appendingTags:tableColumns];
1449
-
1450
- if (nil == [[self executeSQL:[NSString stringWithFormat:@"%@ FROM %@;", query, table]]error])
1451
- numberOfIssues++;
1452
-
1453
- // Delete the old table
1454
- if ([self dropTable:table] == NO)
1455
- numberOfIssues++;
1456
-
1457
- // Create the new table with the columns and datatypes
1458
- isTableTemporary = [[self temporaryTables]containsObject:table];
1459
- if ([self NSFP_createTable:table withColumns:tableColumns datatypes:tableDatatypes isTemporary:isTableTemporary] == NO)
1460
- numberOfIssues++;
1461
-
1462
- // Copy the data from the backup table
1463
- query = [NSMutableString stringWithString:[NSString stringWithFormat:@"INSERT INTO %@(", table]];
1464
-
1465
- [self NSFP_sqlString:query appendingTags:tableColumns];
1466
- [query appendString:@") SELECT "];
1467
- [self NSFP_sqlString:query appendingTags:tableColumns];
1468
-
1469
- if (nil == [[self executeSQL:[NSString stringWithFormat:@"%@ FROM %@_backup;", query, table]]error])
1470
- numberOfIssues++;
1471
-
1472
- // Delete the backup table
1473
- if ([self dropTable:[NSString stringWithFormat:@"%@_backup", table]] == NO)
1474
- numberOfIssues++;
1475
- } else {
1476
- numberOfIssues++;
1477
- }
1478
-
1479
- if (transactionSetHere) {
1480
- if (0 == numberOfIssues) {
1481
- [self commitTransaction];
1482
- } else {
1483
- [self rollbackTransaction];
1484
- }
1485
- }
1486
-
1487
- if (0 == numberOfIssues)
1488
- [self NSFP_rebuildDatatypeCache];
1489
-
1490
- return (0 == numberOfIssues);
1491
- }
1492
-
1493
- - (void)NSFP_rebuildDatatypeCache
1494
- {
1495
- // Cleanup
1496
- schema = nil;
1497
- schema = [[NSMutableDictionary alloc]init];
1498
-
1499
- NSArray *tables = [self NSFP_flattenAllTables];
1500
- if ([tables count] == 0)
1501
- return;
1502
-
1503
- for (NSString *table in tables) {
1504
- NSArray *columns = [self columnsForTable:table];
1505
- NSArray *datatypes = [self datatypesForTable:table];
1506
- if ((nil == table) || (nil != columns) || (nil != datatypes)) {
1507
- break;
1508
- }
1509
-
1510
- // Build the dictionary
1511
- NSMutableDictionary *tableDictionary = [[NSMutableDictionary alloc]init];
1512
- NSInteger j, columnCount = [columns count];
1513
-
1514
- for (j = 0; j < columnCount; j++) {
1515
- [tableDictionary setObject:[datatypes objectAtIndex:j] forKey:[columns objectAtIndex:j]];
1516
- }
1517
-
1518
- [schema setObject:tableDictionary forKey:table];
1519
- }
1520
- }
1521
-
1522
- - (BOOL)NSFP_insertStringValues:(NSArray *)values forColumns:(NSArray *)columns table:(NSString *)table
1523
- {
1524
- if (nil == values)
1525
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1526
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: values is nil.", [self class], _cmd]
1527
- userInfo:nil]raise];
1528
-
1529
- if (nil == columns)
1530
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1531
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: columns is nil.", [self class], _cmd]
1532
- userInfo:nil]raise];
1533
-
1534
- if (nil == table)
1535
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1536
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: table is nil.", [self class], _cmd]
1537
- userInfo:nil]raise];
1538
-
1539
- // Make sure we have specified ROWID in the group of columns
1540
- NSMutableArray *revisedColumns = (NSMutableArray*)columns;
1541
-
1542
- // Escape all values except the one with type NSFNanoTypeRowUID
1543
- NSMutableArray *escapedValues = [[NSMutableArray alloc]init];
1544
- NSInteger i, count = [revisedColumns count];
1545
-
1546
- for (i = 0; i < count; i++) {
1547
- NSString *column = [revisedColumns objectAtIndex:i];
1548
- NSString *value = [values objectAtIndex:i];
1549
- NSString *escapedValue = nil;
1550
- if (NO == [self NSFP_isColumnROWIDAlias:column forTable:table])
1551
- escapedValue = [[NSString alloc]initWithFormat:@"'%@'", value];
1552
- else
1553
- escapedValue = [[NSString alloc]initWithFormat:@"%@", value];
1554
- [escapedValues addObject:escapedValue];
1555
- }
1556
-
1557
- NSMutableString* theSQLStatement = [[NSMutableString alloc]initWithString:[NSString stringWithFormat:@"INSERT INTO %@(", table]];
1558
-
1559
- [self NSFP_sqlString:theSQLStatement appendingTags:revisedColumns];
1560
- [theSQLStatement appendString:@") VALUES("];
1561
- [self NSFP_sqlString:theSQLStatement appendingTags:escapedValues];
1562
- [theSQLStatement appendString:@");"];
1563
- BOOL insertWasOK = (nil == [[self executeSQL:theSQLStatement]error]);
1564
-
1565
- return insertWasOK;
1566
- }
1567
-
1568
- - (void)NSFP_sqlString:(NSMutableString*)theSQLStatement appendingTags:(NSArray *)tags quoteTags:(BOOL)flag
1569
- {
1570
- if (nil == theSQLStatement)
1571
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1572
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: theSQLStatement is nil.", [self class], _cmd]
1573
- userInfo:nil]raise];
1574
-
1575
- if (nil == tags)
1576
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1577
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: tags is nil.", [self class], _cmd]
1578
- userInfo:nil]raise];
1579
-
1580
- NSInteger i, count = [tags count];
1581
-
1582
- if (flag) {
1583
- for (i = 0; i < count; i++) {
1584
- NSString *tagName = [tags objectAtIndex:i];
1585
- NSString *escapedValue = [[NSString alloc]initWithFormat:@"'%@'", tagName];
1586
-
1587
- [theSQLStatement appendString:escapedValue];
1588
-
1589
- if (i != count - 1)
1590
- [theSQLStatement appendString:@","];
1591
- }
1592
- } else {
1593
- [theSQLStatement appendString:[tags componentsJoinedByString:@","]];
1594
- }
1595
- }
1596
-
1597
- - (void)NSFP_sqlString:(NSMutableString*)theSQLStatement appendingTags:(NSArray *)tags
1598
- {
1599
- if (nil == theSQLStatement)
1600
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1601
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: theSQLStatement is nil.", [self class], _cmd]
1602
- userInfo:nil]raise];
1603
-
1604
- if (nil == tags)
1605
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1606
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: tags is nil.", [self class], _cmd]
1607
- userInfo:nil]raise];
1608
-
1609
- [self NSFP_sqlString:theSQLStatement appendingTags:tags quoteTags:NO];
1610
- }
1611
-
1612
- - (BOOL)NSFP_sqlString:(NSMutableString*)theSQLStatement forTable:(NSString *)table withColumns:(NSArray *)columns datatypes:(NSArray *)datatypes
1613
- {
1614
- if (nil == theSQLStatement)
1615
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1616
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: theSQLStatement is nil.", [self class], _cmd]
1617
- userInfo:nil]raise];
1618
-
1619
- if (nil == table)
1620
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1621
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: table is nil.", [self class], _cmd]
1622
- userInfo:nil]raise];
1623
-
1624
- if (nil == columns)
1625
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1626
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: columns is nil.", [self class], _cmd]
1627
- userInfo:nil]raise];
1628
-
1629
- if (nil == datatypes)
1630
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1631
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: datatypes is nil.", [self class], _cmd]
1632
- userInfo:nil]raise];
1633
-
1634
- BOOL constructionSucceeded = YES;
1635
- NSInteger i, count = [columns count];
1636
-
1637
- for (i = 0; i < count; i++) {
1638
- NSString *column = [columns objectAtIndex:i];
1639
- NSString *datatype = [datatypes objectAtIndex:i];
1640
-
1641
- if (nil != datatype) {
1642
- // Some datatypes may be empty strings.
1643
- // See NSFNanoEngine's header file for more info on datatypesForTable:.
1644
- NSString *columnAndDatatype = nil;
1645
-
1646
- if ([datatype isEqualToString:@""])
1647
- columnAndDatatype = [[NSString alloc]initWithFormat:@"%@", column];
1648
- else
1649
- columnAndDatatype = [[NSString alloc]initWithFormat:@"%@ %@", column, datatype];
1650
-
1651
- [theSQLStatement appendString:columnAndDatatype];
1652
-
1653
- if (i != count - 1)
1654
- [theSQLStatement appendString:@","];
1655
- } else {
1656
- constructionSucceeded = NO;
1657
- }
1658
- }
1659
-
1660
- return constructionSucceeded;
1661
- }
1662
-
1663
- - (NSInteger)NSFP_ROWIDPresenceLocation:(NSArray *)tableColumns datatypes:(NSArray *)datatypes
1664
- {
1665
- if (nil == tableColumns)
1666
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1667
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: tableColumns is nil.", [self class], _cmd]
1668
- userInfo:nil]raise];
1669
-
1670
- if (nil == datatypes)
1671
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1672
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: datatypes is nil.", [self class], _cmd]
1673
- userInfo:nil]raise];
1674
-
1675
- // First check if we have a datatype of type NSFNanoTypeRowUID
1676
- NSInteger ROWIDIndex = NSNotFound;
1677
-
1678
- if (nil != datatypes) {
1679
- NSInteger i, count = [datatypes count];
1680
- NSString *rowUIDDatatype = NSFStringFromNanoDataType(NSFNanoTypeRowUID);
1681
-
1682
- for (i = 0; i < count; i++) {
1683
- if ([[[datatypes objectAtIndex:i] uppercaseString]isEqualToString:rowUIDDatatype]) {
1684
- ROWIDIndex = i;
1685
- break;
1686
- }
1687
- }
1688
- }
1689
-
1690
- if (NSNotFound == ROWIDIndex) {
1691
- // Make sure we have specified ROWID in the group of columns
1692
- NSArray *reservedKeywords = [NSFNanoEngine NSFP_sharedROWIDKeywords];
1693
-
1694
- for (NSString *tableColumn in tableColumns) {
1695
- NSInteger index = [reservedKeywords indexOfObject:tableColumn];
1696
-
1697
- if (NSNotFound != index) {
1698
- ROWIDIndex = index;
1699
- break;
1700
- }
1701
- }
1702
- }
1703
-
1704
- return ROWIDIndex;
1705
- }
1706
-
1707
- - (BOOL)NSFP_isColumnROWIDAlias:(NSString *)column forTable:(NSString *)table
1708
- {
1709
- if (nil == column)
1710
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1711
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: column is nil.", [self class], _cmd]
1712
- userInfo:nil]raise];
1713
-
1714
- if (nil == table)
1715
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1716
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: table is nil.", [self class], _cmd]
1717
- userInfo:nil]raise];
1718
-
1719
- NSString *rowUIDDatatype = NSFStringFromNanoDataType(NSFNanoTypeRowUID);
1720
-
1721
- if (nil != schema)
1722
- return [[[schema objectForKey:table]objectForKey:column]isEqualToString:rowUIDDatatype];
1723
-
1724
- NSString *theSQLStatement = [NSString stringWithFormat:@"SELECT %@ FROM %@ WHERE %@ = '%@' AND %@ = '%@';", NSFP_DatatypeIdentifier, NSFP_SchemaTable, NSFP_TableIdentifier, table, NSFP_ColumnIdentifier, column];
1725
- NSFNanoResult* result = [self executeSQL:theSQLStatement];
1726
-
1727
- NSString *columnFound = [[result valuesForColumn:NSFP_FullDatatypeIdentifier]lastObject];
1728
- BOOL isROWIDAlias = [columnFound isEqualToString:rowUIDDatatype];
1729
-
1730
- return isROWIDAlias;
1731
- }
1732
-
1733
- - (NSString *)NSFP_prefixWithDotDelimiter:(NSString *)tableAndColumn
1734
- {
1735
- if (nil == tableAndColumn)
1736
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1737
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: tableAndColumn is nil.", [self class], _cmd]
1738
- userInfo:nil]raise];
1739
-
1740
- NSRange range = [tableAndColumn rangeOfString:@"." options:NSBackwardsSearch];
1741
- if (NSNotFound == range.location)
1742
- return tableAndColumn;
1743
-
1744
- return [tableAndColumn substringToIndex:range.location];
1745
- }
1746
-
1747
- - (NSString *)NSFP_suffixWithDotDelimiter:(NSString *)tableAndColumn
1748
- {
1749
- if (nil == tableAndColumn)
1750
- [[NSException exceptionWithName:NSFUnexpectedParameterException
1751
- reason:[NSString stringWithFormat:@"*** -[%@ %s]: tableAndColumn is nil.", [self class], _cmd]
1752
- userInfo:nil]raise];
1753
-
1754
- NSRange range = [tableAndColumn rangeOfString:@"." options:NSBackwardsSearch];
1755
- if (NSNotFound == range.location)
1756
- return tableAndColumn;
1757
-
1758
- range.location++;
1759
- range.length = [tableAndColumn length] - range.location;
1760
-
1761
- return [tableAndColumn substringWithRange:range];
1762
- }
1763
-
1764
- - (void)NSFP_installCommitCallback
1765
- {
1766
- sqlite3_commit_hook( self.sqlite, NSFP_commitCallback, (__bridge void *)(self));
1767
- }
1768
-
1769
- - (void)NSFP_uninstallCommitCallback
1770
- {
1771
- sqlite3_commit_hook( self.sqlite, NULL, NULL);
1772
- }
1773
-
1774
- int NSFP_commitCallback(void* nsfdb)
1775
- {
1776
- return SQLITE_OK;
1777
- }
1778
-
1779
- /** \endcond */
1780
-
1781
- @end