@@ -178,34 +178,33 @@ -(void)openNow: (CDVInvokedUrlCommand*)command
178178 // NOTE: create DB from resource [pre-populated] NOT supported with sqlcipher.
179179
180180 if (sqlite3_open (name, &db) != SQLITE_OK) {
181+ [self logSqlError: db message: @" Unable to open DB" ];
181182 pluginResult = [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR messageAsString: @" Unable to open DB" ];
182183 [self .commandDelegate sendPluginResult: pluginResult callbackId: command.callbackId];
183- return ;
184184 } else {
185- sqlite3_db_config (db, SQLITE_DBCONFIG_DEFENSIVE, 1 , NULL );
186-
187- #if 0
188- sqlite3_create_function(db, "REGEXP", 2, SQLITE_ANY, NULL, &sqlite_regexp, NULL, NULL);
189- #endif
190-
191- // SQLCipher key:
192- NSString *dbkey = [options objectForKey: @" key" ];
193- const char *key = NULL ;
194- if (dbkey != NULL && dbkey.length != 0 ) key = [dbkey UTF8String ];
195- NSLog ((key != NULL ) ? @" Open DB with encryption" : @" Open DB with NO encryption" );
196- if (key != NULL ) sqlite3_key (db, key, strlen (key));
197-
185+ [self prepareDatabase: db options: options];
198186 // XXX Brody TODO check this in Javascript instead.
199187 // Attempt to read the SQLite master table [to support SQLCipher version]:
200- if (sqlite3_exec (db, (const char *)" SELECT count(*) FROM sqlite_master;" , NULL , NULL , NULL ) == SQLITE_OK) {
201- NSLog (@" DB open, check sqlite master table OK" );
202- dbPointer = [NSValue valueWithPointer: db];
203- [openDBs setObject: dbPointer forKey: dbfilename];
188+
189+ Boolean databaseCheck = NO ;
190+ if ([self checkDatabaseConnection: db dbfilename: dbfilename]) {
191+ databaseCheck = YES ;
192+ } else {
193+ NSString *sCipherMigrate = [options objectForKey: @" cipherMigrate" ];
194+ Boolean cipherMigrate = sCipherMigrate ? [sCipherMigrate boolValue ] : NO ;
195+
196+ if (cipherMigrate) {
197+ db = [self executeCipherMigration: db name: name options: options];
198+ if (db != NULL ) {
199+ databaseCheck = [self checkDatabaseConnection: db dbfilename: dbfilename];
200+ }
201+ }
202+ }
203+
204+ if (databaseCheck) {
204205 pluginResult = [CDVPluginResult resultWithStatus: CDVCommandStatus_OK messageAsString: @" Database opened" ];
205206 } else {
206- NSLog (@" ERROR reading sqlite master table" );
207207 pluginResult = [CDVPluginResult resultWithStatus: CDVCommandStatus_ERROR messageAsString: @" Unable to open DB with key" ];
208- // XXX TODO: close the db handle & [perhaps] remove from openDBs!!
209208 }
210209 }
211210 }
@@ -216,6 +215,97 @@ -(void)openNow: (CDVInvokedUrlCommand*)command
216215 // DLog(@"open cb finished ok");
217216}
218217
218+ -(Boolean) prepareDatabase : (sqlite3*) db options : (NSMutableDictionary *) options
219+ {
220+ sqlite3_db_config (db, SQLITE_DBCONFIG_DEFENSIVE, 1 , NULL );
221+
222+ #if 0
223+ sqlite3_create_function(db, "REGEXP", 2, SQLITE_ANY, NULL, &sqlite_regexp, NULL, NULL);
224+ #endif
225+
226+ // SQLCipher key:
227+ NSString *dbkey = [options objectForKey: @" key" ];
228+ const char *key = NULL ;
229+ if (dbkey != NULL && dbkey.length != 0 ) key = [dbkey UTF8String ];
230+ NSLog ((key != NULL ) ? @" Open DB with encryption" : @" Open DB with NO encryption" );
231+ if (key != NULL ) {
232+ if (sqlite3_key (db, key, strlen (key)) != SQLITE_OK) {
233+ [self logSqlError: db message: @" Error setting key: " ];
234+ return NO ;
235+ }
236+ }
237+
238+ return YES ;
239+ }
240+
241+ -(sqlite3*) reopenDatabase : (sqlite3*) db name : (const char *) name options : (NSMutableDictionary *) options
242+ {
243+ sqlite3_close (db);
244+
245+ sqlite3* newDb;
246+
247+ if (sqlite3_open (name, &newDb) != SQLITE_OK) {
248+ [self logSqlError: db message: @" Unable to open DB" ];
249+ return NULL ;
250+ } else {
251+ [self prepareDatabase: newDb options: options];
252+ return newDb;
253+ }
254+ }
255+
256+ -(sqlite3*) executeCipherMigration : (sqlite3*) db name : (const char *) name options : (NSMutableDictionary *) options
257+ {
258+ db = [self reopenDatabase: db name: name options: options];
259+ if (db == NULL ) {
260+ NSLog (@" %@ " , @" Unable to reopen database for cipher migration" );
261+ return NULL ;
262+ } else {
263+ sqlite3_stmt *statement;
264+
265+ sqlite3_prepare_v2 (db, " PRAGMA CIPHER_MIGRATE" , -1 , &statement, NULL );
266+
267+ while (sqlite3_step (statement) == SQLITE_ROW) {
268+ NSString *result = [[NSString alloc ] initWithUTF8String:
269+ (const char *) sqlite3_column_text (statement, 0 )];
270+ NSLog (@" %@%@ " , @" Pragma migrate: " , result);
271+ }
272+
273+ if (sqlite3_finalize (statement) != SQLITE_OK) {
274+ [self logSqlError: db message: @" Unable to finalize cipher migrate statement: " ];
275+ return NULL ;
276+ }
277+
278+ db = [self reopenDatabase: db name: name options: options];
279+ if (db == NULL ) {
280+ NSLog (@" %@ " , @" Unable to reopen database after cipher migration" );
281+ return NULL ;
282+ } else {
283+ return db;
284+ }
285+ }
286+ }
287+
288+ -(void ) logSqlError : (sqlite3*)db message : (NSString *) message
289+ {
290+ const char *errmsg = sqlite3_errmsg (db);
291+ NSLog (@" %@%@ " , message, [NSString stringWithUTF8String: errmsg]);
292+ }
293+
294+ -(Boolean) checkDatabaseConnection : (sqlite3*)db dbfilename : (NSString *) dbfilename
295+ {
296+ int checkResult = sqlite3_exec (db, (const char *)" SELECT count(*) FROM sqlite_master;" , NULL , NULL , NULL );
297+
298+ if (checkResult == SQLITE_OK) {
299+ NSLog (@" DB open, check sqlite master table OK" );
300+ NSValue *dbPointer = [NSValue valueWithPointer: db];
301+ [openDBs setObject: dbPointer forKey: dbfilename];
302+ return YES ;
303+ } else {
304+ [self logSqlError: db message: @" Error checking connection: " ];
305+ return NO ;
306+ }
307+ }
308+
219309-(void ) close : (CDVInvokedUrlCommand*)command
220310{
221311 [self .commandDelegate runInBackground: ^{
0 commit comments