-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTiAdvanceddatabaseProxy.m
285 lines (239 loc) · 7.51 KB
/
TiAdvanceddatabaseProxy.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
/**
* Appcelerator Titanium Mobile
* Copyright (c) 2009-2013 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*
* WARNING: This is generated code. Modify at your own risk and without support.
*/
#import "TiAdvanceddatabaseProxy.h"
#import "TiAdvanceddatabaseResultSetProxy.h"
#import "TiUtils.h"
#import "TiFilesystemFileProxy.h"
@implementation TiAdvanceddatabaseProxy
#pragma mark Internal
-(void)dealloc
{
[self _destroy];
RELEASE_TO_NIL(name);
[super dealloc];
}
-(void)shutdown:(id)sender
{
if (database!=nil)
{
[self performSelector:@selector(close:) withObject:nil];
}
}
-(void)_destroy
{
WARN_IF_BACKGROUND_THREAD_OBJ; //NSNotificationCenter is not threadsafe!
[[NSNotificationCenter defaultCenter] removeObserver:self name:kTiShutdownNotification object:nil];
[self shutdown:nil];
[super _destroy];
}
-(void)_configure
{
WARN_IF_BACKGROUND_THREAD_OBJ; //NSNotificationCenter is not threadsafe!
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(shutdown:) name:kTiShutdownNotification object:nil];
[super _configure];
}
-(NSString*)dbDir
{
// See this apple tech note for why this changed: https://developer.apple.com/library/ios/#qa/qa1719/_index.html
// Apparently following these guidelines is now required for app submission
NSString *rootDir = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *dbPath = [rootDir stringByAppendingPathComponent:@"Private Documents"];
NSFileManager *fm = [NSFileManager defaultManager];
BOOL isDirectory;
BOOL exists = [fm fileExistsAtPath:dbPath isDirectory:&isDirectory];
// Because of sandboxing, this should never happen, but we still need to handle it.
if (exists && !isDirectory) {
NSLog(@"[WARN] Recreating file %@... should be a directory and isn't.", dbPath);
[fm removeItemAtPath:dbPath error:nil];
exists = NO;
}
// create folder, and migrate the old one if necessary
if (!exists)
{
[fm createDirectoryAtPath:dbPath withIntermediateDirectories:YES attributes:nil error:nil];
}
// Migrate any old data if available
NSString* oldRoot = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* oldPath = [oldRoot stringByAppendingPathComponent:@"database"];
BOOL oldCopyExists = [fm fileExistsAtPath:oldPath isDirectory:&isDirectory];
if (oldCopyExists && isDirectory) {
NSDirectoryEnumerator* contents = [fm enumeratorAtPath:oldPath];
//This gives relative paths. So create full path before moving
for (NSString* oldFile in contents) {
[fm moveItemAtPath:[oldPath stringByAppendingPathComponent:oldFile] toPath:[dbPath stringByAppendingPathComponent:oldFile] error:nil];
}
// Remove the old copy after migrating everything
[fm removeItemAtPath:oldPath error:nil];
}
return dbPath;
}
-(NSString*)dbPath:(NSString*)name_
{
NSString *dbDir = [self dbDir];
return [[dbDir stringByAppendingPathComponent:name_] stringByAppendingPathExtension:@"sql"];
}
-(void)open:(NSString*)name_
{
name = [name_ retain];
NSString *path = [self dbPath:name];
database = [[PLSqliteDatabase alloc] initWithPath:path];
if (![database open])
{
[self throwException:@"couldn't open database" subreason:name_ location:CODELOCATION];
}
}
-(void)install:(NSString*)path name:(NSString*)name_
{
BOOL isDirectory;
NSFileManager *fm = [NSFileManager defaultManager];
NSURL *url = [TiUtils toURL:path proxy:self];
path = [url path];
#if TARGET_IPHONE_SIMULATOR
//TIMOB-6081. Resources are right now symbolic links when running in simulator) so the copy method
//of filemanager just creates a link to the original resource.
//Resolve the symbolic link if running in simulator
NSError *pathError = nil;
NSDictionary *attributes = [fm attributesOfItemAtPath:path error:&pathError];
if (pathError != nil)
{
[self throwException:@"Could not retrieve attributes" subreason:[pathError description] location:CODELOCATION];
}
NSString *fileType = [attributes valueForKey:NSFileType];
if ([fileType isEqual:NSFileTypeSymbolicLink])
{
pathError = nil;
path = [fm destinationOfSymbolicLinkAtPath:path error:&pathError];
if (pathError != nil)
{
[self throwException:@"Could not resolve symbolic link" subreason:[pathError description] location:CODELOCATION];
}
}
#endif
BOOL exists = [fm fileExistsAtPath:path isDirectory:&isDirectory];
if (!exists)
{
[self throwException:@"invalid database install path" subreason:path location:CODELOCATION];
}
// get the install path
NSString *installPath = [self dbPath:name_];
// see if we have already installed the DB
exists = [fm fileExistsAtPath:installPath isDirectory:&isDirectory];
if (!exists)
{
NSError *error = nil;
// install it by copying it
[fm copyItemAtPath:path toPath:installPath error:&error];
if (error!=nil)
{
[self throwException:@"couldn't install database" subreason:[error description] location:CODELOCATION];
}
}
[self open:name_];
}
-(void)removeStatement:(PLSqliteResultSet*)statement
{
[statement close];
if (statements!=nil)
{
[statements removeObject:statement];
}
}
-(id)execute:(id)args
{
ENSURE_TYPE(args, NSArray);
NSString *sql = [[args objectAtIndex:0] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSError *error = nil;
PLSqlitePreparedStatement * statement = (PLSqlitePreparedStatement *) [database prepareStatement:sql error:&error];
if (error!=nil)
{
[self throwException:@"invalid SQL statement" subreason:[error description] location:CODELOCATION];
}
if([args count] > 1) {
NSArray *params = [args objectAtIndex:1];
if(![params isKindOfClass:[NSArray class]]) {
params = [args subarrayWithRange:NSMakeRange(1, [args count]-1)];
}
[statement bindParameters:params];
}
PLSqliteResultSet *result = (PLSqliteResultSet*) [statement executeQuery];
if ([[result fieldNames] count]==0)
{
[result next]; // we need to do this to make sure lastInsertRowId and rowsAffected work
[result close];
return [NSNull null];
}
if (statements==nil)
{
statements = [[NSMutableArray alloc] initWithCapacity:5];
}
[statements addObject:result];
TiAdvanceddatabaseResultSetProxy *proxy = [[[TiAdvanceddatabaseResultSetProxy alloc] initWithResults:result database:self pageContext:[self pageContext]] autorelease];
return proxy;
}
-(void)close:(id)args
{
if (statements!=nil)
{
for (PLSqliteResultSet *result in statements)
{
[result close];
}
RELEASE_TO_NIL(statements);
}
if (database!=nil)
{
if ([database goodConnection])
{
@try
{
[database close];
}
@catch (NSException * e)
{
NSLog(@"[WARN] attempting to close database, returned error: %@",e);
}
}
RELEASE_TO_NIL(database);
}
}
-(void)remove:(id)args
{
NSString *dbPath = [self dbPath:name];
[[NSFileManager defaultManager] removeItemAtPath:dbPath error:nil];
}
-(NSNumber*)lastInsertRowId
{
if (database!=nil)
{
return NUMINT([database lastInsertRowId]);
}
return NUMINT(0);
}
-(NSNumber*)rowsAffected
{
if (database!=nil)
{
return NUMINT(sqlite3_changes([database sqliteDB]));
}
return NUMINT(0);
}
-(NSString*)name
{
return name;
}
-(TiFilesystemFileProxy*)file
{
return [[TiFilesystemFileProxy alloc] initWithFile:[self dbPath:name]];
}
#pragma mark Internal
-(PLSqliteDatabase*)database
{
return database;
}
@end