diff --git a/src/android/org/pgsqlite/SQLitePlugin.java b/src/android/org/pgsqlite/SQLitePlugin.java index 41a635115..66a328160 100755 --- a/src/android/org/pgsqlite/SQLitePlugin.java +++ b/src/android/org/pgsqlite/SQLitePlugin.java @@ -104,7 +104,7 @@ private boolean executeAndPossiblyThrow(Action action, JSONArray args, CallbackC o = args.getJSONObject(0); dbname = o.getString("name"); // open database and start reading its queue - this.startDatabase(dbname, o.has("createFromResource"), cbc); + this.startDatabase(dbname, o, cbc); break; case close: @@ -158,14 +158,14 @@ private boolean executeAndPossiblyThrow(Action action, JSONArray args, CallbackC DBQuery q = new DBQuery(queries, queryIDs, jsonparams, cbc); DBRunner r = dbrmap.get(dbname); if (r != null) { - try { - r.q.put(q); - } catch(Exception e) { - Log.e(SQLitePlugin.class.getSimpleName(), "couldn't add to queue", e); - cbc.error("couldn't add to queue"); - } + try { + r.q.put(q); + } catch(Exception e) { + Log.e(SQLitePlugin.class.getSimpleName(), "couldn't add to queue", e); + cbc.error("couldn't add to queue"); + } } else { - cbc.error("database not open"); + cbc.error("database not open"); } break; } @@ -198,19 +198,19 @@ public void onDestroy() { // LOCAL METHODS // -------------------------------------------------------------------------- - private void startDatabase(String dbname, boolean createFromAssets, CallbackContext cbc) { + private void startDatabase(String dbname, JSONObject options, CallbackContext cbc) { // TODO: is it an issue that we can orphan an existing thread? What should we do here? // If we re-use the existing DBRunner it might be in the process of closing... DBRunner r = dbrmap.get(dbname); // Brody TODO: It may be better to terminate the existing db thread here & start a new one, instead. if (r != null) { - // don't orphan the existing thread; just re-open the existing database. - // In the worst case it might be in the process of closing, but even that's less serious - // than orphaning the old DBRunner. + // don't orphan the existing thread; just re-open the existing database. + // In the worst case it might be in the process of closing, but even that's less serious + // than orphaning the old DBRunner. cbc.success(); } else { - r = new DBRunner(dbname, createFromAssets, cbc); + r = new DBRunner(dbname, options, cbc); dbrmap.put(dbname, r); this.cordova.getThreadPool().execute(r); } @@ -224,7 +224,7 @@ private SQLiteDatabase openDatabase(String dbname, boolean createFromAssets, Cal try { if (this.getDatabase(dbname) != null) { // this should not happen - should be blocked at the execute("open") level - cbc.error("database already open"); + if (cbc != null) cbc.error("database already open"); throw new Exception("database already open"); } @@ -240,11 +240,13 @@ private SQLiteDatabase openDatabase(String dbname, boolean createFromAssets, Cal SQLiteDatabase mydb = SQLiteDatabase.openOrCreateDatabase(dbfile, null); - cbc.success(); + //if (cbc != null) // needed for Android locking/closing workaround + cbc.success(); return mydb; } catch (SQLiteException e) { - cbc.error("can't open database " + e); + //if (cbc != null) // needed for Android locking/closing workaround + cbc.error("can't open database " + e); throw e; } } @@ -308,15 +310,15 @@ private void closeDatabase(String dbName, CallbackContext cbc) { try { r.q.put(new DBQuery(false, cbc)); } catch(Exception e) { - if (cbc != null) { - cbc.error("couldn't close database" + e); - } + if (cbc != null) { + cbc.error("couldn't close database" + e); + } Log.e(SQLitePlugin.class.getSimpleName(), "couldn't close database", e); } } else { - if (cbc != null) { - cbc.success(); - } + if (cbc != null) { + cbc.success(); + } } } @@ -339,9 +341,9 @@ private void deleteDatabase(String dbname, CallbackContext cbc) { try { r.q.put(new DBQuery(true, cbc)); } catch(Exception e) { - if (cbc != null) { - cbc.error("couldn't close database" + e); - } + if (cbc != null) { + cbc.error("couldn't close database" + e); + } Log.e(SQLitePlugin.class.getSimpleName(), "couldn't close database", e); } } else { @@ -367,14 +369,14 @@ private boolean deleteDatabaseNow(String dbname) { if (android.os.Build.VERSION.SDK_INT >= 11) { // Use try & catch just in case android.os.Build.VERSION.SDK_INT >= 16 was lying: try { - return SQLiteDatabase.deleteDatabase(dbfile); + return SQLiteDatabase.deleteDatabase(dbfile); } catch (Exception e) { Log.e(SQLitePlugin.class.getSimpleName(), "couldn't delete because old SDK_INT", e); return deleteDatabasePreHoneycomb(dbfile); } } else { // use old API - return deleteDatabasePreHoneycomb(dbfile); + return deleteDatabasePreHoneycomb(dbfile); } } @@ -413,9 +415,9 @@ private void executeSqlBatch(String dbname, String[] queryarr, JSONArray[] jsonp SQLiteDatabase mydb = getDatabase(dbname); if (mydb == null) { - // not allowed - can only happen if someone has closed (and possibly deleted) a database and then re-used the database - cbc.error("database has been closed"); - return; + // not allowed - can only happen if someone has closed (and possibly deleted) a database and then re-used the database + cbc.error("database has been closed"); + return; } @@ -818,15 +820,17 @@ private void bindPreHoneycomb(JSONObject row, String key, Cursor cursor, int i) private class DBRunner implements Runnable { final String dbname; - final boolean createFromAssets; + private boolean createFromAssets; + //private boolean androidLockWorkaround; final BlockingQueue q; final CallbackContext openCbc; SQLiteDatabase mydb; - DBRunner(final String dbname, boolean createFromAssets, CallbackContext cbc) { + DBRunner(final String dbname, JSONObject options, CallbackContext cbc) { this.dbname = dbname; - this.createFromAssets = createFromAssets; + this.createFromAssets = options.has("createFromResource"); + //this.androidLockWorkaround = options.has("androidLockWorkaround"); this.q = new LinkedBlockingQueue(); this.openCbc = cbc; } @@ -848,6 +852,14 @@ public void run() { while (!dbq.stop) { executeSqlBatch(dbname, dbq.queries, dbq.jsonparams, dbq.queryIDs, dbq.cbc); + // XXX workaround for Android locking/closing issue: + //if (androidLockWorkaround && dbq.queries.length == 1 && dbq.queries[0] == "COMMIT") { + // Log.v(SQLitePlugin.class.getSimpleName(), "close and reopen db"); + // closeDatabaseNow(dbname); + // this.mydb = openDatabase(dbname, false, null); + // Log.v(SQLitePlugin.class.getSimpleName(), "close and reopen db finished"); + //} + dbq = q.take(); } } catch (Exception e) { @@ -861,24 +873,24 @@ public void run() { dbrmap.remove(dbname); // (should) remove ourself if (!dbq.delete) { - dbq.cbc.success(); + dbq.cbc.success(); } else { - try { - boolean deleteResult = deleteDatabaseNow(dbname); - if (deleteResult) { - dbq.cbc.success(); - } else { - dbq.cbc.error("couldn't delete database"); - } - } catch (Exception e) { - Log.e(SQLitePlugin.class.getSimpleName(), "couldn't delete database", e); - dbq.cbc.error("couldn't delete database: " + e); - } + try { + boolean deleteResult = deleteDatabaseNow(dbname); + if (deleteResult) { + dbq.cbc.success(); + } else { + dbq.cbc.error("couldn't delete database"); + } + } catch (Exception e) { + Log.e(SQLitePlugin.class.getSimpleName(), "couldn't delete database", e); + dbq.cbc.error("couldn't delete database: " + e); + } } } catch (Exception e) { Log.e(SQLitePlugin.class.getSimpleName(), "couldn't close database", e); if (dbq.cbc != null) { - dbq.cbc.error("couldn't close database: " + e); + dbq.cbc.error("couldn't close database: " + e); } } }